From ad6ee271cfeebc75e859d677b3b471d8afa742ac Mon Sep 17 00:00:00 2001 From: youngLiuHY Date: Mon, 2 Feb 2026 18:06:14 +0800 Subject: [PATCH 01/10] fix: check workload update ready && need TerminatingReplicas is 0 --- pkg/workload/info.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/workload/info.go b/pkg/workload/info.go index 7598bae..3cc29db 100644 --- a/pkg/workload/info.go +++ b/pkg/workload/info.go @@ -110,7 +110,7 @@ func (o *Info) CheckUpdatedReady(replicas int32, strictCheck bool) (bool, string if o.Status.UpdatedAvailableReplicas < replicas { return false, "workload updated available replicas is not satisfied" } - if strictCheck && o.Status.ObservedReplicas > o.Status.DesiredReplicas { + if strictCheck && (o.Status.ObservedReplicas > o.Status.DesiredReplicas || o.Status.TerminatingReplicas != 0) { return false, "workload observed replicas is more than desiredReplicas" } return true, "" From f39d6225a961be6e4c853ce43409c45eb180609a Mon Sep 17 00:00:00 2001 From: youngLiuHY Date: Tue, 17 Mar 2026 17:42:43 +0800 Subject: [PATCH 02/10] feat: rollout support inline batch strategy --- .claude/rules/01-coding-conventions.md | 30 + .claude/rules/02-testing.md | 68 + .claude/rules/03-code-review.md | 18 + CLAUDE.md | 210 + apis/rollout/v1alpha1/validation/rollout.go | 32 +- .../v1alpha1/validation/rollout_test.go | 305 + .../rollout.kusionstack.io_rolloutruns.yaml | 9475 ++++++++--------- .../rollout.kusionstack.io_rollouts.yaml | 4928 ++++++++- go.mod | 2 +- go.sum | 4 +- pkg/controllers/rollout/CLAUDE.md | 201 + pkg/controllers/rollout/inline_strategy.go | 184 + .../rollout/inline_strategy_test.go | 619 ++ pkg/controllers/rollout/rollout_controller.go | 45 +- .../rollout/rollout_controller_test.go | 439 + pkg/controllers/rollout/suite_test.go | 78 + pkg/controllers/rollout/utils.go | 10 +- pkg/controllers/rollout/utils_test.go | 276 + pkg/controllers/rolloutrun/CLAUDE.md | 338 + pkg/features/ontimestrategy/ontimestrategy.go | 23 + 20 files changed, 12269 insertions(+), 5016 deletions(-) create mode 100644 .claude/rules/01-coding-conventions.md create mode 100644 .claude/rules/02-testing.md create mode 100644 .claude/rules/03-code-review.md create mode 100644 CLAUDE.md create mode 100644 pkg/controllers/rollout/CLAUDE.md create mode 100644 pkg/controllers/rollout/inline_strategy.go create mode 100644 pkg/controllers/rollout/inline_strategy_test.go create mode 100644 pkg/controllers/rollout/rollout_controller_test.go create mode 100644 pkg/controllers/rollout/suite_test.go create mode 100644 pkg/controllers/rolloutrun/CLAUDE.md diff --git a/.claude/rules/01-coding-conventions.md b/.claude/rules/01-coding-conventions.md new file mode 100644 index 0000000..82b37b7 --- /dev/null +++ b/.claude/rules/01-coding-conventions.md @@ -0,0 +1,30 @@ +# 编码规范 + +## 命名约定 + +| 类型 | 格式 | 示例 | +|------|------|------| +| 文件 | 蛇形命名 | `agentic_version_create.go` | +| 结构体 | PascalCase | `AgenticVersionCreateRequest` | +| 方法 | CamelCase,动词开头 | `CreateVersion` | +| 常量 | 驼峰或全大写下划线 | `DefaultEnvPre` | + +## 包导入顺序 + +```go +import ( + // 标准库 + "context" + "fmt" + "time" + + // 第三方库 + "github.com/gin-gonic/gin" + "go.uber.org/zap" + "go.mongodb.org/mongo-driver/bson" + + // 项目内部包 + "code.alipay.com/paas-core/kox/pkg/model" + "code.alipay.com/paas-core/kox/pkg/logging" +) +``` diff --git a/.claude/rules/02-testing.md b/.claude/rules/02-testing.md new file mode 100644 index 0000000..4f88cb6 --- /dev/null +++ b/.claude/rules/02-testing.md @@ -0,0 +1,68 @@ +# 测试规范 +- 单元测试覆盖 Reconcile 各分支 +- 使用 envtest 模拟 API Server +- 集成测试验证端到端流程 +- 测试执行命令 `go test -v`,仅执行改动的测试文件 + +## 单元测试模板 + +```go +func TestFunctionName(t *testing.T) { + type args struct { + param string + } + + tests := []struct { + name string + args args + want string + wantErr bool + }{ + { + name: "success case", + args: args{param: "value"}, + want: "expected", + wantErr: false, + }, + { + name: "error case", + args: args{param: ""}, + wantErr: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := Function(tt.args.param) + if (err != nil) != tt.wantErr { + t.Errorf("Function() error = %v, wantErr %v", err, tt.wantErr) + return + } + if got != tt.want { + t.Errorf("Function() = %v, want %v", got, tt.want) + } + }) + } +} +``` + +## 集成测试模板 + +### 使用 "github.com/onsi/ginkgo" 和 "github.com/onsi/gomega" 框架 + +```go +It("namespace created", func() { + ns := &corev1.Namespace{ + ObjectMeta: metav1.ObjectMeta{ + Name: namespaceUT, + }, + } + + Expect(c.Create(context.TODO(), ns)).Should(Succeed()) +}) +``` + +## 测试文件位置 + +- 单元测试文件与源文件同目录 +- 命名:`xxx_test.go` diff --git a/.claude/rules/03-code-review.md b/.claude/rules/03-code-review.md new file mode 100644 index 0000000..da41d03 --- /dev/null +++ b/.claude/rules/03-code-review.md @@ -0,0 +1,18 @@ +# 代码审查清单 + +## 检查项 + +- [ ] 错误处理是否完善? +- [ ] 日志是否包含足够的上下文? +- [ ] 参数校验是否完整? +- [ ] 测试是否覆盖了主要路径? +- [ ] 是否有未使用的导入或变量? + +## 不要做的事 + +- **不要** 忽略 error 检查(使用 `_` 丢弃) + +## 必须做的事 + +- **必须** 提交前执行 `go build -o bin/manager kusionstack.io/rollout/cmd/rollout` +- **必须** 提交前执行 `make lint` diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..84cf8dc --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,210 @@ +# CLAUDE.md - Rollout 开发上下文 + +## 快速参考 + +| 主题 | 规则文件 | +|------|------------------------------------------| +| 编码规范 | `.claude/rules/01-coding-conventions.md` | +| 测试规范 | `.claude/rules/02-testing.md` | +| 代码审查 | `.claude/rules/03-code-review.md` | + +--- + +## Claude 开发工作流 (SDD) + +使用 Specification-Driven Development (SDD) 方式与 Claude 协作开发,确保开发过程有序可控。 + +**⚠️ 绝对禁止:在任何阶段未完成时进入下一阶段。Claude 必须等待用户明确确认后才能继续。** + +**推荐技能:** + +```bash +/superpowers:brainstorming # 需求讨论和设计 +/superpowers:writing-plans # 编写设计文档 +/superpowers:using-git-worktrees # 创建隔离工作区 +/superpowers:test-driven-development # TDD开发 +/superpowers:requesting-code-review # 代码审查 +/skill create-dima-issue # 创建 DIMA 工单 +/skill gitpr # 创建 PR +``` + +--- + +### Phase 1: 需求澄清 (Requirement Clarification) + +**触发条件**:用户提出任何需求、想法或问题时 + +**Claude 必须执行:** +1. 使用 `/superpowers:brainstorming` skill 启动头脑风暴 +2. 通过提问充分理解需求,一次只问一个问题 +3. 明确功能目标、验收标准、影响范围 + +**完成标准**: +- [ ] 需求已充分澄清 +- [ ] 验收标准已定义 +- [ ] 用户确认需求理解正确 + +**阶段输出**:需求澄清总结(文字描述即可) + +**用户确认话术**:"需求澄清完毕,请确认我的理解是否正确:[总结]。确认无误后,我将进入 Dima Issue 创建阶段。" + +**⚠️ 禁止**:未完成需求澄清前进入 Dima 创建阶段 + +--- + +### Phase 2: Dima Issue 关联 (Issue Tracking) + +**触发条件**:需求澄清完成且用户确认后 + +**Claude 必须执行:** +1. 询问用户是否已有 Dima Issue +2. 如无,调用 `/skill create-dima-issue` 创建 +3. 记录 Dima ID,后续所有工作必须关联此 ID + +**完成标准**: +- [ ] Dima Issue 已存在或已创建 +- [ ] Dima ID 已记录 + +**阶段输出**:Dima Issue 链接/ID + +**用户确认话术**:"Dima Issue 已关联:[DIMA-XXXX]。确认后,我将进入方案设计阶段。" + +**⚠️ 禁止**:无 Dima Issue 关联时进入设计阶段 + +--- + +### Phase 3: 方案设计 (Design) + +**触发条件**:Dima Issue 关联完成后 + +**Claude 必须执行:** +1. 输出设计文档到 `docs/plans/YYYY-MM-DD-.md`,包含: + - 背景和目标 + - 技术方案(含接口设计、数据模型变更) + - 影响分析 + - 风险和对策 +2. 使用 `/superpowers:writing-plans` skill 辅助生成规范的计划文档 + +**完成标准**: +- [ ] 设计文档已创建并写入文件 +- [ ] 技术方案已详细描述 +- [ ] 用户已审阅设计文档 + +**阶段输出**:`docs/plans/YYYY-MM-DD-.md` + +**用户确认话术**:"设计方案已输出到 [文件路径],请审阅。确认无误后,我将进入开发阶段。" + +**⚠️ 禁止**:设计文档未经用户确认前编写任何业务代码 + +--- + +### Phase 4: 开发实现 (Implementation) + +**触发条件**:设计方案经用户确认后 + +**4.1 环境准备** +- 询问用户是否需要创建隔离工作区以及独立分支 +- 若需要,使用 `/superpowers:using-git-worktrees` 创建隔离工作区 +- 切换到独立分支 + +**4.2 TDD 开发流程** + +**Step 1: Red - 编写失败的测试** +- 先编写测试用例(覆盖正常路径、边界条件、错误处理) +- 运行测试确保失败(验证测试有效性) +- **检查点**:测试文件已创建,测试失败符合预期 + +**Step 2: Green - 最小化实现** +- 编写刚好让测试通过的最小代码 +- 运行测试确保通过 +- **检查点**:所有测试通过 + +**Step 3: Refactor - 重构优化** +- 优化代码质量 +- 确保测试仍然通过 +- 运行 `make lint` 确保规范 +- 运行 `go build -o bin/manager kusionstack.io/rollout/cmd/rollout` 确保编译通过 +- 运行 `go test` 确保测试通过 +- **检查点**:确保编译测试全部通过 + +**完成标准**: +- [ ] 单元测试已编写并通过 +- [ ] 实现代码已完成 +- [ ] 编译测试全部通过 + +**阶段输出**:实现代码 + 测试代码 + +--- + +### Phase 5: 代码审查与提交 (Review & Commit) + +**触发条件**:开发实现完成后 + +**Claude 必须执行:** +1. 使用 `/superpowers:requesting-code-review` 进行自我审查 +2. 使用 `/skill gitpr` 创建 PR +3. PR 描述中必须包含:`Relates to: DIMA-XXXX` + +**PR 格式要求:** +``` +[DIMA-XXXX] (): + +- 变更点 1 +- 变更点 2 + +Relates to: DIMA-XXXX +``` + +**完成标准**: +- [ ] 代码审查完成 +- [ ] PR 已创建并关联 Dima Issue + +**阶段输出**:PR 链接 + +--- + +### 阶段转换检查清单 + +**每个阶段转换前,Claude 必须:** + +1. **明确询问用户**:"[当前阶段] 已完成,是否进入 [下一阶段]?" +2. **等待用户明确回复** "是/确认/可以" 后才能继续 +3. **不允许假设用户同意** + +**阶段依赖关系:** +``` +需求澄清 → Dima关联 → 方案设计 → 开发实现 → 代码审查 + ↑ ↑ ↑ ↑ ↑ +必须等待 必须等待 必须等待 必须等待 必须等待 +用户确认 用户确认 用户确认 用户确认 用户确认 +``` + +--- + +### Rule: 严格禁止的行为 + +| 禁止行为 | 违反后果 | +|---------|---------| +| 跳过用户确认进入下一阶段 | 可能导致方向错误,需回滚重做 | +| Planning 完成前编写业务代码 | 违反 SDD 原则 | +| 无 Dima Issue 关联进行开发 | 无法追溯需求来源 | +| 一次提交超过 500 行代码(不含测试) | 难以 Review,容易引入 Bug | +| 修改与当前功能无关的代码 | 引入不可控变更 | +| 跳过测试直接提交 | 质量无法保证 | +| 假设用户同意而非明确确认 | 可能误解需求 | + +--- + +### 工作流程总结 + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ 强制用户确认点 │ +├─────────────────────────────────────────────────────────────────┤ +│ 1. 需求澄清 → [等待用户确认: 理解是否正确?] → Dima关联 │ +│ 2. Dima关联 → [等待用户确认: Issue是否创建?] → 方案设计 │ +│ 3. 方案设计 → [等待用户确认: 设计文档是否可接受?] → 开发实现 │ +│ 4. 开发实现 → [TDD循环: Red→Green→Refactor] → 代码审查 │ +│ 5. 代码审查 → [等待用户确认: 是否创建PR?] → 完成 │ +└─────────────────────────────────────────────────────────────────┘ +``` diff --git a/apis/rollout/v1alpha1/validation/rollout.go b/apis/rollout/v1alpha1/validation/rollout.go index 3d19422..8c3b232 100644 --- a/apis/rollout/v1alpha1/validation/rollout.go +++ b/apis/rollout/v1alpha1/validation/rollout.go @@ -42,8 +42,36 @@ func ValidateRolloutSpec(spec *rolloutv1alpha1.RolloutSpec, fldPath *field.Path, allErrs = append(allErrs, field.NotSupported(fldPath.Child("triggerPolicy"), spec.TriggerPolicy, []string{string(rolloutv1alpha1.AutoTriggerPolicy), string(rolloutv1alpha1.ManualTriggerPolicy)})) } - if len(spec.StrategyRef) == 0 { - allErrs = append(allErrs, field.Required(fldPath.Child("strategyRef"), "must specify a strategy")) + // Validate strategy mutual exclusion: StrategyRef vs inline strategies (CanaryStrategy and BatchStrategy) + hasStrategyRef := len(spec.StrategyRef) > 0 + hasCanary := spec.CanaryStrategy != nil + hasBatch := spec.BatchStrategy != nil + + // StrategyRef is mutually exclusive with inline strategies + if hasStrategyRef && hasBatch { + allErrs = append(allErrs, field.Invalid( + fldPath, + spec.StrategyRef, + "strategyRef is mutually exclusive with batchStrategy", + )) + } + + // Must specify at least one strategy + if !hasStrategyRef && !hasBatch { + allErrs = append(allErrs, field.Required( + fldPath.Child("strategyRef"), + "must specify either strategyRef, or batchStrategy", + )) + } + + // Validate CanaryStrategy if present + if hasCanary { + allErrs = append(allErrs, ValidateRolloutRunCanaryStrategy(spec.CanaryStrategy, fldPath.Child("canaryStrategy"))...) + } + + // Validate BatchStrategy if present + if hasBatch { + allErrs = append(allErrs, ValidateRolloutRunBatchStrategy(spec.BatchStrategy, fldPath.Child("batchStrategy"))...) } allErrs = append(allErrs, ValidateWorkloadRef(&spec.WorkloadRef, fldPath.Child("workloadRef"), isSupportedGVK)...) diff --git a/apis/rollout/v1alpha1/validation/rollout_test.go b/apis/rollout/v1alpha1/validation/rollout_test.go index 5e97f46..9cee580 100644 --- a/apis/rollout/v1alpha1/validation/rollout_test.go +++ b/apis/rollout/v1alpha1/validation/rollout_test.go @@ -21,6 +21,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/util/intstr" rolloutv1alpha1 "kusionstack.io/kube-api/rollout/v1alpha1" ) @@ -121,3 +122,307 @@ func TestValidateRollout(t *testing.T) { }) } } + +// Tests for inline batch strategy validation +func TestValidateRollout_InlineBatchStrategy(t *testing.T) { + tests := []struct { + name string + obj *rolloutv1alpha1.Rollout + isSupportedGVK SupportedGVKFunc + wantErr bool + errMsg string + }{ + { + name: "valid inline batch strategy", + obj: &rolloutv1alpha1.Rollout{ + ObjectMeta: validMetadata, + Spec: rolloutv1alpha1.RolloutSpec{ + TriggerPolicy: "Auto", + WorkloadRef: validWorkloadRef, + BatchStrategy: &rolloutv1alpha1.RolloutRunBatchStrategy{ + Batches: []rolloutv1alpha1.RolloutRunStep{ + { + Targets: []rolloutv1alpha1.RolloutRunStepTarget{ + { + CrossClusterObjectNameReference: rolloutv1alpha1.CrossClusterObjectNameReference{ + Cluster: "cluster-a", + Name: "test", + }, + Replicas: intstr.FromString("20%"), + }, + }, + }, + }, + }, + }, + }, + isSupportedGVK: supportAllGVK, + wantErr: false, + }, + { + name: "batch strategy with multiple batches", + obj: &rolloutv1alpha1.Rollout{ + ObjectMeta: validMetadata, + Spec: rolloutv1alpha1.RolloutSpec{ + TriggerPolicy: "Auto", + WorkloadRef: validWorkloadRef, + BatchStrategy: &rolloutv1alpha1.RolloutRunBatchStrategy{ + Batches: []rolloutv1alpha1.RolloutRunStep{ + { + Breakpoint: true, + Targets: []rolloutv1alpha1.RolloutRunStepTarget{ + { + CrossClusterObjectNameReference: rolloutv1alpha1.CrossClusterObjectNameReference{ + Cluster: "cluster-a", + Name: "test", + }, + Replicas: intstr.FromString("20%"), + }, + }, + }, + { + Targets: []rolloutv1alpha1.RolloutRunStepTarget{ + { + CrossClusterObjectNameReference: rolloutv1alpha1.CrossClusterObjectNameReference{ + Cluster: "cluster-a", + Name: "test", + }, + Replicas: intstr.FromString("100%"), + }, + }, + }, + }, + }, + }, + }, + isSupportedGVK: supportAllGVK, + wantErr: false, + }, + { + name: "batch strategy with multiple targets in one batch", + obj: &rolloutv1alpha1.Rollout{ + ObjectMeta: validMetadata, + Spec: rolloutv1alpha1.RolloutSpec{ + TriggerPolicy: "Auto", + WorkloadRef: validWorkloadRef, + BatchStrategy: &rolloutv1alpha1.RolloutRunBatchStrategy{ + Batches: []rolloutv1alpha1.RolloutRunStep{ + { + Targets: []rolloutv1alpha1.RolloutRunStepTarget{ + { + CrossClusterObjectNameReference: rolloutv1alpha1.CrossClusterObjectNameReference{ + Cluster: "cluster-a", + Name: "test-1", + }, + Replicas: intstr.FromString("20%"), + }, + { + CrossClusterObjectNameReference: rolloutv1alpha1.CrossClusterObjectNameReference{ + Cluster: "cluster-b", + Name: "test-2", + }, + Replicas: intstr.FromString("30%"), + }, + }, + }, + }, + }, + }, + }, + isSupportedGVK: supportAllGVK, + wantErr: false, + }, + { + name: "empty batch strategy - no batches", + obj: &rolloutv1alpha1.Rollout{ + ObjectMeta: validMetadata, + Spec: rolloutv1alpha1.RolloutSpec{ + TriggerPolicy: "Auto", + WorkloadRef: validWorkloadRef, + BatchStrategy: &rolloutv1alpha1.RolloutRunBatchStrategy{ + Batches: []rolloutv1alpha1.RolloutRunStep{}, + }, + }, + }, + isSupportedGVK: supportAllGVK, + wantErr: true, + errMsg: "must specify at least one batch", + }, + { + name: "batch with empty targets", + obj: &rolloutv1alpha1.Rollout{ + ObjectMeta: validMetadata, + Spec: rolloutv1alpha1.RolloutSpec{ + TriggerPolicy: "Auto", + WorkloadRef: validWorkloadRef, + BatchStrategy: &rolloutv1alpha1.RolloutRunBatchStrategy{ + Batches: []rolloutv1alpha1.RolloutRunStep{ + { + Targets: []rolloutv1alpha1.RolloutRunStepTarget{}, + }, + }, + }, + }, + }, + isSupportedGVK: supportAllGVK, + wantErr: true, + errMsg: "must specify at least one target", + }, + { + name: "target missing name", + obj: &rolloutv1alpha1.Rollout{ + ObjectMeta: validMetadata, + Spec: rolloutv1alpha1.RolloutSpec{ + TriggerPolicy: "Auto", + WorkloadRef: validWorkloadRef, + BatchStrategy: &rolloutv1alpha1.RolloutRunBatchStrategy{ + Batches: []rolloutv1alpha1.RolloutRunStep{ + { + Targets: []rolloutv1alpha1.RolloutRunStepTarget{ + { + CrossClusterObjectNameReference: rolloutv1alpha1.CrossClusterObjectNameReference{ + Cluster: "cluster-a", + }, + Replicas: intstr.FromString("20%"), + }, + }, + }, + }, + }, + }, + }, + isSupportedGVK: supportAllGVK, + wantErr: true, + errMsg: "name is required", + }, + { + name: "target with invalid replicas", + obj: &rolloutv1alpha1.Rollout{ + ObjectMeta: validMetadata, + Spec: rolloutv1alpha1.RolloutSpec{ + TriggerPolicy: "Auto", + WorkloadRef: validWorkloadRef, + BatchStrategy: &rolloutv1alpha1.RolloutRunBatchStrategy{ + Batches: []rolloutv1alpha1.RolloutRunStep{ + { + Targets: []rolloutv1alpha1.RolloutRunStepTarget{ + { + CrossClusterObjectNameReference: rolloutv1alpha1.CrossClusterObjectNameReference{ + Cluster: "cluster-a", + Name: "test", + }, + Replicas: intstr.FromString("-1"), + }, + }, + }, + }, + }, + }, + }, + isSupportedGVK: supportAllGVK, + wantErr: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := ValidateRollout(tt.obj, tt.isSupportedGVK) + hasErr := got.ToAggregate() != nil + if tt.wantErr != hasErr { + t.Errorf("ValidateRollout() error = %v, wantErr %v", got.ToAggregate(), tt.wantErr) + return + } + if tt.wantErr && tt.errMsg != "" { + errStr := got.ToAggregate().Error() + if !containsString(errStr, tt.errMsg) { + t.Errorf("ValidateRollout() error message = %q, should contain %q", errStr, tt.errMsg) + } + } + }) + } +} + +// Tests for StrategyRef and inline strategy mutual exclusion +func TestValidateRollout_StrategyMutualExclusion(t *testing.T) { + tests := []struct { + name string + obj *rolloutv1alpha1.Rollout + isSupportedGVK SupportedGVKFunc + wantErr bool + errMsg string + }{ + { + name: "StrategyRef is mutually exclusive with BatchStrategy", + obj: &rolloutv1alpha1.Rollout{ + ObjectMeta: validMetadata, + Spec: rolloutv1alpha1.RolloutSpec{ + TriggerPolicy: "Auto", + StrategyRef: "strategy-a", + WorkloadRef: validWorkloadRef, + BatchStrategy: &rolloutv1alpha1.RolloutRunBatchStrategy{ + Batches: []rolloutv1alpha1.RolloutRunStep{ + { + Targets: []rolloutv1alpha1.RolloutRunStepTarget{ + { + CrossClusterObjectNameReference: rolloutv1alpha1.CrossClusterObjectNameReference{ + Cluster: "cluster-a", + Name: "test", + }, + Replicas: intstr.FromString("20%"), + }, + }, + }, + }, + }, + }, + }, + isSupportedGVK: supportAllGVK, + wantErr: true, + errMsg: "strategyRef is mutually exclusive with batchStrategy", + }, + { + name: "neither StrategyRef nor BatchStrategy specified", + obj: &rolloutv1alpha1.Rollout{ + ObjectMeta: validMetadata, + Spec: rolloutv1alpha1.RolloutSpec{ + TriggerPolicy: "Auto", + WorkloadRef: validWorkloadRef, + }, + }, + isSupportedGVK: supportAllGVK, + wantErr: true, + errMsg: "must specify either strategyRef, or batchStrategy", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := ValidateRollout(tt.obj, tt.isSupportedGVK) + hasErr := got.ToAggregate() != nil + if tt.wantErr != hasErr { + t.Errorf("ValidateRollout() error = %v, wantErr %v", got.ToAggregate(), tt.wantErr) + return + } + if tt.wantErr && tt.errMsg != "" { + errStr := got.ToAggregate().Error() + if !containsString(errStr, tt.errMsg) { + t.Errorf("ValidateRollout() error message = %q, should contain %q", errStr, tt.errMsg) + } + } + }) + } +} + +// Helper function +func containsString(s, substr string) bool { + return len(s) >= len(substr) && (s == substr || len(s) > 0 && containsStringSub(s, substr)) +} + +func containsStringSub(s, substr string) bool { + for i := 0; i <= len(s)-len(substr); i++ { + if s[i:i+len(substr)] == substr { + return true + } + } + return false +} diff --git a/config/crd/bases/rollout.kusionstack.io_rolloutruns.yaml b/config/crd/bases/rollout.kusionstack.io_rolloutruns.yaml index b580d4e..f6ddbe0 100644 --- a/config/crd/bases/rollout.kusionstack.io_rolloutruns.yaml +++ b/config/crd/bases/rollout.kusionstack.io_rolloutruns.yaml @@ -11,4961 +11,4946 @@ spec: listKind: RolloutRunList plural: rolloutruns shortNames: - - ror + - ror singular: rolloutrun scope: Namespaced versions: - - additionalPrinterColumns: - - jsonPath: .metadata.ownerReferences[0].name - name: OWNER - type: string - - jsonPath: .status.phase - name: Phase - type: string - - jsonPath: .status.canaryStatus.state - name: Canary State - type: string - - jsonPath: .status.batchStatus.currentBatchIndex - name: Batch Index - type: string - - jsonPath: .status.batchStatus.currentBatchState - name: Batch State - type: string - - jsonPath: .status.error.code - name: Error - type: string - - format: date-time - jsonPath: .metadata.creationTimestamp - name: AGE - type: date - name: v1alpha1 - schema: - openAPIV3Schema: - properties: - apiVersion: - description: |- - APIVersion defines the versioned schema of this representation of an object. - Servers should convert recognized schemas to the latest internal value, and - may reject unrecognized values. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources - type: string - kind: - description: |- - Kind is a string value representing the REST resource this object represents. - Servers may infer this from the endpoint the client submits requests to. - Cannot be updated. - In CamelCase. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - type: string - metadata: - type: object - spec: - properties: - batch: - description: Batch Strategy - properties: - batches: - description: Batches define the order of phases to execute release in batch release - items: - properties: - breakpoint: - description: If set to true, the rollout will be paused before the step starts. - type: boolean + - additionalPrinterColumns: + - jsonPath: .metadata.ownerReferences[0].name + name: OWNER + type: string + - jsonPath: .status.phase + name: Phase + type: string + - jsonPath: .status.canaryStatus.state + name: Canary State + type: string + - jsonPath: .status.batchStatus.currentBatchIndex + name: Batch Index + type: string + - jsonPath: .status.batchStatus.currentBatchState + name: Batch State + type: string + - jsonPath: .status.error.code + name: Error + type: string + - format: date-time + jsonPath: .metadata.creationTimestamp + name: AGE + type: date + name: v1alpha1 + schema: + openAPIV3Schema: + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + properties: + batch: + description: Batch Strategy + properties: + batches: + description: Batches define the order of phases to execute release in batch release + items: properties: - additionalProperties: - type: string - description: Properties contains additional information for step - type: object - targets: - description: desired target replicas - items: - properties: - cluster: - description: Cluster indicates the name of cluster - type: string - name: - description: Name is the resource name - type: string - replicaSlidingWindow: - anyOf: - - type: integer - - type: string - description: |- - ReplicaSlidingWindow used to control the number of pods that are allowed to be upgraded in - a sliding window for progressive rollout smoothly. - x-kubernetes-int-or-string: true - replicas: - anyOf: - - type: integer - - type: string - description: Replicas is the replicas of the rollout task, which represents the number of pods to be upgraded - x-kubernetes-int-or-string: true - required: - - name - - replicas - type: object - type: array - traffic: - description: traffic strategy + breakpoint: + description: If set to true, the rollout will be paused before the step starts. + type: boolean properties: - http: + additionalProperties: + type: string + description: Properties contains additional information for step + type: object + targets: + description: desired target replicas + items: properties: - filters: + cluster: + description: Cluster indicates the name of cluster + type: string + name: + description: Name is the resource name + type: string + replicaSlidingWindow: + anyOf: + - type: integer + - type: string description: |- - Filters define the filters that are applied to requests that match - this rule. - - - The effects of ordering of multiple behaviors are currently unspecified. - This can change in the future based on feedback during the alpha stage. - - - Conformance-levels at this level are defined based on the type of filter: - - - - ALL core filters MUST be supported by all implementations. - - Implementers are encouraged to support extended filters. - - Implementation-specific custom filters have no API guarantees across - implementations. - - - Specifying the same filter multiple times is not supported unless explicitly - indicated in the filter. - - - All filters are expected to be compatible with each other except for the - URLRewrite and RequestRedirect filters, which may not be combined. If an - implementation can not support other combinations of filters, they must clearly - document that limitation. In cases where incompatible or unsupported - filters are specified and cause the `Accepted` condition to be set to status - `False`, implementations may use the `IncompatibleFilters` reason to specify - this configuration error. - - - Support: Core - items: + ReplicaSlidingWindow used to control the number of pods that are allowed to be upgraded in + a sliding window for progressive rollout smoothly. + x-kubernetes-int-or-string: true + replicas: + anyOf: + - type: integer + - type: string + description: Replicas is the replicas of the rollout task, which represents the number of pods to be upgraded + x-kubernetes-int-or-string: true + required: + - name + - replicas + type: object + type: array + traffic: + description: traffic strategy + properties: + http: + properties: + filters: description: |- - HTTPRouteFilter defines processing steps that must be completed during the - request or response lifecycle. HTTPRouteFilters are meant as an extension - point to express processing that may be done in Gateway implementations. Some - examples include request or response modification, implementing - authentication strategies, rate-limiting, and traffic shaping. API - guarantee/conformance is defined based on the type of the filter. - properties: - extensionRef: - description: |- - ExtensionRef is an optional, implementation-specific extension to the - "filter" behavior. For example, resource "myroutefilter" in group - "networking.example.net"). ExtensionRef MUST NOT be used for core and - extended filters. - - - This filter can be used multiple times within the same rule. - - - Support: Implementation-specific - properties: - group: - description: |- - Group is the group of the referent. For example, "gateway.networking.k8s.io". - When unspecified or empty string, core API group is inferred. - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - description: Kind is kind of the referent. For example "HTTPRoute" or "Service". - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - type: string - name: - description: Name is the name of the referent. - maxLength: 253 - minLength: 1 - type: string - required: - - group - - kind - - name - type: object - requestHeaderModifier: - description: |- - RequestHeaderModifier defines a schema for a filter that modifies request - headers. - - - Support: Core - properties: - add: - description: |- - Add adds the given header(s) (name, value) to the request - before the action. It appends to any existing values associated - with the header name. - - - Input: - GET /foo HTTP/1.1 - my-header: foo - - - Config: - add: - - name: "my-header" - value: "bar,baz" - - - Output: - GET /foo HTTP/1.1 - my-header: foo,bar,baz - items: - description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. + Filters define the filters that are applied to requests that match + this rule. + + + The effects of ordering of multiple behaviors are currently unspecified. + This can change in the future based on feedback during the alpha stage. + + + Conformance-levels at this level are defined based on the type of filter: + + + - ALL core filters MUST be supported by all implementations. + - Implementers are encouraged to support extended filters. + - Implementation-specific custom filters have no API guarantees across + implementations. + + + Specifying the same filter multiple times is not supported unless explicitly + indicated in the filter. + + + All filters are expected to be compatible with each other except for the + URLRewrite and RequestRedirect filters, which may not be combined. If an + implementation can not support other combinations of filters, they must clearly + document that limitation. In cases where incompatible or unsupported + filters are specified and cause the `Accepted` condition to be set to status + `False`, implementations may use the `IncompatibleFilters` reason to specify + this configuration error. + + + Support: Core + items: + description: |- + HTTPRouteFilter defines processing steps that must be completed during the + request or response lifecycle. HTTPRouteFilters are meant as an extension + point to express processing that may be done in Gateway implementations. Some + examples include request or response modification, implementing + authentication strategies, rate-limiting, and traffic shaping. API + guarantee/conformance is defined based on the type of the filter. + properties: + extensionRef: + description: |- + ExtensionRef is an optional, implementation-specific extension to the + "filter" behavior. For example, resource "myroutefilter" in group + "networking.example.net"). ExtensionRef MUST NOT be used for core and + extended filters. + + + This filter can be used multiple times within the same rule. + + + Support: Implementation-specific + properties: + group: + description: |- + Group is the group of the referent. For example, "gateway.networking.k8s.io". + When unspecified or empty string, core API group is inferred. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + description: Kind is kind of the referent. For example "HTTPRoute" or "Service". + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: Name is the name of the referent. + maxLength: 253 + minLength: 1 + type: string + required: + - group + - kind + - name + type: object + requestHeaderModifier: + description: |- + RequestHeaderModifier defines a schema for a filter that modifies request + headers. + + + Support: Core + properties: + add: + description: |- + Add adds the given header(s) (name, value) to the request + before the action. It appends to any existing values associated + with the header name. + + + Input: + GET /foo HTTP/1.1 + my-header: foo + + + Config: + add: + - name: "my-header" + value: "bar,baz" + + + Output: + GET /foo HTTP/1.1 + my-header: foo,bar,baz + items: + description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + + If multiple entries specify equivalent header names, the first entry with + an equivalent name MUST be considered for a match. Subsequent entries + with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + description: Value is the value of HTTP Header to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + remove: + description: |- + Remove the given header(s) from the HTTP request before the action. The + value of Remove is a list of HTTP header names. Note that the header + names are case-insensitive (see + https://datatracker.ietf.org/doc/html/rfc2616#section-4.2). + + + Input: + GET /foo HTTP/1.1 + my-header1: foo + my-header2: bar + my-header3: baz + + + Config: + remove: ["my-header1", "my-header3"] + + + Output: + GET /foo HTTP/1.1 + my-header2: bar + items: + type: string + maxItems: 16 + type: array + x-kubernetes-list-type: set + set: + description: |- + Set overwrites the request with the given header (name, value) + before the action. + + + Input: + GET /foo HTTP/1.1 + my-header: foo + + + Config: + set: + - name: "my-header" + value: "bar" + + + Output: + GET /foo HTTP/1.1 + my-header: bar + items: + description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + + If multiple entries specify equivalent header names, the first entry with + an equivalent name MUST be considered for a match. Subsequent entries + with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + description: Value is the value of HTTP Header to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + type: object + requestMirror: + description: |- + RequestMirror defines a schema for a filter that mirrors requests. + Requests are sent to the specified destination, but responses from + that destination are ignored. + + + This filter can be used multiple times within the same rule. Note that + not all implementations will be able to support mirroring to multiple + backends. + + + Support: Extended + + + + properties: + backendRef: + description: |- + BackendRef references a resource where mirrored requests are sent. + + + Mirrored requests must be sent only to a single destination endpoint + within this BackendRef, irrespective of how many endpoints are present + within this BackendRef. + + + If the referent cannot be found, this BackendRef is invalid and must be + dropped from the Gateway. The controller must ensure the "ResolvedRefs" + condition on the Route status is set to `status: False` and not configure + this backend in the underlying implementation. + + + If there is a cross-namespace reference to an *existing* object + that is not allowed by a ReferenceGrant, the controller must ensure the + "ResolvedRefs" condition on the Route is set to `status: False`, + with the "RefNotPermitted" reason and not configure this backend in the + underlying implementation. + + + In either error case, the Message of the `ResolvedRefs` Condition + should be used to provide more detail about the problem. + + + Support: Extended for Kubernetes Service + + + Support: Implementation-specific for any other resource properties: - name: + group: + default: "" description: |- - Name is the name of the HTTP Header to be matched. Name matching MUST be - case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). - - - If multiple entries specify equivalent header names, the first entry with - an equivalent name MUST be considered for a match. Subsequent entries - with an equivalent header name MUST be ignored. Due to the - case-insensitivity of header names, "foo" and "Foo" are considered - equivalent. - maxLength: 256 - minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + Group is the group of the referent. For example, "gateway.networking.k8s.io". + When unspecified or empty string, core API group is inferred. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ type: string - value: - description: Value is the value of HTTP Header to be matched. - maxLength: 4096 + kind: + default: Service + description: |- + Kind is the Kubernetes resource kind of the referent. For example + "Service". + + + Defaults to "Service" when not specified. + + + ExternalName services can refer to CNAME DNS records that may live + outside of the cluster and as such are difficult to reason about in + terms of conformance. They also may not be safe to forward to (see + CVE-2021-25740 for more information). Implementations SHOULD NOT + support ExternalName Services. + + + Support: Core (Services with a type other than ExternalName) + + + Support: Implementation-specific (Services with type ExternalName) + maxLength: 63 minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ type: string - required: - - name - - value - type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - remove: - description: |- - Remove the given header(s) from the HTTP request before the action. The - value of Remove is a list of HTTP header names. Note that the header - names are case-insensitive (see - https://datatracker.ietf.org/doc/html/rfc2616#section-4.2). - - - Input: - GET /foo HTTP/1.1 - my-header1: foo - my-header2: bar - my-header3: baz - - - Config: - remove: ["my-header1", "my-header3"] - - - Output: - GET /foo HTTP/1.1 - my-header2: bar - items: - type: string - maxItems: 16 - type: array - x-kubernetes-list-type: set - set: - description: |- - Set overwrites the request with the given header (name, value) - before the action. - - - Input: - GET /foo HTTP/1.1 - my-header: foo - - - Config: - set: - - name: "my-header" - value: "bar" - - - Output: - GET /foo HTTP/1.1 - my-header: bar - items: - description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. - properties: name: - description: |- - Name is the name of the HTTP Header to be matched. Name matching MUST be - case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). - - - If multiple entries specify equivalent header names, the first entry with - an equivalent name MUST be considered for a match. Subsequent entries - with an equivalent header name MUST be ignored. Due to the - case-insensitivity of header names, "foo" and "Foo" are considered - equivalent. - maxLength: 256 + description: Name is the name of the referent. + maxLength: 253 minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ type: string - value: - description: Value is the value of HTTP Header to be matched. - maxLength: 4096 + namespace: + description: |- + Namespace is the namespace of the backend. When unspecified, the local + namespace is inferred. + + + Note that when a namespace different than the local namespace is specified, + a ReferenceGrant object is required in the referent namespace to allow that + namespace's owner to accept the reference. See the ReferenceGrant + documentation for details. + + + Support: Core + maxLength: 63 minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ type: string + port: + description: |- + Port specifies the destination port number to use for this resource. + Port is required when the referent is a Kubernetes Service. In this + case, the port number is the service port number, not the target port. + For other resources, destination port might be derived from the referent + resource or this field. + format: int32 + maximum: 65535 + minimum: 1 + type: integer required: - - name - - value + - name type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - type: object - requestMirror: - description: |- - RequestMirror defines a schema for a filter that mirrors requests. - Requests are sent to the specified destination, but responses from - that destination are ignored. - - - This filter can be used multiple times within the same rule. Note that - not all implementations will be able to support mirroring to multiple - backends. - - - Support: Extended - - - - properties: - backendRef: + fraction: + description: |- + Fraction represents the fraction of requests that should be + mirrored to BackendRef. + + + Only one of Fraction or Percent may be specified. If neither field + is specified, 100% of requests will be mirrored. + + + + properties: + denominator: + default: 100 + format: int32 + minimum: 1 + type: integer + numerator: + format: int32 + minimum: 0 + type: integer + required: + - numerator + type: object + percent: + description: |- + Percent represents the percentage of requests that should be + mirrored to BackendRef. Its minimum value is 0 (indicating 0% of + requests) and its maximum value is 100 (indicating 100% of requests). + + + Only one of Fraction or Percent may be specified. If neither field + is specified, 100% of requests will be mirrored. + + + + format: int32 + maximum: 100 + minimum: 0 + type: integer + required: + - backendRef + type: object + requestRedirect: + description: |- + RequestRedirect defines a schema for a filter that responds to the + request with an HTTP redirection. + + + Support: Core + properties: + hostname: + description: |- + Hostname is the hostname to be used in the value of the `Location` + header in the response. + When empty, the hostname in the `Host` header of the request is used. + + + Support: Core + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + path: + description: |- + Path defines parameters used to modify the path of the incoming request. + The modified path is then used to construct the `Location` header. When + empty, the request path is used as-is. + + + Support: Extended + properties: + replaceFullPath: + description: |- + ReplaceFullPath specifies the value with which to replace the full path + of a request during a rewrite or redirect. + maxLength: 1024 + type: string + replacePrefixMatch: + description: |- + ReplacePrefixMatch specifies the value with which to replace the prefix + match of a request during a rewrite or redirect. For example, a request + to "/foo/bar" with a prefix match of "/foo" and a ReplacePrefixMatch + of "/xyz" would be modified to "/xyz/bar". + + + Note that this matches the behavior of the PathPrefix match type. This + matches full path elements. A path element refers to the list of labels + in the path split by the `/` separator. When specified, a trailing `/` is + ignored. For example, the paths `/abc`, `/abc/`, and `/abc/def` would all + match the prefix `/abc`, but the path `/abcd` would not. + + + ReplacePrefixMatch is only compatible with a `PathPrefix` HTTPRouteMatch. + Using any other HTTPRouteMatch type on the same HTTPRouteRule will result in + the implementation setting the Accepted Condition for the Route to `status: False`. + + + Request Path | Prefix Match | Replace Prefix | Modified Path + -------------|--------------|----------------|---------- + /foo/bar | /foo | /xyz | /xyz/bar + /foo/bar | /foo | /xyz/ | /xyz/bar + /foo/bar | /foo/ | /xyz | /xyz/bar + /foo/bar | /foo/ | /xyz/ | /xyz/bar + /foo | /foo | /xyz | /xyz + /foo/ | /foo | /xyz | /xyz/ + /foo/bar | /foo | | /bar + /foo/ | /foo | | / + /foo | /foo | | / + /foo/ | /foo | / | / + /foo | /foo | / | / + maxLength: 1024 + type: string + type: + description: |- + Type defines the type of path modifier. Additional types may be + added in a future release of the API. + + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + enum: + - ReplaceFullPath + - ReplacePrefixMatch + type: string + required: + - type + type: object + port: + description: |- + Port is the port to be used in the value of the `Location` + header in the response. + + + If no port is specified, the redirect port MUST be derived using the + following rules: + + + * If redirect scheme is not-empty, the redirect port MUST be the well-known + port associated with the redirect scheme. Specifically "http" to port 80 + and "https" to port 443. If the redirect scheme does not have a + well-known port, the listener port of the Gateway SHOULD be used. + * If redirect scheme is empty, the redirect port MUST be the Gateway + Listener port. + + + Implementations SHOULD NOT add the port number in the 'Location' + header in the following cases: + + + * A Location header that will use HTTP (whether that is determined via + the Listener protocol or the Scheme field) _and_ use port 80. + * A Location header that will use HTTPS (whether that is determined via + the Listener protocol or the Scheme field) _and_ use port 443. + + + Support: Extended + format: int32 + maximum: 65535 + minimum: 1 + type: integer + scheme: + description: |- + Scheme is the scheme to be used in the value of the `Location` header in + the response. When empty, the scheme of the request is used. + + + Scheme redirects can affect the port of the redirect, for more information, + refer to the documentation for the port field of this filter. + + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + + + Support: Extended + enum: + - http + - https + type: string + statusCode: + default: 302 + description: |- + StatusCode is the HTTP status code to be used in response. + + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + + + Support: Core + enum: + - 301 + - 302 + type: integer + type: object + responseHeaderModifier: + description: |- + ResponseHeaderModifier defines a schema for a filter that modifies response + headers. + + + Support: Extended + properties: + add: + description: |- + Add adds the given header(s) (name, value) to the request + before the action. It appends to any existing values associated + with the header name. + + + Input: + GET /foo HTTP/1.1 + my-header: foo + + + Config: + add: + - name: "my-header" + value: "bar,baz" + + + Output: + GET /foo HTTP/1.1 + my-header: foo,bar,baz + items: + description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + + If multiple entries specify equivalent header names, the first entry with + an equivalent name MUST be considered for a match. Subsequent entries + with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + description: Value is the value of HTTP Header to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + remove: + description: |- + Remove the given header(s) from the HTTP request before the action. The + value of Remove is a list of HTTP header names. Note that the header + names are case-insensitive (see + https://datatracker.ietf.org/doc/html/rfc2616#section-4.2). + + + Input: + GET /foo HTTP/1.1 + my-header1: foo + my-header2: bar + my-header3: baz + + + Config: + remove: ["my-header1", "my-header3"] + + + Output: + GET /foo HTTP/1.1 + my-header2: bar + items: + type: string + maxItems: 16 + type: array + x-kubernetes-list-type: set + set: + description: |- + Set overwrites the request with the given header (name, value) + before the action. + + + Input: + GET /foo HTTP/1.1 + my-header: foo + + + Config: + set: + - name: "my-header" + value: "bar" + + + Output: + GET /foo HTTP/1.1 + my-header: bar + items: + description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + + If multiple entries specify equivalent header names, the first entry with + an equivalent name MUST be considered for a match. Subsequent entries + with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + description: Value is the value of HTTP Header to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + type: object + type: + description: |- + Type identifies the type of filter to apply. As with other API fields, + types are classified into three conformance levels: + + + - Core: Filter types and their corresponding configuration defined by + "Support: Core" in this package, e.g. "RequestHeaderModifier". All + implementations must support core filters. + + + - Extended: Filter types and their corresponding configuration defined by + "Support: Extended" in this package, e.g. "RequestMirror". Implementers + are encouraged to support extended filters. + + + - Implementation-specific: Filters that are defined and supported by + specific vendors. + In the future, filters showing convergence in behavior across multiple + implementations will be considered for inclusion in extended or core + conformance levels. Filter-specific configuration for such filters + is specified using the ExtensionRef field. `Type` should be set to + "ExtensionRef" for custom filters. + + + Implementers are encouraged to define custom implementation types to + extend the core API with implementation-specific behavior. + + + If a reference to a custom filter type cannot be resolved, the filter + MUST NOT be skipped. Instead, requests that would have been processed by + that filter MUST receive a HTTP error response. + + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + enum: + - RequestHeaderModifier + - ResponseHeaderModifier + - RequestMirror + - RequestRedirect + - URLRewrite + - ExtensionRef + type: string + urlRewrite: + description: |- + URLRewrite defines a schema for a filter that modifies a request during forwarding. + + + Support: Extended + properties: + hostname: + description: |- + Hostname is the value to be used to replace the Host header value during + forwarding. + + + Support: Extended + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + path: + description: |- + Path defines a path rewrite. + + + Support: Extended + properties: + replaceFullPath: + description: |- + ReplaceFullPath specifies the value with which to replace the full path + of a request during a rewrite or redirect. + maxLength: 1024 + type: string + replacePrefixMatch: + description: |- + ReplacePrefixMatch specifies the value with which to replace the prefix + match of a request during a rewrite or redirect. For example, a request + to "/foo/bar" with a prefix match of "/foo" and a ReplacePrefixMatch + of "/xyz" would be modified to "/xyz/bar". + + + Note that this matches the behavior of the PathPrefix match type. This + matches full path elements. A path element refers to the list of labels + in the path split by the `/` separator. When specified, a trailing `/` is + ignored. For example, the paths `/abc`, `/abc/`, and `/abc/def` would all + match the prefix `/abc`, but the path `/abcd` would not. + + + ReplacePrefixMatch is only compatible with a `PathPrefix` HTTPRouteMatch. + Using any other HTTPRouteMatch type on the same HTTPRouteRule will result in + the implementation setting the Accepted Condition for the Route to `status: False`. + + + Request Path | Prefix Match | Replace Prefix | Modified Path + -------------|--------------|----------------|---------- + /foo/bar | /foo | /xyz | /xyz/bar + /foo/bar | /foo | /xyz/ | /xyz/bar + /foo/bar | /foo/ | /xyz | /xyz/bar + /foo/bar | /foo/ | /xyz/ | /xyz/bar + /foo | /foo | /xyz | /xyz + /foo/ | /foo | /xyz | /xyz/ + /foo/bar | /foo | | /bar + /foo/ | /foo | | / + /foo | /foo | | / + /foo/ | /foo | / | / + /foo | /foo | / | / + maxLength: 1024 + type: string + type: + description: |- + Type defines the type of path modifier. Additional types may be + added in a future release of the API. + + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + enum: + - ReplaceFullPath + - ReplacePrefixMatch + type: string + required: + - type + type: object + type: object + required: + - type + type: object + maxItems: 16 + type: array + matches: + description: |- + Matches define conditions used for matching the rule against incoming + HTTP requests. Each match is independent, i.e. this rule will be matched + if **any** one of the matches is satisfied. + + + For example, take the following matches configuration: + + + ``` + matches: + - path: + value: "/foo" + headers: + - name: "version" + value: "v2" + - path: + value: "/v2/foo" + ``` + + + For a request to match against this rule, a request must satisfy + EITHER of the two conditions: + + + - path prefixed with `/foo` AND contains the header `version: v2` + - path prefix of `/v2/foo` + + + See the documentation for HTTPRouteMatch on how to specify multiple + match conditions that should be ANDed together. + + + If no matches are specified, the default is a prefix + path match on "/", which has the effect of matching every + HTTP request. + + + Proxy or Load Balancer routing configuration generated from HTTPRoutes + MUST prioritize matches based on the following criteria, continuing on + ties. Across all rules specified on applicable Routes, precedence must be + given to the match having: + + + * "Exact" path match. + * "Prefix" path match with largest number of characters. + * Method match. + * Largest number of header matches. + * Largest number of query param matches. + + + Note: The precedence of RegularExpression path matches are implementation-specific. + + + If ties still exist across multiple Routes, matching precedence MUST be + determined in order of the following criteria, continuing on ties: + + + * The oldest Route based on creation timestamp. + * The Route appearing first in alphabetical order by + "{namespace}/{name}". + + + If ties still exist within an HTTPRoute, matching precedence MUST be granted + to the FIRST matching rule (in list order) with a match meeting the above + criteria. + + + When no rules matching a request have been successfully attached to the + parent a request is coming from, a HTTP 404 status code MUST be returned. + items: + properties: + headers: + description: |- + Headers specifies HTTP request header matchers. Multiple match values are + ANDed together, meaning, a request must match all the specified headers + to select the route. + items: description: |- - BackendRef references a resource where mirrored requests are sent. - - - Mirrored requests must be sent only to a single destination endpoint - within this BackendRef, irrespective of how many endpoints are present - within this BackendRef. - - - If the referent cannot be found, this BackendRef is invalid and must be - dropped from the Gateway. The controller must ensure the "ResolvedRefs" - condition on the Route status is set to `status: False` and not configure - this backend in the underlying implementation. - - - If there is a cross-namespace reference to an *existing* object - that is not allowed by a ReferenceGrant, the controller must ensure the - "ResolvedRefs" condition on the Route is set to `status: False`, - with the "RefNotPermitted" reason and not configure this backend in the - underlying implementation. - - - In either error case, the Message of the `ResolvedRefs` Condition - should be used to provide more detail about the problem. - - - Support: Extended for Kubernetes Service - - - Support: Implementation-specific for any other resource + HTTPHeaderMatch describes how to select a HTTP route by matching HTTP request + headers. properties: - group: - default: "" + name: description: |- - Group is the group of the referent. For example, "gateway.networking.k8s.io". - When unspecified or empty string, core API group is inferred. - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + + If multiple entries specify equivalent header names, only the first + entry with an equivalent name MUST be considered for a match. Subsequent + entries with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + + + When a header is repeated in an HTTP request, it is + implementation-specific behavior as to how this is represented. + Generally, proxies should follow the guidance from the RFC: + https://www.rfc-editor.org/rfc/rfc7230.html#section-3.2.2 regarding + processing a repeated header, with special handling for "Set-Cookie". + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ type: string - kind: - default: Service + type: + default: Exact description: |- - Kind is the Kubernetes resource kind of the referent. For example - "Service". - - - Defaults to "Service" when not specified. - - - ExternalName services can refer to CNAME DNS records that may live - outside of the cluster and as such are difficult to reason about in - terms of conformance. They also may not be safe to forward to (see - CVE-2021-25740 for more information). Implementations SHOULD NOT - support ExternalName Services. - - - Support: Core (Services with a type other than ExternalName) - - - Support: Implementation-specific (Services with type ExternalName) - maxLength: 63 + Type specifies how to match against the value of the header. + + + Support: Core (Exact) + + + Support: Implementation-specific (RegularExpression) + + + Since RegularExpression HeaderMatchType has implementation-specific + conformance, implementations can support POSIX, PCRE or any other dialects + of regular expressions. Please read the implementation's documentation to + determine the supported dialect. + enum: + - Exact + - RegularExpression + type: string + value: + description: Value is the value of HTTP Header to be matched. + maxLength: 4096 minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + path: + description: Path specifies a HTTP request path matcher. + properties: + type: + default: PathPrefix + description: |- + Type specifies how to match against the path Value. + + + Support: Core (Exact, PathPrefix) + + + Support: Implementation-specific (RegularExpression) + enum: + - Exact + - PathPrefix + - RegularExpression + type: string + value: + default: / + description: Value of the HTTP path to match against. + maxLength: 1024 + type: string + type: object + queryParams: + description: |- + QueryParams specifies HTTP query parameter matchers. Multiple match + values are ANDed together, meaning, a request must match all the + specified query parameters to select the route. + + + Support: Extended + items: + description: |- + HTTPQueryParamMatch describes how to select a HTTP route by matching HTTP + query parameters. + properties: name: - description: Name is the name of the referent. - maxLength: 253 + description: |- + Name is the name of the HTTP query param to be matched. This must be an + exact string match. (See + https://tools.ietf.org/html/rfc7230#section-2.7.3). + + + If multiple entries specify equivalent query param names, only the first + entry with an equivalent name MUST be considered for a match. Subsequent + entries with an equivalent query param name MUST be ignored. + + + If a query param is repeated in an HTTP request, the behavior is + purposely left undefined, since different data planes have different + capabilities. However, it is *recommended* that implementations should + match against the first value of the param if the data plane supports it, + as this behavior is expected in other load balancing contexts outside of + the Gateway API. + + + Users SHOULD NOT route traffic based on repeated query params to guard + themselves against potential differences in the implementations. + maxLength: 256 minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ type: string - namespace: + type: + default: Exact description: |- - Namespace is the namespace of the backend. When unspecified, the local - namespace is inferred. - - - Note that when a namespace different than the local namespace is specified, - a ReferenceGrant object is required in the referent namespace to allow that - namespace's owner to accept the reference. See the ReferenceGrant - documentation for details. - - - Support: Core - maxLength: 63 + Type specifies how to match against the value of the query parameter. + + + Support: Extended (Exact) + + + Support: Implementation-specific (RegularExpression) + + + Since RegularExpression QueryParamMatchType has Implementation-specific + conformance, implementations can support POSIX, PCRE or any other + dialects of regular expressions. Please read the implementation's + documentation to determine the supported dialect. + enum: + - Exact + - RegularExpression + type: string + value: + description: Value is the value of HTTP query param to be matched. + maxLength: 1024 minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ type: string - port: - description: |- - Port specifies the destination port number to use for this resource. - Port is required when the referent is a Kubernetes Service. In this - case, the port number is the service port number, not the target port. - For other resources, destination port might be derived from the referent - resource or this field. - format: int32 - maximum: 65535 - minimum: 1 - type: integer - required: - - name - type: object - fraction: - description: |- - Fraction represents the fraction of requests that should be - mirrored to BackendRef. - - - Only one of Fraction or Percent may be specified. If neither field - is specified, 100% of requests will be mirrored. - - - - properties: - denominator: - default: 100 - format: int32 - minimum: 1 - type: integer - numerator: - format: int32 - minimum: 0 - type: integer required: - - numerator + - name + - value type: object - percent: - description: |- - Percent represents the percentage of requests that should be - mirrored to BackendRef. Its minimum value is 0 (indicating 0% of - requests) and its maximum value is 100 (indicating 100% of requests). - - - Only one of Fraction or Percent may be specified. If neither field - is specified, 100% of requests will be mirrored. - - - - format: int32 - maximum: 100 - minimum: 0 - type: integer - required: - - backendRef - type: object - requestRedirect: + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + type: object + maxItems: 8 + type: array + stableTraffic: + description: StableTraffic indicate the base traffic rule + properties: + filters: description: |- - RequestRedirect defines a schema for a filter that responds to the - request with an HTTP redirection. - - + Filters define the filters that are applied to requests that match + this rule. + + + The effects of ordering of multiple behaviors are currently unspecified. + This can change in the future based on feedback during the alpha stage. + + + Conformance-levels at this level are defined based on the type of filter: + + + - ALL core filters MUST be supported by all implementations. + - Implementers are encouraged to support extended filters. + - Implementation-specific custom filters have no API guarantees across + implementations. + + + Specifying the same filter multiple times is not supported unless explicitly + indicated in the filter. + + + All filters are expected to be compatible with each other except for the + URLRewrite and RequestRedirect filters, which may not be combined. If an + implementation can not support other combinations of filters, they must clearly + document that limitation. In cases where incompatible or unsupported + filters are specified and cause the `Accepted` condition to be set to status + `False`, implementations may use the `IncompatibleFilters` reason to specify + this configuration error. + + Support: Core - properties: - hostname: - description: |- - Hostname is the hostname to be used in the value of the `Location` - header in the response. - When empty, the hostname in the `Host` header of the request is used. - - - Support: Core - maxLength: 253 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - path: - description: |- - Path defines parameters used to modify the path of the incoming request. - The modified path is then used to construct the `Location` header. When - empty, the request path is used as-is. - - - Support: Extended - properties: - replaceFullPath: - description: |- - ReplaceFullPath specifies the value with which to replace the full path - of a request during a rewrite or redirect. - maxLength: 1024 - type: string - replacePrefixMatch: - description: |- - ReplacePrefixMatch specifies the value with which to replace the prefix - match of a request during a rewrite or redirect. For example, a request - to "/foo/bar" with a prefix match of "/foo" and a ReplacePrefixMatch - of "/xyz" would be modified to "/xyz/bar". - - - Note that this matches the behavior of the PathPrefix match type. This - matches full path elements. A path element refers to the list of labels - in the path split by the `/` separator. When specified, a trailing `/` is - ignored. For example, the paths `/abc`, `/abc/`, and `/abc/def` would all - match the prefix `/abc`, but the path `/abcd` would not. - - - ReplacePrefixMatch is only compatible with a `PathPrefix` HTTPRouteMatch. - Using any other HTTPRouteMatch type on the same HTTPRouteRule will result in - the implementation setting the Accepted Condition for the Route to `status: False`. - - - Request Path | Prefix Match | Replace Prefix | Modified Path - -------------|--------------|----------------|---------- - /foo/bar | /foo | /xyz | /xyz/bar - /foo/bar | /foo | /xyz/ | /xyz/bar - /foo/bar | /foo/ | /xyz | /xyz/bar - /foo/bar | /foo/ | /xyz/ | /xyz/bar - /foo | /foo | /xyz | /xyz - /foo/ | /foo | /xyz | /xyz/ - /foo/bar | /foo | | /bar - /foo/ | /foo | | / - /foo | /foo | | / - /foo/ | /foo | / | / - /foo | /foo | / | / - maxLength: 1024 - type: string - type: - description: |- - Type defines the type of path modifier. Additional types may be - added in a future release of the API. - - - Note that values may be added to this enum, implementations - must ensure that unknown values will not cause a crash. - - - Unknown values here must result in the implementation setting the - Accepted Condition for the Route to `status: False`, with a - Reason of `UnsupportedValue`. - enum: - - ReplaceFullPath - - ReplacePrefixMatch - type: string - required: - - type - type: object - port: - description: |- - Port is the port to be used in the value of the `Location` - header in the response. - - - If no port is specified, the redirect port MUST be derived using the - following rules: - - - * If redirect scheme is not-empty, the redirect port MUST be the well-known - port associated with the redirect scheme. Specifically "http" to port 80 - and "https" to port 443. If the redirect scheme does not have a - well-known port, the listener port of the Gateway SHOULD be used. - * If redirect scheme is empty, the redirect port MUST be the Gateway - Listener port. - - - Implementations SHOULD NOT add the port number in the 'Location' - header in the following cases: - - - * A Location header that will use HTTP (whether that is determined via - the Listener protocol or the Scheme field) _and_ use port 80. - * A Location header that will use HTTPS (whether that is determined via - the Listener protocol or the Scheme field) _and_ use port 443. - - - Support: Extended - format: int32 - maximum: 65535 - minimum: 1 - type: integer - scheme: - description: |- - Scheme is the scheme to be used in the value of the `Location` header in - the response. When empty, the scheme of the request is used. - - - Scheme redirects can affect the port of the redirect, for more information, - refer to the documentation for the port field of this filter. - - - Note that values may be added to this enum, implementations - must ensure that unknown values will not cause a crash. - - - Unknown values here must result in the implementation setting the - Accepted Condition for the Route to `status: False`, with a - Reason of `UnsupportedValue`. - - - Support: Extended - enum: - - http - - https - type: string - statusCode: - default: 302 - description: |- - StatusCode is the HTTP status code to be used in response. - - - Note that values may be added to this enum, implementations - must ensure that unknown values will not cause a crash. - - - Unknown values here must result in the implementation setting the - Accepted Condition for the Route to `status: False`, with a - Reason of `UnsupportedValue`. - - - Support: Core - enum: - - 301 - - 302 - type: integer - type: object - responseHeaderModifier: - description: |- - ResponseHeaderModifier defines a schema for a filter that modifies response - headers. - - - Support: Extended - properties: - add: - description: |- - Add adds the given header(s) (name, value) to the request - before the action. It appends to any existing values associated - with the header name. - - - Input: - GET /foo HTTP/1.1 - my-header: foo - - - Config: - add: - - name: "my-header" - value: "bar,baz" - - - Output: - GET /foo HTTP/1.1 - my-header: foo,bar,baz - items: - description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. + items: + description: |- + HTTPRouteFilter defines processing steps that must be completed during the + request or response lifecycle. HTTPRouteFilters are meant as an extension + point to express processing that may be done in Gateway implementations. Some + examples include request or response modification, implementing + authentication strategies, rate-limiting, and traffic shaping. API + guarantee/conformance is defined based on the type of the filter. + properties: + extensionRef: + description: |- + ExtensionRef is an optional, implementation-specific extension to the + "filter" behavior. For example, resource "myroutefilter" in group + "networking.example.net"). ExtensionRef MUST NOT be used for core and + extended filters. + + + This filter can be used multiple times within the same rule. + + + Support: Implementation-specific properties: - name: + group: description: |- - Name is the name of the HTTP Header to be matched. Name matching MUST be - case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). - - - If multiple entries specify equivalent header names, the first entry with - an equivalent name MUST be considered for a match. Subsequent entries - with an equivalent header name MUST be ignored. Due to the - case-insensitivity of header names, "foo" and "Foo" are considered - equivalent. - maxLength: 256 + Group is the group of the referent. For example, "gateway.networking.k8s.io". + When unspecified or empty string, core API group is inferred. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + description: Kind is kind of the referent. For example "HTTPRoute" or "Service". + maxLength: 63 minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ type: string - value: - description: Value is the value of HTTP Header to be matched. - maxLength: 4096 + name: + description: Name is the name of the referent. + maxLength: 253 minLength: 1 type: string required: - - name - - value + - group + - kind + - name type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - remove: - description: |- - Remove the given header(s) from the HTTP request before the action. The - value of Remove is a list of HTTP header names. Note that the header - names are case-insensitive (see - https://datatracker.ietf.org/doc/html/rfc2616#section-4.2). - - - Input: - GET /foo HTTP/1.1 - my-header1: foo - my-header2: bar - my-header3: baz - - - Config: - remove: ["my-header1", "my-header3"] - - - Output: - GET /foo HTTP/1.1 - my-header2: bar - items: - type: string - maxItems: 16 - type: array - x-kubernetes-list-type: set - set: - description: |- - Set overwrites the request with the given header (name, value) - before the action. - - - Input: - GET /foo HTTP/1.1 - my-header: foo - - - Config: - set: - - name: "my-header" - value: "bar" - - - Output: - GET /foo HTTP/1.1 - my-header: bar - items: - description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. + requestHeaderModifier: + description: |- + RequestHeaderModifier defines a schema for a filter that modifies request + headers. + + + Support: Core properties: - name: + add: description: |- - Name is the name of the HTTP Header to be matched. Name matching MUST be - case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). - - - If multiple entries specify equivalent header names, the first entry with - an equivalent name MUST be considered for a match. Subsequent entries - with an equivalent header name MUST be ignored. Due to the - case-insensitivity of header names, "foo" and "Foo" are considered - equivalent. - maxLength: 256 + Add adds the given header(s) (name, value) to the request + before the action. It appends to any existing values associated + with the header name. + + + Input: + GET /foo HTTP/1.1 + my-header: foo + + + Config: + add: + - name: "my-header" + value: "bar,baz" + + + Output: + GET /foo HTTP/1.1 + my-header: foo,bar,baz + items: + description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + + If multiple entries specify equivalent header names, the first entry with + an equivalent name MUST be considered for a match. Subsequent entries + with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + description: Value is the value of HTTP Header to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + remove: + description: |- + Remove the given header(s) from the HTTP request before the action. The + value of Remove is a list of HTTP header names. Note that the header + names are case-insensitive (see + https://datatracker.ietf.org/doc/html/rfc2616#section-4.2). + + + Input: + GET /foo HTTP/1.1 + my-header1: foo + my-header2: bar + my-header3: baz + + + Config: + remove: ["my-header1", "my-header3"] + + + Output: + GET /foo HTTP/1.1 + my-header2: bar + items: + type: string + maxItems: 16 + type: array + x-kubernetes-list-type: set + set: + description: |- + Set overwrites the request with the given header (name, value) + before the action. + + + Input: + GET /foo HTTP/1.1 + my-header: foo + + + Config: + set: + - name: "my-header" + value: "bar" + + + Output: + GET /foo HTTP/1.1 + my-header: bar + items: + description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + + If multiple entries specify equivalent header names, the first entry with + an equivalent name MUST be considered for a match. Subsequent entries + with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + description: Value is the value of HTTP Header to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + type: object + requestMirror: + description: |- + RequestMirror defines a schema for a filter that mirrors requests. + Requests are sent to the specified destination, but responses from + that destination are ignored. + + + This filter can be used multiple times within the same rule. Note that + not all implementations will be able to support mirroring to multiple + backends. + + + Support: Extended + + + + properties: + backendRef: + description: |- + BackendRef references a resource where mirrored requests are sent. + + + Mirrored requests must be sent only to a single destination endpoint + within this BackendRef, irrespective of how many endpoints are present + within this BackendRef. + + + If the referent cannot be found, this BackendRef is invalid and must be + dropped from the Gateway. The controller must ensure the "ResolvedRefs" + condition on the Route status is set to `status: False` and not configure + this backend in the underlying implementation. + + + If there is a cross-namespace reference to an *existing* object + that is not allowed by a ReferenceGrant, the controller must ensure the + "ResolvedRefs" condition on the Route is set to `status: False`, + with the "RefNotPermitted" reason and not configure this backend in the + underlying implementation. + + + In either error case, the Message of the `ResolvedRefs` Condition + should be used to provide more detail about the problem. + + + Support: Extended for Kubernetes Service + + + Support: Implementation-specific for any other resource + properties: + group: + default: "" + description: |- + Group is the group of the referent. For example, "gateway.networking.k8s.io". + When unspecified or empty string, core API group is inferred. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + default: Service + description: |- + Kind is the Kubernetes resource kind of the referent. For example + "Service". + + + Defaults to "Service" when not specified. + + + ExternalName services can refer to CNAME DNS records that may live + outside of the cluster and as such are difficult to reason about in + terms of conformance. They also may not be safe to forward to (see + CVE-2021-25740 for more information). Implementations SHOULD NOT + support ExternalName Services. + + + Support: Core (Services with a type other than ExternalName) + + + Support: Implementation-specific (Services with type ExternalName) + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: Name is the name of the referent. + maxLength: 253 + minLength: 1 + type: string + namespace: + description: |- + Namespace is the namespace of the backend. When unspecified, the local + namespace is inferred. + + + Note that when a namespace different than the local namespace is specified, + a ReferenceGrant object is required in the referent namespace to allow that + namespace's owner to accept the reference. See the ReferenceGrant + documentation for details. + + + Support: Core + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + port: + description: |- + Port specifies the destination port number to use for this resource. + Port is required when the referent is a Kubernetes Service. In this + case, the port number is the service port number, not the target port. + For other resources, destination port might be derived from the referent + resource or this field. + format: int32 + maximum: 65535 + minimum: 1 + type: integer + required: + - name + type: object + fraction: + description: |- + Fraction represents the fraction of requests that should be + mirrored to BackendRef. + + + Only one of Fraction or Percent may be specified. If neither field + is specified, 100% of requests will be mirrored. + + + + properties: + denominator: + default: 100 + format: int32 + minimum: 1 + type: integer + numerator: + format: int32 + minimum: 0 + type: integer + required: + - numerator + type: object + percent: + description: |- + Percent represents the percentage of requests that should be + mirrored to BackendRef. Its minimum value is 0 (indicating 0% of + requests) and its maximum value is 100 (indicating 100% of requests). + + + Only one of Fraction or Percent may be specified. If neither field + is specified, 100% of requests will be mirrored. + + + + format: int32 + maximum: 100 + minimum: 0 + type: integer + required: + - backendRef + type: object + requestRedirect: + description: |- + RequestRedirect defines a schema for a filter that responds to the + request with an HTTP redirection. + + + Support: Core + properties: + hostname: + description: |- + Hostname is the hostname to be used in the value of the `Location` + header in the response. + When empty, the hostname in the `Host` header of the request is used. + + + Support: Core + maxLength: 253 minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ type: string - value: - description: Value is the value of HTTP Header to be matched. - maxLength: 4096 + path: + description: |- + Path defines parameters used to modify the path of the incoming request. + The modified path is then used to construct the `Location` header. When + empty, the request path is used as-is. + + + Support: Extended + properties: + replaceFullPath: + description: |- + ReplaceFullPath specifies the value with which to replace the full path + of a request during a rewrite or redirect. + maxLength: 1024 + type: string + replacePrefixMatch: + description: |- + ReplacePrefixMatch specifies the value with which to replace the prefix + match of a request during a rewrite or redirect. For example, a request + to "/foo/bar" with a prefix match of "/foo" and a ReplacePrefixMatch + of "/xyz" would be modified to "/xyz/bar". + + + Note that this matches the behavior of the PathPrefix match type. This + matches full path elements. A path element refers to the list of labels + in the path split by the `/` separator. When specified, a trailing `/` is + ignored. For example, the paths `/abc`, `/abc/`, and `/abc/def` would all + match the prefix `/abc`, but the path `/abcd` would not. + + + ReplacePrefixMatch is only compatible with a `PathPrefix` HTTPRouteMatch. + Using any other HTTPRouteMatch type on the same HTTPRouteRule will result in + the implementation setting the Accepted Condition for the Route to `status: False`. + + + Request Path | Prefix Match | Replace Prefix | Modified Path + -------------|--------------|----------------|---------- + /foo/bar | /foo | /xyz | /xyz/bar + /foo/bar | /foo | /xyz/ | /xyz/bar + /foo/bar | /foo/ | /xyz | /xyz/bar + /foo/bar | /foo/ | /xyz/ | /xyz/bar + /foo | /foo | /xyz | /xyz + /foo/ | /foo | /xyz | /xyz/ + /foo/bar | /foo | | /bar + /foo/ | /foo | | / + /foo | /foo | | / + /foo/ | /foo | / | / + /foo | /foo | / | / + maxLength: 1024 + type: string + type: + description: |- + Type defines the type of path modifier. Additional types may be + added in a future release of the API. + + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + enum: + - ReplaceFullPath + - ReplacePrefixMatch + type: string + required: + - type + type: object + port: + description: |- + Port is the port to be used in the value of the `Location` + header in the response. + + + If no port is specified, the redirect port MUST be derived using the + following rules: + + + * If redirect scheme is not-empty, the redirect port MUST be the well-known + port associated with the redirect scheme. Specifically "http" to port 80 + and "https" to port 443. If the redirect scheme does not have a + well-known port, the listener port of the Gateway SHOULD be used. + * If redirect scheme is empty, the redirect port MUST be the Gateway + Listener port. + + + Implementations SHOULD NOT add the port number in the 'Location' + header in the following cases: + + + * A Location header that will use HTTP (whether that is determined via + the Listener protocol or the Scheme field) _and_ use port 80. + * A Location header that will use HTTPS (whether that is determined via + the Listener protocol or the Scheme field) _and_ use port 443. + + + Support: Extended + format: int32 + maximum: 65535 + minimum: 1 + type: integer + scheme: + description: |- + Scheme is the scheme to be used in the value of the `Location` header in + the response. When empty, the scheme of the request is used. + + + Scheme redirects can affect the port of the redirect, for more information, + refer to the documentation for the port field of this filter. + + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + + + Support: Extended + enum: + - http + - https + type: string + statusCode: + default: 302 + description: |- + StatusCode is the HTTP status code to be used in response. + + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + + + Support: Core + enum: + - 301 + - 302 + type: integer + type: object + responseHeaderModifier: + description: |- + ResponseHeaderModifier defines a schema for a filter that modifies response + headers. + + + Support: Extended + properties: + add: + description: |- + Add adds the given header(s) (name, value) to the request + before the action. It appends to any existing values associated + with the header name. + + + Input: + GET /foo HTTP/1.1 + my-header: foo + + + Config: + add: + - name: "my-header" + value: "bar,baz" + + + Output: + GET /foo HTTP/1.1 + my-header: foo,bar,baz + items: + description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + + If multiple entries specify equivalent header names, the first entry with + an equivalent name MUST be considered for a match. Subsequent entries + with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + description: Value is the value of HTTP Header to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + remove: + description: |- + Remove the given header(s) from the HTTP request before the action. The + value of Remove is a list of HTTP header names. Note that the header + names are case-insensitive (see + https://datatracker.ietf.org/doc/html/rfc2616#section-4.2). + + + Input: + GET /foo HTTP/1.1 + my-header1: foo + my-header2: bar + my-header3: baz + + + Config: + remove: ["my-header1", "my-header3"] + + + Output: + GET /foo HTTP/1.1 + my-header2: bar + items: + type: string + maxItems: 16 + type: array + x-kubernetes-list-type: set + set: + description: |- + Set overwrites the request with the given header (name, value) + before the action. + + + Input: + GET /foo HTTP/1.1 + my-header: foo + + + Config: + set: + - name: "my-header" + value: "bar" + + + Output: + GET /foo HTTP/1.1 + my-header: bar + items: + description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + + If multiple entries specify equivalent header names, the first entry with + an equivalent name MUST be considered for a match. Subsequent entries + with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + description: Value is the value of HTTP Header to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + type: object + type: + description: |- + Type identifies the type of filter to apply. As with other API fields, + types are classified into three conformance levels: + + + - Core: Filter types and their corresponding configuration defined by + "Support: Core" in this package, e.g. "RequestHeaderModifier". All + implementations must support core filters. + + + - Extended: Filter types and their corresponding configuration defined by + "Support: Extended" in this package, e.g. "RequestMirror". Implementers + are encouraged to support extended filters. + + + - Implementation-specific: Filters that are defined and supported by + specific vendors. + In the future, filters showing convergence in behavior across multiple + implementations will be considered for inclusion in extended or core + conformance levels. Filter-specific configuration for such filters + is specified using the ExtensionRef field. `Type` should be set to + "ExtensionRef" for custom filters. + + + Implementers are encouraged to define custom implementation types to + extend the core API with implementation-specific behavior. + + + If a reference to a custom filter type cannot be resolved, the filter + MUST NOT be skipped. Instead, requests that would have been processed by + that filter MUST receive a HTTP error response. + + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + enum: + - RequestHeaderModifier + - ResponseHeaderModifier + - RequestMirror + - RequestRedirect + - URLRewrite + - ExtensionRef + type: string + urlRewrite: + description: |- + URLRewrite defines a schema for a filter that modifies a request during forwarding. + + + Support: Extended + properties: + hostname: + description: |- + Hostname is the value to be used to replace the Host header value during + forwarding. + + + Support: Extended + maxLength: 253 minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ type: string - required: - - name - - value + path: + description: |- + Path defines a path rewrite. + + + Support: Extended + properties: + replaceFullPath: + description: |- + ReplaceFullPath specifies the value with which to replace the full path + of a request during a rewrite or redirect. + maxLength: 1024 + type: string + replacePrefixMatch: + description: |- + ReplacePrefixMatch specifies the value with which to replace the prefix + match of a request during a rewrite or redirect. For example, a request + to "/foo/bar" with a prefix match of "/foo" and a ReplacePrefixMatch + of "/xyz" would be modified to "/xyz/bar". + + + Note that this matches the behavior of the PathPrefix match type. This + matches full path elements. A path element refers to the list of labels + in the path split by the `/` separator. When specified, a trailing `/` is + ignored. For example, the paths `/abc`, `/abc/`, and `/abc/def` would all + match the prefix `/abc`, but the path `/abcd` would not. + + + ReplacePrefixMatch is only compatible with a `PathPrefix` HTTPRouteMatch. + Using any other HTTPRouteMatch type on the same HTTPRouteRule will result in + the implementation setting the Accepted Condition for the Route to `status: False`. + + + Request Path | Prefix Match | Replace Prefix | Modified Path + -------------|--------------|----------------|---------- + /foo/bar | /foo | /xyz | /xyz/bar + /foo/bar | /foo | /xyz/ | /xyz/bar + /foo/bar | /foo/ | /xyz | /xyz/bar + /foo/bar | /foo/ | /xyz/ | /xyz/bar + /foo | /foo | /xyz | /xyz + /foo/ | /foo | /xyz | /xyz/ + /foo/bar | /foo | | /bar + /foo/ | /foo | | / + /foo | /foo | | / + /foo/ | /foo | / | / + /foo | /foo | / | / + maxLength: 1024 + type: string + type: + description: |- + Type defines the type of path modifier. Additional types may be + added in a future release of the API. + + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + enum: + - ReplaceFullPath + - ReplacePrefixMatch + type: string + required: + - type + type: object type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - type: object - type: - description: |- - Type identifies the type of filter to apply. As with other API fields, - types are classified into three conformance levels: - - - - Core: Filter types and their corresponding configuration defined by - "Support: Core" in this package, e.g. "RequestHeaderModifier". All - implementations must support core filters. - - - - Extended: Filter types and their corresponding configuration defined by - "Support: Extended" in this package, e.g. "RequestMirror". Implementers - are encouraged to support extended filters. - - - - Implementation-specific: Filters that are defined and supported by - specific vendors. - In the future, filters showing convergence in behavior across multiple - implementations will be considered for inclusion in extended or core - conformance levels. Filter-specific configuration for such filters - is specified using the ExtensionRef field. `Type` should be set to - "ExtensionRef" for custom filters. - - - Implementers are encouraged to define custom implementation types to - extend the core API with implementation-specific behavior. - - - If a reference to a custom filter type cannot be resolved, the filter - MUST NOT be skipped. Instead, requests that would have been processed by - that filter MUST receive a HTTP error response. - - - Note that values may be added to this enum, implementations - must ensure that unknown values will not cause a crash. - - - Unknown values here must result in the implementation setting the - Accepted Condition for the Route to `status: False`, with a - Reason of `UnsupportedValue`. - enum: - - RequestHeaderModifier - - ResponseHeaderModifier - - RequestMirror - - RequestRedirect - - URLRewrite - - ExtensionRef - type: string - urlRewrite: + required: + - type + type: object + maxItems: 16 + type: array + matches: description: |- - URLRewrite defines a schema for a filter that modifies a request during forwarding. - - - Support: Extended - properties: - hostname: - description: |- - Hostname is the value to be used to replace the Host header value during - forwarding. - - - Support: Extended - maxLength: 253 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - path: - description: |- - Path defines a path rewrite. - - - Support: Extended - properties: - replaceFullPath: - description: |- - ReplaceFullPath specifies the value with which to replace the full path - of a request during a rewrite or redirect. - maxLength: 1024 - type: string - replacePrefixMatch: + Matches define conditions used for matching the rule against incoming + HTTP requests. Each match is independent, i.e. this rule will be matched + if **any** one of the matches is satisfied. + + + For example, take the following matches configuration: + + + ``` + matches: + - path: + value: "/foo" + headers: + - name: "version" + value: "v2" + - path: + value: "/v2/foo" + ``` + + + For a request to match against this rule, a request must satisfy + EITHER of the two conditions: + + + - path prefixed with `/foo` AND contains the header `version: v2` + - path prefix of `/v2/foo` + + + See the documentation for HTTPRouteMatch on how to specify multiple + match conditions that should be ANDed together. + + + If no matches are specified, the default is a prefix + path match on "/", which has the effect of matching every + HTTP request. + + + Proxy or Load Balancer routing configuration generated from HTTPRoutes + MUST prioritize matches based on the following criteria, continuing on + ties. Across all rules specified on applicable Routes, precedence must be + given to the match having: + + + * "Exact" path match. + * "Prefix" path match with largest number of characters. + * Method match. + * Largest number of header matches. + * Largest number of query param matches. + + + Note: The precedence of RegularExpression path matches are implementation-specific. + + + If ties still exist across multiple Routes, matching precedence MUST be + determined in order of the following criteria, continuing on ties: + + + * The oldest Route based on creation timestamp. + * The Route appearing first in alphabetical order by + "{namespace}/{name}". + + + If ties still exist within an HTTPRoute, matching precedence MUST be granted + to the FIRST matching rule (in list order) with a match meeting the above + criteria. + + + When no rules matching a request have been successfully attached to the + parent a request is coming from, a HTTP 404 status code MUST be returned. + items: + properties: + headers: + description: |- + Headers specifies HTTP request header matchers. Multiple match values are + ANDed together, meaning, a request must match all the specified headers + to select the route. + items: description: |- - ReplacePrefixMatch specifies the value with which to replace the prefix - match of a request during a rewrite or redirect. For example, a request - to "/foo/bar" with a prefix match of "/foo" and a ReplacePrefixMatch - of "/xyz" would be modified to "/xyz/bar". - - - Note that this matches the behavior of the PathPrefix match type. This - matches full path elements. A path element refers to the list of labels - in the path split by the `/` separator. When specified, a trailing `/` is - ignored. For example, the paths `/abc`, `/abc/`, and `/abc/def` would all - match the prefix `/abc`, but the path `/abcd` would not. - - - ReplacePrefixMatch is only compatible with a `PathPrefix` HTTPRouteMatch. - Using any other HTTPRouteMatch type on the same HTTPRouteRule will result in - the implementation setting the Accepted Condition for the Route to `status: False`. - - - Request Path | Prefix Match | Replace Prefix | Modified Path - -------------|--------------|----------------|---------- - /foo/bar | /foo | /xyz | /xyz/bar - /foo/bar | /foo | /xyz/ | /xyz/bar - /foo/bar | /foo/ | /xyz | /xyz/bar - /foo/bar | /foo/ | /xyz/ | /xyz/bar - /foo | /foo | /xyz | /xyz - /foo/ | /foo | /xyz | /xyz/ - /foo/bar | /foo | | /bar - /foo/ | /foo | | / - /foo | /foo | | / - /foo/ | /foo | / | / - /foo | /foo | / | / - maxLength: 1024 - type: string - type: + HTTPHeaderMatch describes how to select a HTTP route by matching HTTP request + headers. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + + If multiple entries specify equivalent header names, only the first + entry with an equivalent name MUST be considered for a match. Subsequent + entries with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + + + When a header is repeated in an HTTP request, it is + implementation-specific behavior as to how this is represented. + Generally, proxies should follow the guidance from the RFC: + https://www.rfc-editor.org/rfc/rfc7230.html#section-3.2.2 regarding + processing a repeated header, with special handling for "Set-Cookie". + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + type: + default: Exact + description: |- + Type specifies how to match against the value of the header. + + + Support: Core (Exact) + + + Support: Implementation-specific (RegularExpression) + + + Since RegularExpression HeaderMatchType has implementation-specific + conformance, implementations can support POSIX, PCRE or any other dialects + of regular expressions. Please read the implementation's documentation to + determine the supported dialect. + enum: + - Exact + - RegularExpression + type: string + value: + description: Value is the value of HTTP Header to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + path: + description: Path specifies a HTTP request path matcher. + properties: + type: + default: PathPrefix + description: |- + Type specifies how to match against the path Value. + + + Support: Core (Exact, PathPrefix) + + + Support: Implementation-specific (RegularExpression) + enum: + - Exact + - PathPrefix + - RegularExpression + type: string + value: + default: / + description: Value of the HTTP path to match against. + maxLength: 1024 + type: string + type: object + queryParams: + description: |- + QueryParams specifies HTTP query parameter matchers. Multiple match + values are ANDed together, meaning, a request must match all the + specified query parameters to select the route. + + + Support: Extended + items: description: |- - Type defines the type of path modifier. Additional types may be - added in a future release of the API. - - - Note that values may be added to this enum, implementations - must ensure that unknown values will not cause a crash. - - - Unknown values here must result in the implementation setting the - Accepted Condition for the Route to `status: False`, with a - Reason of `UnsupportedValue`. - enum: - - ReplaceFullPath - - ReplacePrefixMatch - type: string - required: - - type - type: object - type: object - required: - - type - type: object - maxItems: 16 - type: array - matches: - description: |- - Matches define conditions used for matching the rule against incoming - HTTP requests. Each match is independent, i.e. this rule will be matched - if **any** one of the matches is satisfied. - - - For example, take the following matches configuration: - - - ``` - matches: - - path: - value: "/foo" - headers: - - name: "version" - value: "v2" - - path: - value: "/v2/foo" - ``` - - - For a request to match against this rule, a request must satisfy - EITHER of the two conditions: - - - - path prefixed with `/foo` AND contains the header `version: v2` - - path prefix of `/v2/foo` - - - See the documentation for HTTPRouteMatch on how to specify multiple - match conditions that should be ANDed together. - - - If no matches are specified, the default is a prefix - path match on "/", which has the effect of matching every - HTTP request. - - - Proxy or Load Balancer routing configuration generated from HTTPRoutes - MUST prioritize matches based on the following criteria, continuing on - ties. Across all rules specified on applicable Routes, precedence must be - given to the match having: - - - * "Exact" path match. - * "Prefix" path match with largest number of characters. - * Method match. - * Largest number of header matches. - * Largest number of query param matches. - - - Note: The precedence of RegularExpression path matches are implementation-specific. - - - If ties still exist across multiple Routes, matching precedence MUST be - determined in order of the following criteria, continuing on ties: - - - * The oldest Route based on creation timestamp. - * The Route appearing first in alphabetical order by - "{namespace}/{name}". - - - If ties still exist within an HTTPRoute, matching precedence MUST be granted - to the FIRST matching rule (in list order) with a match meeting the above - criteria. - - - When no rules matching a request have been successfully attached to the - parent a request is coming from, a HTTP 404 status code MUST be returned. - items: + HTTPQueryParamMatch describes how to select a HTTP route by matching HTTP + query parameters. + properties: + name: + description: |- + Name is the name of the HTTP query param to be matched. This must be an + exact string match. (See + https://tools.ietf.org/html/rfc7230#section-2.7.3). + + + If multiple entries specify equivalent query param names, only the first + entry with an equivalent name MUST be considered for a match. Subsequent + entries with an equivalent query param name MUST be ignored. + + + If a query param is repeated in an HTTP request, the behavior is + purposely left undefined, since different data planes have different + capabilities. However, it is *recommended* that implementations should + match against the first value of the param if the data plane supports it, + as this behavior is expected in other load balancing contexts outside of + the Gateway API. + + + Users SHOULD NOT route traffic based on repeated query params to guard + themselves against potential differences in the implementations. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + type: + default: Exact + description: |- + Type specifies how to match against the value of the query parameter. + + + Support: Extended (Exact) + + + Support: Implementation-specific (RegularExpression) + + + Since RegularExpression QueryParamMatchType has Implementation-specific + conformance, implementations can support POSIX, PCRE or any other + dialects of regular expressions. Please read the implementation's + documentation to determine the supported dialect. + enum: + - Exact + - RegularExpression + type: string + value: + description: Value is the value of HTTP query param to be matched. + maxLength: 1024 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + type: object + maxItems: 8 + type: array + type: object + weight: + description: Weight indicate how many percentage of traffic the canary pods should receive + format: int32 + maximum: 100 + minimum: 0 + type: integer + type: object + type: object + required: + - targets + type: object + type: array + toleration: + description: Toleration is the toleration policy of the canary strategy + properties: + initialDelaySeconds: + description: Number of seconds after the toleration check has started before the task are initiated. + format: int32 + type: integer + taskFailureThreshold: + anyOf: + - type: integer + - type: string + description: |- + FailureThreshold indicates how many failed pods can be tolerated before marking the rollout task as success + If not set, the default value is 0, which means no failed pods can be tolerated + This is a task level threshold. + x-kubernetes-int-or-string: true + workloadTotalFailureThreshold: + anyOf: + - type: integer + - type: string + description: |- + WorkloadFailureThreshold indicates how many failed pods can be tolerated in all upgraded pods of one workload. + The default value is 0, which means no failed pods can be tolerated. + This is a workload level threshold. + x-kubernetes-int-or-string: true + type: object + type: object + canary: + description: Canary defines the canary strategy + properties: + podTemplateMetadataPatch: + description: PodTemplateMetadataPatch defines a patch for workload podTemplate metadata. + properties: + annotations: + additionalProperties: + type: string + description: Annotations are additional metadata that can be included. + type: object + labels: + additionalProperties: + type: string + description: Labels are additional metadata that can be included. + type: object + type: object + properties: + additionalProperties: + type: string + description: Properties contains additional information for step + type: object + targets: + description: desired target replicas + items: + properties: + cluster: + description: Cluster indicates the name of cluster + type: string + name: + description: Name is the resource name + type: string + replicaSlidingWindow: + anyOf: + - type: integer + - type: string + description: |- + ReplicaSlidingWindow used to control the number of pods that are allowed to be upgraded in + a sliding window for progressive rollout smoothly. + x-kubernetes-int-or-string: true + replicas: + anyOf: + - type: integer + - type: string + description: Replicas is the replicas of the rollout task, which represents the number of pods to be upgraded + x-kubernetes-int-or-string: true + required: + - name + - replicas + type: object + type: array + traffic: + description: traffic strategy + properties: + http: + properties: + filters: + description: |- + Filters define the filters that are applied to requests that match + this rule. + + + The effects of ordering of multiple behaviors are currently unspecified. + This can change in the future based on feedback during the alpha stage. + + + Conformance-levels at this level are defined based on the type of filter: + + + - ALL core filters MUST be supported by all implementations. + - Implementers are encouraged to support extended filters. + - Implementation-specific custom filters have no API guarantees across + implementations. + + + Specifying the same filter multiple times is not supported unless explicitly + indicated in the filter. + + + All filters are expected to be compatible with each other except for the + URLRewrite and RequestRedirect filters, which may not be combined. If an + implementation can not support other combinations of filters, they must clearly + document that limitation. In cases where incompatible or unsupported + filters are specified and cause the `Accepted` condition to be set to status + `False`, implementations may use the `IncompatibleFilters` reason to specify + this configuration error. + + + Support: Core + items: + description: |- + HTTPRouteFilter defines processing steps that must be completed during the + request or response lifecycle. HTTPRouteFilters are meant as an extension + point to express processing that may be done in Gateway implementations. Some + examples include request or response modification, implementing + authentication strategies, rate-limiting, and traffic shaping. API + guarantee/conformance is defined based on the type of the filter. + properties: + extensionRef: + description: |- + ExtensionRef is an optional, implementation-specific extension to the + "filter" behavior. For example, resource "myroutefilter" in group + "networking.example.net"). ExtensionRef MUST NOT be used for core and + extended filters. + + + This filter can be used multiple times within the same rule. + + + Support: Implementation-specific properties: - headers: + group: description: |- - Headers specifies HTTP request header matchers. Multiple match values are - ANDed together, meaning, a request must match all the specified headers - to select the route. + Group is the group of the referent. For example, "gateway.networking.k8s.io". + When unspecified or empty string, core API group is inferred. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + description: Kind is kind of the referent. For example "HTTPRoute" or "Service". + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: Name is the name of the referent. + maxLength: 253 + minLength: 1 + type: string + required: + - group + - kind + - name + type: object + requestHeaderModifier: + description: |- + RequestHeaderModifier defines a schema for a filter that modifies request + headers. + + + Support: Core + properties: + add: + description: |- + Add adds the given header(s) (name, value) to the request + before the action. It appends to any existing values associated + with the header name. + + + Input: + GET /foo HTTP/1.1 + my-header: foo + + + Config: + add: + - name: "my-header" + value: "bar,baz" + + + Output: + GET /foo HTTP/1.1 + my-header: foo,bar,baz items: - description: |- - HTTPHeaderMatch describes how to select a HTTP route by matching HTTP request - headers. + description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. properties: name: description: |- Name is the name of the HTTP Header to be matched. Name matching MUST be case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). - - - If multiple entries specify equivalent header names, only the first - entry with an equivalent name MUST be considered for a match. Subsequent - entries with an equivalent header name MUST be ignored. Due to the + + + If multiple entries specify equivalent header names, the first entry with + an equivalent name MUST be considered for a match. Subsequent entries + with an equivalent header name MUST be ignored. Due to the case-insensitivity of header names, "foo" and "Foo" are considered equivalent. - - - When a header is repeated in an HTTP request, it is - implementation-specific behavior as to how this is represented. - Generally, proxies should follow the guidance from the RFC: - https://www.rfc-editor.org/rfc/rfc7230.html#section-3.2.2 regarding - processing a repeated header, with special handling for "Set-Cookie". maxLength: 256 minLength: 1 pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ type: string - type: - default: Exact - description: |- - Type specifies how to match against the value of the header. - - - Support: Core (Exact) - - - Support: Implementation-specific (RegularExpression) - - - Since RegularExpression HeaderMatchType has implementation-specific - conformance, implementations can support POSIX, PCRE or any other dialects - of regular expressions. Please read the implementation's documentation to - determine the supported dialect. - enum: - - Exact - - RegularExpression - type: string value: description: Value is the value of HTTP Header to be matched. maxLength: 4096 minLength: 1 type: string required: - - name - - value + - name + - value type: object maxItems: 16 type: array x-kubernetes-list-map-keys: - - name + - name x-kubernetes-list-type: map - path: - description: Path specifies a HTTP request path matcher. - properties: - type: - default: PathPrefix - description: |- - Type specifies how to match against the path Value. - - - Support: Core (Exact, PathPrefix) - - - Support: Implementation-specific (RegularExpression) - enum: - - Exact - - PathPrefix - - RegularExpression - type: string - value: - default: / - description: Value of the HTTP path to match against. - maxLength: 1024 - type: string - type: object - queryParams: + remove: description: |- - QueryParams specifies HTTP query parameter matchers. Multiple match - values are ANDed together, meaning, a request must match all the - specified query parameters to select the route. - - - Support: Extended + Remove the given header(s) from the HTTP request before the action. The + value of Remove is a list of HTTP header names. Note that the header + names are case-insensitive (see + https://datatracker.ietf.org/doc/html/rfc2616#section-4.2). + + + Input: + GET /foo HTTP/1.1 + my-header1: foo + my-header2: bar + my-header3: baz + + + Config: + remove: ["my-header1", "my-header3"] + + + Output: + GET /foo HTTP/1.1 + my-header2: bar items: - description: |- - HTTPQueryParamMatch describes how to select a HTTP route by matching HTTP - query parameters. + type: string + maxItems: 16 + type: array + x-kubernetes-list-type: set + set: + description: |- + Set overwrites the request with the given header (name, value) + before the action. + + + Input: + GET /foo HTTP/1.1 + my-header: foo + + + Config: + set: + - name: "my-header" + value: "bar" + + + Output: + GET /foo HTTP/1.1 + my-header: bar + items: + description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. properties: name: description: |- - Name is the name of the HTTP query param to be matched. This must be an - exact string match. (See - https://tools.ietf.org/html/rfc7230#section-2.7.3). - - - If multiple entries specify equivalent query param names, only the first - entry with an equivalent name MUST be considered for a match. Subsequent - entries with an equivalent query param name MUST be ignored. - - - If a query param is repeated in an HTTP request, the behavior is - purposely left undefined, since different data planes have different - capabilities. However, it is *recommended* that implementations should - match against the first value of the param if the data plane supports it, - as this behavior is expected in other load balancing contexts outside of - the Gateway API. - - - Users SHOULD NOT route traffic based on repeated query params to guard - themselves against potential differences in the implementations. + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + + If multiple entries specify equivalent header names, the first entry with + an equivalent name MUST be considered for a match. Subsequent entries + with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. maxLength: 256 minLength: 1 pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ type: string - type: - default: Exact - description: |- - Type specifies how to match against the value of the query parameter. - - - Support: Extended (Exact) - - - Support: Implementation-specific (RegularExpression) - - - Since RegularExpression QueryParamMatchType has Implementation-specific - conformance, implementations can support POSIX, PCRE or any other - dialects of regular expressions. Please read the implementation's - documentation to determine the supported dialect. - enum: - - Exact - - RegularExpression - type: string value: - description: Value is the value of HTTP query param to be matched. - maxLength: 1024 + description: Value is the value of HTTP Header to be matched. + maxLength: 4096 minLength: 1 type: string required: - - name - - value + - name + - value type: object maxItems: 16 type: array x-kubernetes-list-map-keys: - - name + - name x-kubernetes-list-type: map type: object - maxItems: 8 - type: array - stableTraffic: - description: StableTraffic indicate the base traffic rule - properties: - filters: - description: |- - Filters define the filters that are applied to requests that match - this rule. - - - The effects of ordering of multiple behaviors are currently unspecified. - This can change in the future based on feedback during the alpha stage. - - - Conformance-levels at this level are defined based on the type of filter: - - - - ALL core filters MUST be supported by all implementations. - - Implementers are encouraged to support extended filters. - - Implementation-specific custom filters have no API guarantees across - implementations. - - - Specifying the same filter multiple times is not supported unless explicitly - indicated in the filter. - - - All filters are expected to be compatible with each other except for the - URLRewrite and RequestRedirect filters, which may not be combined. If an - implementation can not support other combinations of filters, they must clearly - document that limitation. In cases where incompatible or unsupported - filters are specified and cause the `Accepted` condition to be set to status - `False`, implementations may use the `IncompatibleFilters` reason to specify - this configuration error. - - - Support: Core - items: + requestMirror: + description: |- + RequestMirror defines a schema for a filter that mirrors requests. + Requests are sent to the specified destination, but responses from + that destination are ignored. + + + This filter can be used multiple times within the same rule. Note that + not all implementations will be able to support mirroring to multiple + backends. + + + Support: Extended + + + + properties: + backendRef: description: |- - HTTPRouteFilter defines processing steps that must be completed during the - request or response lifecycle. HTTPRouteFilters are meant as an extension - point to express processing that may be done in Gateway implementations. Some - examples include request or response modification, implementing - authentication strategies, rate-limiting, and traffic shaping. API - guarantee/conformance is defined based on the type of the filter. + BackendRef references a resource where mirrored requests are sent. + + + Mirrored requests must be sent only to a single destination endpoint + within this BackendRef, irrespective of how many endpoints are present + within this BackendRef. + + + If the referent cannot be found, this BackendRef is invalid and must be + dropped from the Gateway. The controller must ensure the "ResolvedRefs" + condition on the Route status is set to `status: False` and not configure + this backend in the underlying implementation. + + + If there is a cross-namespace reference to an *existing* object + that is not allowed by a ReferenceGrant, the controller must ensure the + "ResolvedRefs" condition on the Route is set to `status: False`, + with the "RefNotPermitted" reason and not configure this backend in the + underlying implementation. + + + In either error case, the Message of the `ResolvedRefs` Condition + should be used to provide more detail about the problem. + + + Support: Extended for Kubernetes Service + + + Support: Implementation-specific for any other resource properties: - extensionRef: + group: + default: "" description: |- - ExtensionRef is an optional, implementation-specific extension to the - "filter" behavior. For example, resource "myroutefilter" in group - "networking.example.net"). ExtensionRef MUST NOT be used for core and - extended filters. - - - This filter can be used multiple times within the same rule. - - - Support: Implementation-specific - properties: - group: - description: |- - Group is the group of the referent. For example, "gateway.networking.k8s.io". - When unspecified or empty string, core API group is inferred. - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - description: Kind is kind of the referent. For example "HTTPRoute" or "Service". - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - type: string - name: - description: Name is the name of the referent. - maxLength: 253 - minLength: 1 - type: string - required: - - group - - kind - - name - type: object - requestHeaderModifier: + Group is the group of the referent. For example, "gateway.networking.k8s.io". + When unspecified or empty string, core API group is inferred. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + default: Service description: |- - RequestHeaderModifier defines a schema for a filter that modifies request - headers. - - - Support: Core - properties: - add: - description: |- - Add adds the given header(s) (name, value) to the request - before the action. It appends to any existing values associated - with the header name. - - - Input: - GET /foo HTTP/1.1 - my-header: foo - - - Config: - add: - - name: "my-header" - value: "bar,baz" - - - Output: - GET /foo HTTP/1.1 - my-header: foo,bar,baz - items: - description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. - properties: - name: - description: |- - Name is the name of the HTTP Header to be matched. Name matching MUST be - case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). - - - If multiple entries specify equivalent header names, the first entry with - an equivalent name MUST be considered for a match. Subsequent entries - with an equivalent header name MUST be ignored. Due to the - case-insensitivity of header names, "foo" and "Foo" are considered - equivalent. - maxLength: 256 - minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ - type: string - value: - description: Value is the value of HTTP Header to be matched. - maxLength: 4096 - minLength: 1 - type: string - required: - - name - - value - type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - remove: - description: |- - Remove the given header(s) from the HTTP request before the action. The - value of Remove is a list of HTTP header names. Note that the header - names are case-insensitive (see - https://datatracker.ietf.org/doc/html/rfc2616#section-4.2). - - - Input: - GET /foo HTTP/1.1 - my-header1: foo - my-header2: bar - my-header3: baz - - - Config: - remove: ["my-header1", "my-header3"] - - - Output: - GET /foo HTTP/1.1 - my-header2: bar - items: - type: string - maxItems: 16 - type: array - x-kubernetes-list-type: set - set: - description: |- - Set overwrites the request with the given header (name, value) - before the action. - - - Input: - GET /foo HTTP/1.1 - my-header: foo - - - Config: - set: - - name: "my-header" - value: "bar" - - - Output: - GET /foo HTTP/1.1 - my-header: bar - items: - description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. - properties: - name: - description: |- - Name is the name of the HTTP Header to be matched. Name matching MUST be - case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). - - - If multiple entries specify equivalent header names, the first entry with - an equivalent name MUST be considered for a match. Subsequent entries - with an equivalent header name MUST be ignored. Due to the - case-insensitivity of header names, "foo" and "Foo" are considered - equivalent. - maxLength: 256 - minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ - type: string - value: - description: Value is the value of HTTP Header to be matched. - maxLength: 4096 - minLength: 1 - type: string - required: - - name - - value - type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - type: object - requestMirror: - description: |- - RequestMirror defines a schema for a filter that mirrors requests. - Requests are sent to the specified destination, but responses from - that destination are ignored. - - - This filter can be used multiple times within the same rule. Note that - not all implementations will be able to support mirroring to multiple - backends. - - - Support: Extended - - - - properties: - backendRef: - description: |- - BackendRef references a resource where mirrored requests are sent. - - - Mirrored requests must be sent only to a single destination endpoint - within this BackendRef, irrespective of how many endpoints are present - within this BackendRef. - - - If the referent cannot be found, this BackendRef is invalid and must be - dropped from the Gateway. The controller must ensure the "ResolvedRefs" - condition on the Route status is set to `status: False` and not configure - this backend in the underlying implementation. - - - If there is a cross-namespace reference to an *existing* object - that is not allowed by a ReferenceGrant, the controller must ensure the - "ResolvedRefs" condition on the Route is set to `status: False`, - with the "RefNotPermitted" reason and not configure this backend in the - underlying implementation. - - - In either error case, the Message of the `ResolvedRefs` Condition - should be used to provide more detail about the problem. - - - Support: Extended for Kubernetes Service - - - Support: Implementation-specific for any other resource - properties: - group: - default: "" - description: |- - Group is the group of the referent. For example, "gateway.networking.k8s.io". - When unspecified or empty string, core API group is inferred. - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - default: Service - description: |- - Kind is the Kubernetes resource kind of the referent. For example - "Service". - - - Defaults to "Service" when not specified. - - - ExternalName services can refer to CNAME DNS records that may live - outside of the cluster and as such are difficult to reason about in - terms of conformance. They also may not be safe to forward to (see - CVE-2021-25740 for more information). Implementations SHOULD NOT - support ExternalName Services. - - - Support: Core (Services with a type other than ExternalName) - - - Support: Implementation-specific (Services with type ExternalName) - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - type: string - name: - description: Name is the name of the referent. - maxLength: 253 - minLength: 1 - type: string - namespace: - description: |- - Namespace is the namespace of the backend. When unspecified, the local - namespace is inferred. - - - Note that when a namespace different than the local namespace is specified, - a ReferenceGrant object is required in the referent namespace to allow that - namespace's owner to accept the reference. See the ReferenceGrant - documentation for details. - - - Support: Core - maxLength: 63 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ - type: string - port: - description: |- - Port specifies the destination port number to use for this resource. - Port is required when the referent is a Kubernetes Service. In this - case, the port number is the service port number, not the target port. - For other resources, destination port might be derived from the referent - resource or this field. - format: int32 - maximum: 65535 - minimum: 1 - type: integer - required: - - name - type: object - fraction: - description: |- - Fraction represents the fraction of requests that should be - mirrored to BackendRef. - - - Only one of Fraction or Percent may be specified. If neither field - is specified, 100% of requests will be mirrored. - - - - properties: - denominator: - default: 100 - format: int32 - minimum: 1 - type: integer - numerator: - format: int32 - minimum: 0 - type: integer - required: - - numerator - type: object - percent: - description: |- - Percent represents the percentage of requests that should be - mirrored to BackendRef. Its minimum value is 0 (indicating 0% of - requests) and its maximum value is 100 (indicating 100% of requests). - - - Only one of Fraction or Percent may be specified. If neither field - is specified, 100% of requests will be mirrored. - - - - format: int32 - maximum: 100 - minimum: 0 - type: integer - required: - - backendRef - type: object - requestRedirect: + Kind is the Kubernetes resource kind of the referent. For example + "Service". + + + Defaults to "Service" when not specified. + + + ExternalName services can refer to CNAME DNS records that may live + outside of the cluster and as such are difficult to reason about in + terms of conformance. They also may not be safe to forward to (see + CVE-2021-25740 for more information). Implementations SHOULD NOT + support ExternalName Services. + + + Support: Core (Services with a type other than ExternalName) + + + Support: Implementation-specific (Services with type ExternalName) + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: Name is the name of the referent. + maxLength: 253 + minLength: 1 + type: string + namespace: description: |- - RequestRedirect defines a schema for a filter that responds to the - request with an HTTP redirection. - - + Namespace is the namespace of the backend. When unspecified, the local + namespace is inferred. + + + Note that when a namespace different than the local namespace is specified, + a ReferenceGrant object is required in the referent namespace to allow that + namespace's owner to accept the reference. See the ReferenceGrant + documentation for details. + + Support: Core - properties: - hostname: - description: |- - Hostname is the hostname to be used in the value of the `Location` - header in the response. - When empty, the hostname in the `Host` header of the request is used. - - - Support: Core - maxLength: 253 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - path: - description: |- - Path defines parameters used to modify the path of the incoming request. - The modified path is then used to construct the `Location` header. When - empty, the request path is used as-is. - - - Support: Extended - properties: - replaceFullPath: - description: |- - ReplaceFullPath specifies the value with which to replace the full path - of a request during a rewrite or redirect. - maxLength: 1024 - type: string - replacePrefixMatch: - description: |- - ReplacePrefixMatch specifies the value with which to replace the prefix - match of a request during a rewrite or redirect. For example, a request - to "/foo/bar" with a prefix match of "/foo" and a ReplacePrefixMatch - of "/xyz" would be modified to "/xyz/bar". - - - Note that this matches the behavior of the PathPrefix match type. This - matches full path elements. A path element refers to the list of labels - in the path split by the `/` separator. When specified, a trailing `/` is - ignored. For example, the paths `/abc`, `/abc/`, and `/abc/def` would all - match the prefix `/abc`, but the path `/abcd` would not. - - - ReplacePrefixMatch is only compatible with a `PathPrefix` HTTPRouteMatch. - Using any other HTTPRouteMatch type on the same HTTPRouteRule will result in - the implementation setting the Accepted Condition for the Route to `status: False`. - - - Request Path | Prefix Match | Replace Prefix | Modified Path - -------------|--------------|----------------|---------- - /foo/bar | /foo | /xyz | /xyz/bar - /foo/bar | /foo | /xyz/ | /xyz/bar - /foo/bar | /foo/ | /xyz | /xyz/bar - /foo/bar | /foo/ | /xyz/ | /xyz/bar - /foo | /foo | /xyz | /xyz - /foo/ | /foo | /xyz | /xyz/ - /foo/bar | /foo | | /bar - /foo/ | /foo | | / - /foo | /foo | | / - /foo/ | /foo | / | / - /foo | /foo | / | / - maxLength: 1024 - type: string - type: - description: |- - Type defines the type of path modifier. Additional types may be - added in a future release of the API. - - - Note that values may be added to this enum, implementations - must ensure that unknown values will not cause a crash. - - - Unknown values here must result in the implementation setting the - Accepted Condition for the Route to `status: False`, with a - Reason of `UnsupportedValue`. - enum: - - ReplaceFullPath - - ReplacePrefixMatch - type: string - required: - - type - type: object - port: - description: |- - Port is the port to be used in the value of the `Location` - header in the response. - - - If no port is specified, the redirect port MUST be derived using the - following rules: - - - * If redirect scheme is not-empty, the redirect port MUST be the well-known - port associated with the redirect scheme. Specifically "http" to port 80 - and "https" to port 443. If the redirect scheme does not have a - well-known port, the listener port of the Gateway SHOULD be used. - * If redirect scheme is empty, the redirect port MUST be the Gateway - Listener port. - - - Implementations SHOULD NOT add the port number in the 'Location' - header in the following cases: - - - * A Location header that will use HTTP (whether that is determined via - the Listener protocol or the Scheme field) _and_ use port 80. - * A Location header that will use HTTPS (whether that is determined via - the Listener protocol or the Scheme field) _and_ use port 443. - - - Support: Extended - format: int32 - maximum: 65535 - minimum: 1 - type: integer - scheme: - description: |- - Scheme is the scheme to be used in the value of the `Location` header in - the response. When empty, the scheme of the request is used. - - - Scheme redirects can affect the port of the redirect, for more information, - refer to the documentation for the port field of this filter. - - - Note that values may be added to this enum, implementations - must ensure that unknown values will not cause a crash. - - - Unknown values here must result in the implementation setting the - Accepted Condition for the Route to `status: False`, with a - Reason of `UnsupportedValue`. - - - Support: Extended - enum: - - http - - https - type: string - statusCode: - default: 302 - description: |- - StatusCode is the HTTP status code to be used in response. - - - Note that values may be added to this enum, implementations - must ensure that unknown values will not cause a crash. - - - Unknown values here must result in the implementation setting the - Accepted Condition for the Route to `status: False`, with a - Reason of `UnsupportedValue`. - - - Support: Core - enum: - - 301 - - 302 - type: integer - type: object - responseHeaderModifier: + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + port: description: |- - ResponseHeaderModifier defines a schema for a filter that modifies response - headers. - - - Support: Extended - properties: - add: - description: |- - Add adds the given header(s) (name, value) to the request - before the action. It appends to any existing values associated - with the header name. - - - Input: - GET /foo HTTP/1.1 - my-header: foo - - - Config: - add: - - name: "my-header" - value: "bar,baz" - - - Output: - GET /foo HTTP/1.1 - my-header: foo,bar,baz - items: - description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. - properties: - name: - description: |- - Name is the name of the HTTP Header to be matched. Name matching MUST be - case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). - - - If multiple entries specify equivalent header names, the first entry with - an equivalent name MUST be considered for a match. Subsequent entries - with an equivalent header name MUST be ignored. Due to the - case-insensitivity of header names, "foo" and "Foo" are considered - equivalent. - maxLength: 256 - minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ - type: string - value: - description: Value is the value of HTTP Header to be matched. - maxLength: 4096 - minLength: 1 - type: string - required: - - name - - value - type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - remove: - description: |- - Remove the given header(s) from the HTTP request before the action. The - value of Remove is a list of HTTP header names. Note that the header - names are case-insensitive (see - https://datatracker.ietf.org/doc/html/rfc2616#section-4.2). - - - Input: - GET /foo HTTP/1.1 - my-header1: foo - my-header2: bar - my-header3: baz - - - Config: - remove: ["my-header1", "my-header3"] - - - Output: - GET /foo HTTP/1.1 - my-header2: bar - items: - type: string - maxItems: 16 - type: array - x-kubernetes-list-type: set - set: - description: |- - Set overwrites the request with the given header (name, value) - before the action. - - - Input: - GET /foo HTTP/1.1 - my-header: foo - - - Config: - set: - - name: "my-header" - value: "bar" - - - Output: - GET /foo HTTP/1.1 - my-header: bar - items: - description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. - properties: - name: - description: |- - Name is the name of the HTTP Header to be matched. Name matching MUST be - case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). - - - If multiple entries specify equivalent header names, the first entry with - an equivalent name MUST be considered for a match. Subsequent entries - with an equivalent header name MUST be ignored. Due to the - case-insensitivity of header names, "foo" and "Foo" are considered - equivalent. - maxLength: 256 - minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ - type: string - value: - description: Value is the value of HTTP Header to be matched. - maxLength: 4096 - minLength: 1 - type: string - required: - - name - - value - type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - type: object + Port specifies the destination port number to use for this resource. + Port is required when the referent is a Kubernetes Service. In this + case, the port number is the service port number, not the target port. + For other resources, destination port might be derived from the referent + resource or this field. + format: int32 + maximum: 65535 + minimum: 1 + type: integer + required: + - name + type: object + fraction: + description: |- + Fraction represents the fraction of requests that should be + mirrored to BackendRef. + + + Only one of Fraction or Percent may be specified. If neither field + is specified, 100% of requests will be mirrored. + + + + properties: + denominator: + default: 100 + format: int32 + minimum: 1 + type: integer + numerator: + format: int32 + minimum: 0 + type: integer + required: + - numerator + type: object + percent: + description: |- + Percent represents the percentage of requests that should be + mirrored to BackendRef. Its minimum value is 0 (indicating 0% of + requests) and its maximum value is 100 (indicating 100% of requests). + + + Only one of Fraction or Percent may be specified. If neither field + is specified, 100% of requests will be mirrored. + + + + format: int32 + maximum: 100 + minimum: 0 + type: integer + required: + - backendRef + type: object + requestRedirect: + description: |- + RequestRedirect defines a schema for a filter that responds to the + request with an HTTP redirection. + + + Support: Core + properties: + hostname: + description: |- + Hostname is the hostname to be used in the value of the `Location` + header in the response. + When empty, the hostname in the `Host` header of the request is used. + + + Support: Core + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + path: + description: |- + Path defines parameters used to modify the path of the incoming request. + The modified path is then used to construct the `Location` header. When + empty, the request path is used as-is. + + + Support: Extended + properties: + replaceFullPath: + description: |- + ReplaceFullPath specifies the value with which to replace the full path + of a request during a rewrite or redirect. + maxLength: 1024 + type: string + replacePrefixMatch: + description: |- + ReplacePrefixMatch specifies the value with which to replace the prefix + match of a request during a rewrite or redirect. For example, a request + to "/foo/bar" with a prefix match of "/foo" and a ReplacePrefixMatch + of "/xyz" would be modified to "/xyz/bar". + + + Note that this matches the behavior of the PathPrefix match type. This + matches full path elements. A path element refers to the list of labels + in the path split by the `/` separator. When specified, a trailing `/` is + ignored. For example, the paths `/abc`, `/abc/`, and `/abc/def` would all + match the prefix `/abc`, but the path `/abcd` would not. + + + ReplacePrefixMatch is only compatible with a `PathPrefix` HTTPRouteMatch. + Using any other HTTPRouteMatch type on the same HTTPRouteRule will result in + the implementation setting the Accepted Condition for the Route to `status: False`. + + + Request Path | Prefix Match | Replace Prefix | Modified Path + -------------|--------------|----------------|---------- + /foo/bar | /foo | /xyz | /xyz/bar + /foo/bar | /foo | /xyz/ | /xyz/bar + /foo/bar | /foo/ | /xyz | /xyz/bar + /foo/bar | /foo/ | /xyz/ | /xyz/bar + /foo | /foo | /xyz | /xyz + /foo/ | /foo | /xyz | /xyz/ + /foo/bar | /foo | | /bar + /foo/ | /foo | | / + /foo | /foo | | / + /foo/ | /foo | / | / + /foo | /foo | / | / + maxLength: 1024 + type: string type: description: |- - Type identifies the type of filter to apply. As with other API fields, - types are classified into three conformance levels: - - - - Core: Filter types and their corresponding configuration defined by - "Support: Core" in this package, e.g. "RequestHeaderModifier". All - implementations must support core filters. - - - - Extended: Filter types and their corresponding configuration defined by - "Support: Extended" in this package, e.g. "RequestMirror". Implementers - are encouraged to support extended filters. - - - - Implementation-specific: Filters that are defined and supported by - specific vendors. - In the future, filters showing convergence in behavior across multiple - implementations will be considered for inclusion in extended or core - conformance levels. Filter-specific configuration for such filters - is specified using the ExtensionRef field. `Type` should be set to - "ExtensionRef" for custom filters. - - - Implementers are encouraged to define custom implementation types to - extend the core API with implementation-specific behavior. - - - If a reference to a custom filter type cannot be resolved, the filter - MUST NOT be skipped. Instead, requests that would have been processed by - that filter MUST receive a HTTP error response. - - + Type defines the type of path modifier. Additional types may be + added in a future release of the API. + + Note that values may be added to this enum, implementations must ensure that unknown values will not cause a crash. - - + + Unknown values here must result in the implementation setting the Accepted Condition for the Route to `status: False`, with a Reason of `UnsupportedValue`. enum: - - RequestHeaderModifier - - ResponseHeaderModifier - - RequestMirror - - RequestRedirect - - URLRewrite - - ExtensionRef + - ReplaceFullPath + - ReplacePrefixMatch type: string - urlRewrite: - description: |- - URLRewrite defines a schema for a filter that modifies a request during forwarding. - - - Support: Extended - properties: - hostname: - description: |- - Hostname is the value to be used to replace the Host header value during - forwarding. - - - Support: Extended - maxLength: 253 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - path: - description: |- - Path defines a path rewrite. - - - Support: Extended - properties: - replaceFullPath: - description: |- - ReplaceFullPath specifies the value with which to replace the full path - of a request during a rewrite or redirect. - maxLength: 1024 - type: string - replacePrefixMatch: - description: |- - ReplacePrefixMatch specifies the value with which to replace the prefix - match of a request during a rewrite or redirect. For example, a request - to "/foo/bar" with a prefix match of "/foo" and a ReplacePrefixMatch - of "/xyz" would be modified to "/xyz/bar". - - - Note that this matches the behavior of the PathPrefix match type. This - matches full path elements. A path element refers to the list of labels - in the path split by the `/` separator. When specified, a trailing `/` is - ignored. For example, the paths `/abc`, `/abc/`, and `/abc/def` would all - match the prefix `/abc`, but the path `/abcd` would not. - - - ReplacePrefixMatch is only compatible with a `PathPrefix` HTTPRouteMatch. - Using any other HTTPRouteMatch type on the same HTTPRouteRule will result in - the implementation setting the Accepted Condition for the Route to `status: False`. - - - Request Path | Prefix Match | Replace Prefix | Modified Path - -------------|--------------|----------------|---------- - /foo/bar | /foo | /xyz | /xyz/bar - /foo/bar | /foo | /xyz/ | /xyz/bar - /foo/bar | /foo/ | /xyz | /xyz/bar - /foo/bar | /foo/ | /xyz/ | /xyz/bar - /foo | /foo | /xyz | /xyz - /foo/ | /foo | /xyz | /xyz/ - /foo/bar | /foo | | /bar - /foo/ | /foo | | / - /foo | /foo | | / - /foo/ | /foo | / | / - /foo | /foo | / | / - maxLength: 1024 - type: string - type: - description: |- - Type defines the type of path modifier. Additional types may be - added in a future release of the API. - - - Note that values may be added to this enum, implementations - must ensure that unknown values will not cause a crash. - - - Unknown values here must result in the implementation setting the - Accepted Condition for the Route to `status: False`, with a - Reason of `UnsupportedValue`. - enum: - - ReplaceFullPath - - ReplacePrefixMatch - type: string - required: - - type - type: object - type: object required: - - type + - type type: object - maxItems: 16 - type: array - matches: - description: |- - Matches define conditions used for matching the rule against incoming - HTTP requests. Each match is independent, i.e. this rule will be matched - if **any** one of the matches is satisfied. - - - For example, take the following matches configuration: - - - ``` - matches: - - path: - value: "/foo" - headers: - - name: "version" - value: "v2" - - path: - value: "/v2/foo" - ``` - - - For a request to match against this rule, a request must satisfy - EITHER of the two conditions: - - - - path prefixed with `/foo` AND contains the header `version: v2` - - path prefix of `/v2/foo` - - - See the documentation for HTTPRouteMatch on how to specify multiple - match conditions that should be ANDed together. - - - If no matches are specified, the default is a prefix - path match on "/", which has the effect of matching every - HTTP request. - - - Proxy or Load Balancer routing configuration generated from HTTPRoutes - MUST prioritize matches based on the following criteria, continuing on - ties. Across all rules specified on applicable Routes, precedence must be - given to the match having: - - - * "Exact" path match. - * "Prefix" path match with largest number of characters. - * Method match. - * Largest number of header matches. - * Largest number of query param matches. - - - Note: The precedence of RegularExpression path matches are implementation-specific. - - - If ties still exist across multiple Routes, matching precedence MUST be - determined in order of the following criteria, continuing on ties: - - - * The oldest Route based on creation timestamp. - * The Route appearing first in alphabetical order by - "{namespace}/{name}". - - - If ties still exist within an HTTPRoute, matching precedence MUST be granted - to the FIRST matching rule (in list order) with a match meeting the above - criteria. - - - When no rules matching a request have been successfully attached to the - parent a request is coming from, a HTTP 404 status code MUST be returned. - items: - properties: - headers: - description: |- - Headers specifies HTTP request header matchers. Multiple match values are - ANDed together, meaning, a request must match all the specified headers - to select the route. - items: - description: |- - HTTPHeaderMatch describes how to select a HTTP route by matching HTTP request - headers. - properties: - name: - description: |- - Name is the name of the HTTP Header to be matched. Name matching MUST be - case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). - - - If multiple entries specify equivalent header names, only the first - entry with an equivalent name MUST be considered for a match. Subsequent - entries with an equivalent header name MUST be ignored. Due to the - case-insensitivity of header names, "foo" and "Foo" are considered - equivalent. - - - When a header is repeated in an HTTP request, it is - implementation-specific behavior as to how this is represented. - Generally, proxies should follow the guidance from the RFC: - https://www.rfc-editor.org/rfc/rfc7230.html#section-3.2.2 regarding - processing a repeated header, with special handling for "Set-Cookie". - maxLength: 256 - minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ - type: string - type: - default: Exact - description: |- - Type specifies how to match against the value of the header. - - - Support: Core (Exact) - - - Support: Implementation-specific (RegularExpression) - - - Since RegularExpression HeaderMatchType has implementation-specific - conformance, implementations can support POSIX, PCRE or any other dialects - of regular expressions. Please read the implementation's documentation to - determine the supported dialect. - enum: - - Exact - - RegularExpression - type: string - value: - description: Value is the value of HTTP Header to be matched. - maxLength: 4096 - minLength: 1 - type: string - required: - - name - - value - type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: + port: + description: |- + Port is the port to be used in the value of the `Location` + header in the response. + + + If no port is specified, the redirect port MUST be derived using the + following rules: + + + * If redirect scheme is not-empty, the redirect port MUST be the well-known + port associated with the redirect scheme. Specifically "http" to port 80 + and "https" to port 443. If the redirect scheme does not have a + well-known port, the listener port of the Gateway SHOULD be used. + * If redirect scheme is empty, the redirect port MUST be the Gateway + Listener port. + + + Implementations SHOULD NOT add the port number in the 'Location' + header in the following cases: + + + * A Location header that will use HTTP (whether that is determined via + the Listener protocol or the Scheme field) _and_ use port 80. + * A Location header that will use HTTPS (whether that is determined via + the Listener protocol or the Scheme field) _and_ use port 443. + + + Support: Extended + format: int32 + maximum: 65535 + minimum: 1 + type: integer + scheme: + description: |- + Scheme is the scheme to be used in the value of the `Location` header in + the response. When empty, the scheme of the request is used. + + + Scheme redirects can affect the port of the redirect, for more information, + refer to the documentation for the port field of this filter. + + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + + + Support: Extended + enum: + - http + - https + type: string + statusCode: + default: 302 + description: |- + StatusCode is the HTTP status code to be used in response. + + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + + + Support: Core + enum: + - 301 + - 302 + type: integer + type: object + responseHeaderModifier: + description: |- + ResponseHeaderModifier defines a schema for a filter that modifies response + headers. + + + Support: Extended + properties: + add: + description: |- + Add adds the given header(s) (name, value) to the request + before the action. It appends to any existing values associated + with the header name. + + + Input: + GET /foo HTTP/1.1 + my-header: foo + + + Config: + add: + - name: "my-header" + value: "bar,baz" + + + Output: + GET /foo HTTP/1.1 + my-header: foo,bar,baz + items: + description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + + If multiple entries specify equivalent header names, the first entry with + an equivalent name MUST be considered for a match. Subsequent entries + with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + description: Value is the value of HTTP Header to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: - name - x-kubernetes-list-type: map - path: - description: Path specifies a HTTP request path matcher. - properties: - type: - default: PathPrefix - description: |- - Type specifies how to match against the path Value. - - - Support: Core (Exact, PathPrefix) - - - Support: Implementation-specific (RegularExpression) - enum: - - Exact - - PathPrefix - - RegularExpression - type: string - value: - default: / - description: Value of the HTTP path to match against. - maxLength: 1024 - type: string - type: object - queryParams: - description: |- - QueryParams specifies HTTP query parameter matchers. Multiple match - values are ANDed together, meaning, a request must match all the - specified query parameters to select the route. - - - Support: Extended - items: + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + remove: + description: |- + Remove the given header(s) from the HTTP request before the action. The + value of Remove is a list of HTTP header names. Note that the header + names are case-insensitive (see + https://datatracker.ietf.org/doc/html/rfc2616#section-4.2). + + + Input: + GET /foo HTTP/1.1 + my-header1: foo + my-header2: bar + my-header3: baz + + + Config: + remove: ["my-header1", "my-header3"] + + + Output: + GET /foo HTTP/1.1 + my-header2: bar + items: + type: string + maxItems: 16 + type: array + x-kubernetes-list-type: set + set: + description: |- + Set overwrites the request with the given header (name, value) + before the action. + + + Input: + GET /foo HTTP/1.1 + my-header: foo + + + Config: + set: + - name: "my-header" + value: "bar" + + + Output: + GET /foo HTTP/1.1 + my-header: bar + items: + description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. + properties: + name: description: |- - HTTPQueryParamMatch describes how to select a HTTP route by matching HTTP - query parameters. - properties: - name: - description: |- - Name is the name of the HTTP query param to be matched. This must be an - exact string match. (See - https://tools.ietf.org/html/rfc7230#section-2.7.3). - - - If multiple entries specify equivalent query param names, only the first - entry with an equivalent name MUST be considered for a match. Subsequent - entries with an equivalent query param name MUST be ignored. - - - If a query param is repeated in an HTTP request, the behavior is - purposely left undefined, since different data planes have different - capabilities. However, it is *recommended* that implementations should - match against the first value of the param if the data plane supports it, - as this behavior is expected in other load balancing contexts outside of - the Gateway API. - - - Users SHOULD NOT route traffic based on repeated query params to guard - themselves against potential differences in the implementations. - maxLength: 256 - minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ - type: string - type: - default: Exact - description: |- - Type specifies how to match against the value of the query parameter. - - - Support: Extended (Exact) - - - Support: Implementation-specific (RegularExpression) - - - Since RegularExpression QueryParamMatchType has Implementation-specific - conformance, implementations can support POSIX, PCRE or any other - dialects of regular expressions. Please read the implementation's - documentation to determine the supported dialect. - enum: - - Exact - - RegularExpression - type: string - value: - description: Value is the value of HTTP query param to be matched. - maxLength: 1024 - minLength: 1 - type: string - required: - - name - - value - type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + + If multiple entries specify equivalent header names, the first entry with + an equivalent name MUST be considered for a match. Subsequent entries + with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + description: Value is the value of HTTP Header to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: - name - x-kubernetes-list-type: map - type: object - maxItems: 8 - type: array - type: object - weight: - description: Weight indicate how many percentage of traffic the canary pods should receive - format: int32 - maximum: 100 - minimum: 0 - type: integer - type: object - type: object - required: - - targets - type: object - type: array - toleration: - description: Toleration is the toleration policy of the canary strategy - properties: - initialDelaySeconds: - description: Number of seconds after the toleration check has started before the task are initiated. - format: int32 - type: integer - taskFailureThreshold: - anyOf: - - type: integer - - type: string - description: |- - FailureThreshold indicates how many failed pods can be tolerated before marking the rollout task as success - If not set, the default value is 0, which means no failed pods can be tolerated - This is a task level threshold. - x-kubernetes-int-or-string: true - workloadTotalFailureThreshold: - anyOf: - - type: integer - - type: string - description: |- - WorkloadFailureThreshold indicates how many failed pods can be tolerated in all upgraded pods of one workload. - The default value is 0, which means no failed pods can be tolerated. - This is a workload level threshold. - x-kubernetes-int-or-string: true - type: object - type: object - canary: - description: Canary defines the canary strategy - properties: - podTemplateMetadataPatch: - description: PodTemplateMetadataPatch defines a patch for workload podTemplate metadata. - properties: - annotations: - additionalProperties: - type: string - description: Annotations are additional metadata that can be included. - type: object - labels: - additionalProperties: - type: string - description: Labels are additional metadata that can be included. - type: object - type: object - properties: - additionalProperties: - type: string - description: Properties contains additional information for step - type: object - targets: - description: desired target replicas - items: - properties: - cluster: - description: Cluster indicates the name of cluster - type: string - name: - description: Name is the resource name - type: string - replicaSlidingWindow: - anyOf: - - type: integer - - type: string - description: |- - ReplicaSlidingWindow used to control the number of pods that are allowed to be upgraded in - a sliding window for progressive rollout smoothly. - x-kubernetes-int-or-string: true - replicas: - anyOf: - - type: integer - - type: string - description: Replicas is the replicas of the rollout task, which represents the number of pods to be upgraded - x-kubernetes-int-or-string: true - required: - - name - - replicas - type: object - type: array - traffic: - description: traffic strategy - properties: - http: - properties: - filters: - description: |- - Filters define the filters that are applied to requests that match - this rule. - - - The effects of ordering of multiple behaviors are currently unspecified. - This can change in the future based on feedback during the alpha stage. - - - Conformance-levels at this level are defined based on the type of filter: - - - - ALL core filters MUST be supported by all implementations. - - Implementers are encouraged to support extended filters. - - Implementation-specific custom filters have no API guarantees across - implementations. - - - Specifying the same filter multiple times is not supported unless explicitly - indicated in the filter. - - - All filters are expected to be compatible with each other except for the - URLRewrite and RequestRedirect filters, which may not be combined. If an - implementation can not support other combinations of filters, they must clearly - document that limitation. In cases where incompatible or unsupported - filters are specified and cause the `Accepted` condition to be set to status - `False`, implementations may use the `IncompatibleFilters` reason to specify - this configuration error. - - - Support: Core - items: - description: |- - HTTPRouteFilter defines processing steps that must be completed during the - request or response lifecycle. HTTPRouteFilters are meant as an extension - point to express processing that may be done in Gateway implementations. Some - examples include request or response modification, implementing - authentication strategies, rate-limiting, and traffic shaping. API - guarantee/conformance is defined based on the type of the filter. - properties: - extensionRef: - description: |- - ExtensionRef is an optional, implementation-specific extension to the - "filter" behavior. For example, resource "myroutefilter" in group - "networking.example.net"). ExtensionRef MUST NOT be used for core and - extended filters. - - - This filter can be used multiple times within the same rule. - - - Support: Implementation-specific - properties: - group: - description: |- - Group is the group of the referent. For example, "gateway.networking.k8s.io". - When unspecified or empty string, core API group is inferred. - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - description: Kind is kind of the referent. For example "HTTPRoute" or "Service". - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - type: string - name: - description: Name is the name of the referent. - maxLength: 253 - minLength: 1 - type: string - required: - - group - - kind - - name - type: object - requestHeaderModifier: - description: |- - RequestHeaderModifier defines a schema for a filter that modifies request - headers. - - - Support: Core - properties: - add: - description: |- - Add adds the given header(s) (name, value) to the request - before the action. It appends to any existing values associated - with the header name. - - - Input: - GET /foo HTTP/1.1 - my-header: foo - - - Config: - add: - - name: "my-header" - value: "bar,baz" - - - Output: - GET /foo HTTP/1.1 - my-header: foo,bar,baz - items: - description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + type: object + type: + description: |- + Type identifies the type of filter to apply. As with other API fields, + types are classified into three conformance levels: + + + - Core: Filter types and their corresponding configuration defined by + "Support: Core" in this package, e.g. "RequestHeaderModifier". All + implementations must support core filters. + + + - Extended: Filter types and their corresponding configuration defined by + "Support: Extended" in this package, e.g. "RequestMirror". Implementers + are encouraged to support extended filters. + + + - Implementation-specific: Filters that are defined and supported by + specific vendors. + In the future, filters showing convergence in behavior across multiple + implementations will be considered for inclusion in extended or core + conformance levels. Filter-specific configuration for such filters + is specified using the ExtensionRef field. `Type` should be set to + "ExtensionRef" for custom filters. + + + Implementers are encouraged to define custom implementation types to + extend the core API with implementation-specific behavior. + + + If a reference to a custom filter type cannot be resolved, the filter + MUST NOT be skipped. Instead, requests that would have been processed by + that filter MUST receive a HTTP error response. + + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + enum: + - RequestHeaderModifier + - ResponseHeaderModifier + - RequestMirror + - RequestRedirect + - URLRewrite + - ExtensionRef + type: string + urlRewrite: + description: |- + URLRewrite defines a schema for a filter that modifies a request during forwarding. + + + Support: Extended + properties: + hostname: + description: |- + Hostname is the value to be used to replace the Host header value during + forwarding. + + + Support: Extended + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + path: + description: |- + Path defines a path rewrite. + + + Support: Extended properties: - name: + replaceFullPath: description: |- - Name is the name of the HTTP Header to be matched. Name matching MUST be - case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). - - - If multiple entries specify equivalent header names, the first entry with - an equivalent name MUST be considered for a match. Subsequent entries - with an equivalent header name MUST be ignored. Due to the - case-insensitivity of header names, "foo" and "Foo" are considered - equivalent. - maxLength: 256 - minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ - type: string - value: - description: Value is the value of HTTP Header to be matched. - maxLength: 4096 - minLength: 1 + ReplaceFullPath specifies the value with which to replace the full path + of a request during a rewrite or redirect. + maxLength: 1024 type: string - required: - - name - - value - type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - remove: - description: |- - Remove the given header(s) from the HTTP request before the action. The - value of Remove is a list of HTTP header names. Note that the header - names are case-insensitive (see - https://datatracker.ietf.org/doc/html/rfc2616#section-4.2). - - - Input: - GET /foo HTTP/1.1 - my-header1: foo - my-header2: bar - my-header3: baz - - - Config: - remove: ["my-header1", "my-header3"] - - - Output: - GET /foo HTTP/1.1 - my-header2: bar - items: - type: string - maxItems: 16 - type: array - x-kubernetes-list-type: set - set: - description: |- - Set overwrites the request with the given header (name, value) - before the action. - - - Input: - GET /foo HTTP/1.1 - my-header: foo - - - Config: - set: - - name: "my-header" - value: "bar" - - - Output: - GET /foo HTTP/1.1 - my-header: bar - items: - description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. - properties: - name: + replacePrefixMatch: description: |- - Name is the name of the HTTP Header to be matched. Name matching MUST be - case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). - - - If multiple entries specify equivalent header names, the first entry with - an equivalent name MUST be considered for a match. Subsequent entries - with an equivalent header name MUST be ignored. Due to the - case-insensitivity of header names, "foo" and "Foo" are considered - equivalent. - maxLength: 256 - minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + ReplacePrefixMatch specifies the value with which to replace the prefix + match of a request during a rewrite or redirect. For example, a request + to "/foo/bar" with a prefix match of "/foo" and a ReplacePrefixMatch + of "/xyz" would be modified to "/xyz/bar". + + + Note that this matches the behavior of the PathPrefix match type. This + matches full path elements. A path element refers to the list of labels + in the path split by the `/` separator. When specified, a trailing `/` is + ignored. For example, the paths `/abc`, `/abc/`, and `/abc/def` would all + match the prefix `/abc`, but the path `/abcd` would not. + + + ReplacePrefixMatch is only compatible with a `PathPrefix` HTTPRouteMatch. + Using any other HTTPRouteMatch type on the same HTTPRouteRule will result in + the implementation setting the Accepted Condition for the Route to `status: False`. + + + Request Path | Prefix Match | Replace Prefix | Modified Path + -------------|--------------|----------------|---------- + /foo/bar | /foo | /xyz | /xyz/bar + /foo/bar | /foo | /xyz/ | /xyz/bar + /foo/bar | /foo/ | /xyz | /xyz/bar + /foo/bar | /foo/ | /xyz/ | /xyz/bar + /foo | /foo | /xyz | /xyz + /foo/ | /foo | /xyz | /xyz/ + /foo/bar | /foo | | /bar + /foo/ | /foo | | / + /foo | /foo | | / + /foo/ | /foo | / | / + /foo | /foo | / | / + maxLength: 1024 type: string - value: - description: Value is the value of HTTP Header to be matched. - maxLength: 4096 - minLength: 1 + type: + description: |- + Type defines the type of path modifier. Additional types may be + added in a future release of the API. + + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + enum: + - ReplaceFullPath + - ReplacePrefixMatch type: string required: - - name - - value + - type type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - type: object - requestMirror: - description: |- - RequestMirror defines a schema for a filter that mirrors requests. - Requests are sent to the specified destination, but responses from - that destination are ignored. - - - This filter can be used multiple times within the same rule. Note that - not all implementations will be able to support mirroring to multiple - backends. - - - Support: Extended - - - - properties: - backendRef: + type: object + required: + - type + type: object + maxItems: 16 + type: array + matches: + description: |- + Matches define conditions used for matching the rule against incoming + HTTP requests. Each match is independent, i.e. this rule will be matched + if **any** one of the matches is satisfied. + + + For example, take the following matches configuration: + + + ``` + matches: + - path: + value: "/foo" + headers: + - name: "version" + value: "v2" + - path: + value: "/v2/foo" + ``` + + + For a request to match against this rule, a request must satisfy + EITHER of the two conditions: + + + - path prefixed with `/foo` AND contains the header `version: v2` + - path prefix of `/v2/foo` + + + See the documentation for HTTPRouteMatch on how to specify multiple + match conditions that should be ANDed together. + + + If no matches are specified, the default is a prefix + path match on "/", which has the effect of matching every + HTTP request. + + + Proxy or Load Balancer routing configuration generated from HTTPRoutes + MUST prioritize matches based on the following criteria, continuing on + ties. Across all rules specified on applicable Routes, precedence must be + given to the match having: + + + * "Exact" path match. + * "Prefix" path match with largest number of characters. + * Method match. + * Largest number of header matches. + * Largest number of query param matches. + + + Note: The precedence of RegularExpression path matches are implementation-specific. + + + If ties still exist across multiple Routes, matching precedence MUST be + determined in order of the following criteria, continuing on ties: + + + * The oldest Route based on creation timestamp. + * The Route appearing first in alphabetical order by + "{namespace}/{name}". + + + If ties still exist within an HTTPRoute, matching precedence MUST be granted + to the FIRST matching rule (in list order) with a match meeting the above + criteria. + + + When no rules matching a request have been successfully attached to the + parent a request is coming from, a HTTP 404 status code MUST be returned. + items: + properties: + headers: + description: |- + Headers specifies HTTP request header matchers. Multiple match values are + ANDed together, meaning, a request must match all the specified headers + to select the route. + items: description: |- - BackendRef references a resource where mirrored requests are sent. - - - Mirrored requests must be sent only to a single destination endpoint - within this BackendRef, irrespective of how many endpoints are present - within this BackendRef. - - - If the referent cannot be found, this BackendRef is invalid and must be - dropped from the Gateway. The controller must ensure the "ResolvedRefs" - condition on the Route status is set to `status: False` and not configure - this backend in the underlying implementation. - - - If there is a cross-namespace reference to an *existing* object - that is not allowed by a ReferenceGrant, the controller must ensure the - "ResolvedRefs" condition on the Route is set to `status: False`, - with the "RefNotPermitted" reason and not configure this backend in the - underlying implementation. - - - In either error case, the Message of the `ResolvedRefs` Condition - should be used to provide more detail about the problem. - - - Support: Extended for Kubernetes Service - - - Support: Implementation-specific for any other resource + HTTPHeaderMatch describes how to select a HTTP route by matching HTTP request + headers. properties: - group: - default: "" - description: |- - Group is the group of the referent. For example, "gateway.networking.k8s.io". - When unspecified or empty string, core API group is inferred. - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - default: Service - description: |- - Kind is the Kubernetes resource kind of the referent. For example - "Service". - - - Defaults to "Service" when not specified. - - - ExternalName services can refer to CNAME DNS records that may live - outside of the cluster and as such are difficult to reason about in - terms of conformance. They also may not be safe to forward to (see - CVE-2021-25740 for more information). Implementations SHOULD NOT - support ExternalName Services. - - - Support: Core (Services with a type other than ExternalName) - - - Support: Implementation-specific (Services with type ExternalName) - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - type: string name: - description: Name is the name of the referent. - maxLength: 253 + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + + If multiple entries specify equivalent header names, only the first + entry with an equivalent name MUST be considered for a match. Subsequent + entries with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + + + When a header is repeated in an HTTP request, it is + implementation-specific behavior as to how this is represented. + Generally, proxies should follow the guidance from the RFC: + https://www.rfc-editor.org/rfc/rfc7230.html#section-3.2.2 regarding + processing a repeated header, with special handling for "Set-Cookie". + maxLength: 256 minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ type: string - namespace: + type: + default: Exact description: |- - Namespace is the namespace of the backend. When unspecified, the local - namespace is inferred. - - - Note that when a namespace different than the local namespace is specified, - a ReferenceGrant object is required in the referent namespace to allow that - namespace's owner to accept the reference. See the ReferenceGrant - documentation for details. - - - Support: Core - maxLength: 63 + Type specifies how to match against the value of the header. + + + Support: Core (Exact) + + + Support: Implementation-specific (RegularExpression) + + + Since RegularExpression HeaderMatchType has implementation-specific + conformance, implementations can support POSIX, PCRE or any other dialects + of regular expressions. Please read the implementation's documentation to + determine the supported dialect. + enum: + - Exact + - RegularExpression + type: string + value: + description: Value is the value of HTTP Header to be matched. + maxLength: 4096 minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ type: string - port: - description: |- - Port specifies the destination port number to use for this resource. - Port is required when the referent is a Kubernetes Service. In this - case, the port number is the service port number, not the target port. - For other resources, destination port might be derived from the referent - resource or this field. - format: int32 - maximum: 65535 - minimum: 1 - type: integer required: - - name - type: object - fraction: - description: |- - Fraction represents the fraction of requests that should be - mirrored to BackendRef. - - - Only one of Fraction or Percent may be specified. If neither field - is specified, 100% of requests will be mirrored. - - - - properties: - denominator: - default: 100 - format: int32 - minimum: 1 - type: integer - numerator: - format: int32 - minimum: 0 - type: integer - required: - - numerator - type: object - percent: - description: |- - Percent represents the percentage of requests that should be - mirrored to BackendRef. Its minimum value is 0 (indicating 0% of - requests) and its maximum value is 100 (indicating 100% of requests). - - - Only one of Fraction or Percent may be specified. If neither field - is specified, 100% of requests will be mirrored. - - - - format: int32 - maximum: 100 - minimum: 0 - type: integer - required: - - backendRef - type: object - requestRedirect: - description: |- - RequestRedirect defines a schema for a filter that responds to the - request with an HTTP redirection. - - - Support: Core - properties: - hostname: - description: |- - Hostname is the hostname to be used in the value of the `Location` - header in the response. - When empty, the hostname in the `Host` header of the request is used. - - - Support: Core - maxLength: 253 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - path: - description: |- - Path defines parameters used to modify the path of the incoming request. - The modified path is then used to construct the `Location` header. When - empty, the request path is used as-is. - - - Support: Extended - properties: - replaceFullPath: - description: |- - ReplaceFullPath specifies the value with which to replace the full path - of a request during a rewrite or redirect. - maxLength: 1024 - type: string - replacePrefixMatch: - description: |- - ReplacePrefixMatch specifies the value with which to replace the prefix - match of a request during a rewrite or redirect. For example, a request - to "/foo/bar" with a prefix match of "/foo" and a ReplacePrefixMatch - of "/xyz" would be modified to "/xyz/bar". - - - Note that this matches the behavior of the PathPrefix match type. This - matches full path elements. A path element refers to the list of labels - in the path split by the `/` separator. When specified, a trailing `/` is - ignored. For example, the paths `/abc`, `/abc/`, and `/abc/def` would all - match the prefix `/abc`, but the path `/abcd` would not. - - - ReplacePrefixMatch is only compatible with a `PathPrefix` HTTPRouteMatch. - Using any other HTTPRouteMatch type on the same HTTPRouteRule will result in - the implementation setting the Accepted Condition for the Route to `status: False`. - - - Request Path | Prefix Match | Replace Prefix | Modified Path - -------------|--------------|----------------|---------- - /foo/bar | /foo | /xyz | /xyz/bar - /foo/bar | /foo | /xyz/ | /xyz/bar - /foo/bar | /foo/ | /xyz | /xyz/bar - /foo/bar | /foo/ | /xyz/ | /xyz/bar - /foo | /foo | /xyz | /xyz - /foo/ | /foo | /xyz | /xyz/ - /foo/bar | /foo | | /bar - /foo/ | /foo | | / - /foo | /foo | | / - /foo/ | /foo | / | / - /foo | /foo | / | / - maxLength: 1024 - type: string - type: - description: |- - Type defines the type of path modifier. Additional types may be - added in a future release of the API. - - - Note that values may be added to this enum, implementations - must ensure that unknown values will not cause a crash. - - - Unknown values here must result in the implementation setting the - Accepted Condition for the Route to `status: False`, with a - Reason of `UnsupportedValue`. - enum: - - ReplaceFullPath - - ReplacePrefixMatch - type: string - required: - - type - type: object - port: - description: |- - Port is the port to be used in the value of the `Location` - header in the response. - - - If no port is specified, the redirect port MUST be derived using the - following rules: - - - * If redirect scheme is not-empty, the redirect port MUST be the well-known - port associated with the redirect scheme. Specifically "http" to port 80 - and "https" to port 443. If the redirect scheme does not have a - well-known port, the listener port of the Gateway SHOULD be used. - * If redirect scheme is empty, the redirect port MUST be the Gateway - Listener port. - - - Implementations SHOULD NOT add the port number in the 'Location' - header in the following cases: - - - * A Location header that will use HTTP (whether that is determined via - the Listener protocol or the Scheme field) _and_ use port 80. - * A Location header that will use HTTPS (whether that is determined via - the Listener protocol or the Scheme field) _and_ use port 443. - - - Support: Extended - format: int32 - maximum: 65535 - minimum: 1 - type: integer - scheme: - description: |- - Scheme is the scheme to be used in the value of the `Location` header in - the response. When empty, the scheme of the request is used. - - - Scheme redirects can affect the port of the redirect, for more information, - refer to the documentation for the port field of this filter. - - - Note that values may be added to this enum, implementations - must ensure that unknown values will not cause a crash. - - - Unknown values here must result in the implementation setting the - Accepted Condition for the Route to `status: False`, with a - Reason of `UnsupportedValue`. - - - Support: Extended - enum: - - http - - https - type: string - statusCode: - default: 302 - description: |- - StatusCode is the HTTP status code to be used in response. - - - Note that values may be added to this enum, implementations - must ensure that unknown values will not cause a crash. - - - Unknown values here must result in the implementation setting the - Accepted Condition for the Route to `status: False`, with a - Reason of `UnsupportedValue`. - - - Support: Core - enum: - - 301 - - 302 - type: integer - type: object - responseHeaderModifier: - description: |- - ResponseHeaderModifier defines a schema for a filter that modifies response - headers. - - - Support: Extended - properties: - add: - description: |- - Add adds the given header(s) (name, value) to the request - before the action. It appends to any existing values associated - with the header name. - - - Input: - GET /foo HTTP/1.1 - my-header: foo - - - Config: - add: - - name: "my-header" - value: "bar,baz" - - - Output: - GET /foo HTTP/1.1 - my-header: foo,bar,baz - items: - description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. - properties: - name: - description: |- - Name is the name of the HTTP Header to be matched. Name matching MUST be - case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). - - - If multiple entries specify equivalent header names, the first entry with - an equivalent name MUST be considered for a match. Subsequent entries - with an equivalent header name MUST be ignored. Due to the - case-insensitivity of header names, "foo" and "Foo" are considered - equivalent. - maxLength: 256 - minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ - type: string - value: - description: Value is the value of HTTP Header to be matched. - maxLength: 4096 - minLength: 1 - type: string - required: - - name - - value - type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - remove: - description: |- - Remove the given header(s) from the HTTP request before the action. The - value of Remove is a list of HTTP header names. Note that the header - names are case-insensitive (see - https://datatracker.ietf.org/doc/html/rfc2616#section-4.2). - - - Input: - GET /foo HTTP/1.1 - my-header1: foo - my-header2: bar - my-header3: baz - - - Config: - remove: ["my-header1", "my-header3"] - - - Output: - GET /foo HTTP/1.1 - my-header2: bar - items: - type: string - maxItems: 16 - type: array - x-kubernetes-list-type: set - set: - description: |- - Set overwrites the request with the given header (name, value) - before the action. - - - Input: - GET /foo HTTP/1.1 - my-header: foo - - - Config: - set: - - name: "my-header" - value: "bar" - - - Output: - GET /foo HTTP/1.1 - my-header: bar - items: - description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. - properties: - name: - description: |- - Name is the name of the HTTP Header to be matched. Name matching MUST be - case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). - - - If multiple entries specify equivalent header names, the first entry with - an equivalent name MUST be considered for a match. Subsequent entries - with an equivalent header name MUST be ignored. Due to the - case-insensitivity of header names, "foo" and "Foo" are considered - equivalent. - maxLength: 256 - minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ - type: string - value: - description: Value is the value of HTTP Header to be matched. - maxLength: 4096 - minLength: 1 - type: string - required: - name - value - type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - type: object - type: - description: |- - Type identifies the type of filter to apply. As with other API fields, - types are classified into three conformance levels: - - - - Core: Filter types and their corresponding configuration defined by - "Support: Core" in this package, e.g. "RequestHeaderModifier". All - implementations must support core filters. - - - - Extended: Filter types and their corresponding configuration defined by - "Support: Extended" in this package, e.g. "RequestMirror". Implementers - are encouraged to support extended filters. - - - - Implementation-specific: Filters that are defined and supported by - specific vendors. - In the future, filters showing convergence in behavior across multiple - implementations will be considered for inclusion in extended or core - conformance levels. Filter-specific configuration for such filters - is specified using the ExtensionRef field. `Type` should be set to - "ExtensionRef" for custom filters. - - - Implementers are encouraged to define custom implementation types to - extend the core API with implementation-specific behavior. - - - If a reference to a custom filter type cannot be resolved, the filter - MUST NOT be skipped. Instead, requests that would have been processed by - that filter MUST receive a HTTP error response. - - - Note that values may be added to this enum, implementations - must ensure that unknown values will not cause a crash. - - - Unknown values here must result in the implementation setting the - Accepted Condition for the Route to `status: False`, with a - Reason of `UnsupportedValue`. - enum: - - RequestHeaderModifier - - ResponseHeaderModifier - - RequestMirror - - RequestRedirect - - URLRewrite - - ExtensionRef - type: string - urlRewrite: - description: |- - URLRewrite defines a schema for a filter that modifies a request during forwarding. - - - Support: Extended - properties: - hostname: - description: |- - Hostname is the value to be used to replace the Host header value during - forwarding. - - - Support: Extended - maxLength: 253 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - path: - description: |- - Path defines a path rewrite. - - - Support: Extended - properties: - replaceFullPath: - description: |- - ReplaceFullPath specifies the value with which to replace the full path - of a request during a rewrite or redirect. - maxLength: 1024 - type: string - replacePrefixMatch: - description: |- - ReplacePrefixMatch specifies the value with which to replace the prefix - match of a request during a rewrite or redirect. For example, a request - to "/foo/bar" with a prefix match of "/foo" and a ReplacePrefixMatch - of "/xyz" would be modified to "/xyz/bar". - - - Note that this matches the behavior of the PathPrefix match type. This - matches full path elements. A path element refers to the list of labels - in the path split by the `/` separator. When specified, a trailing `/` is - ignored. For example, the paths `/abc`, `/abc/`, and `/abc/def` would all - match the prefix `/abc`, but the path `/abcd` would not. - - - ReplacePrefixMatch is only compatible with a `PathPrefix` HTTPRouteMatch. - Using any other HTTPRouteMatch type on the same HTTPRouteRule will result in - the implementation setting the Accepted Condition for the Route to `status: False`. - - - Request Path | Prefix Match | Replace Prefix | Modified Path - -------------|--------------|----------------|---------- - /foo/bar | /foo | /xyz | /xyz/bar - /foo/bar | /foo | /xyz/ | /xyz/bar - /foo/bar | /foo/ | /xyz | /xyz/bar - /foo/bar | /foo/ | /xyz/ | /xyz/bar - /foo | /foo | /xyz | /xyz - /foo/ | /foo | /xyz | /xyz/ - /foo/bar | /foo | | /bar - /foo/ | /foo | | / - /foo | /foo | | / - /foo/ | /foo | / | / - /foo | /foo | / | / - maxLength: 1024 - type: string - type: - description: |- - Type defines the type of path modifier. Additional types may be - added in a future release of the API. - - - Note that values may be added to this enum, implementations - must ensure that unknown values will not cause a crash. - - - Unknown values here must result in the implementation setting the - Accepted Condition for the Route to `status: False`, with a - Reason of `UnsupportedValue`. - enum: - - ReplaceFullPath - - ReplacePrefixMatch - type: string - required: - - type type: object - type: object - required: - - type - type: object - maxItems: 16 - type: array - matches: - description: |- - Matches define conditions used for matching the rule against incoming - HTTP requests. Each match is independent, i.e. this rule will be matched - if **any** one of the matches is satisfied. - - - For example, take the following matches configuration: - - - ``` - matches: - - path: - value: "/foo" - headers: - - name: "version" - value: "v2" - - path: - value: "/v2/foo" - ``` - - - For a request to match against this rule, a request must satisfy - EITHER of the two conditions: - - - - path prefixed with `/foo` AND contains the header `version: v2` - - path prefix of `/v2/foo` - - - See the documentation for HTTPRouteMatch on how to specify multiple - match conditions that should be ANDed together. - - - If no matches are specified, the default is a prefix - path match on "/", which has the effect of matching every - HTTP request. - - - Proxy or Load Balancer routing configuration generated from HTTPRoutes - MUST prioritize matches based on the following criteria, continuing on - ties. Across all rules specified on applicable Routes, precedence must be - given to the match having: - - - * "Exact" path match. - * "Prefix" path match with largest number of characters. - * Method match. - * Largest number of header matches. - * Largest number of query param matches. - - - Note: The precedence of RegularExpression path matches are implementation-specific. - - - If ties still exist across multiple Routes, matching precedence MUST be - determined in order of the following criteria, continuing on ties: - - - * The oldest Route based on creation timestamp. - * The Route appearing first in alphabetical order by - "{namespace}/{name}". - - - If ties still exist within an HTTPRoute, matching precedence MUST be granted - to the FIRST matching rule (in list order) with a match meeting the above - criteria. - - - When no rules matching a request have been successfully attached to the - parent a request is coming from, a HTTP 404 status code MUST be returned. - items: - properties: - headers: - description: |- - Headers specifies HTTP request header matchers. Multiple match values are - ANDed together, meaning, a request must match all the specified headers - to select the route. - items: - description: |- - HTTPHeaderMatch describes how to select a HTTP route by matching HTTP request - headers. - properties: - name: - description: |- - Name is the name of the HTTP Header to be matched. Name matching MUST be - case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). - - - If multiple entries specify equivalent header names, only the first - entry with an equivalent name MUST be considered for a match. Subsequent - entries with an equivalent header name MUST be ignored. Due to the - case-insensitivity of header names, "foo" and "Foo" are considered - equivalent. - - - When a header is repeated in an HTTP request, it is - implementation-specific behavior as to how this is represented. - Generally, proxies should follow the guidance from the RFC: - https://www.rfc-editor.org/rfc/rfc7230.html#section-3.2.2 regarding - processing a repeated header, with special handling for "Set-Cookie". - maxLength: 256 - minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ - type: string - type: - default: Exact - description: |- - Type specifies how to match against the value of the header. - - - Support: Core (Exact) - - - Support: Implementation-specific (RegularExpression) - - - Since RegularExpression HeaderMatchType has implementation-specific - conformance, implementations can support POSIX, PCRE or any other dialects - of regular expressions. Please read the implementation's documentation to - determine the supported dialect. - enum: - - Exact - - RegularExpression - type: string - value: - description: Value is the value of HTTP Header to be matched. - maxLength: 4096 - minLength: 1 - type: string - required: - - name - - value - type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - path: - description: Path specifies a HTTP request path matcher. - properties: - type: - default: PathPrefix - description: |- - Type specifies how to match against the path Value. - - - Support: Core (Exact, PathPrefix) - - - Support: Implementation-specific (RegularExpression) - enum: - - Exact - - PathPrefix - - RegularExpression - type: string - value: - default: / - description: Value of the HTTP path to match against. - maxLength: 1024 - type: string - type: object - queryParams: - description: |- - QueryParams specifies HTTP query parameter matchers. Multiple match - values are ANDed together, meaning, a request must match all the - specified query parameters to select the route. - - - Support: Extended - items: - description: |- - HTTPQueryParamMatch describes how to select a HTTP route by matching HTTP - query parameters. + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + path: + description: Path specifies a HTTP request path matcher. properties: - name: - description: |- - Name is the name of the HTTP query param to be matched. This must be an - exact string match. (See - https://tools.ietf.org/html/rfc7230#section-2.7.3). - - - If multiple entries specify equivalent query param names, only the first - entry with an equivalent name MUST be considered for a match. Subsequent - entries with an equivalent query param name MUST be ignored. - - - If a query param is repeated in an HTTP request, the behavior is - purposely left undefined, since different data planes have different - capabilities. However, it is *recommended* that implementations should - match against the first value of the param if the data plane supports it, - as this behavior is expected in other load balancing contexts outside of - the Gateway API. - - - Users SHOULD NOT route traffic based on repeated query params to guard - themselves against potential differences in the implementations. - maxLength: 256 - minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ - type: string type: - default: Exact + default: PathPrefix description: |- - Type specifies how to match against the value of the query parameter. - - - Support: Extended (Exact) - - + Type specifies how to match against the path Value. + + + Support: Core (Exact, PathPrefix) + + Support: Implementation-specific (RegularExpression) - - - Since RegularExpression QueryParamMatchType has Implementation-specific - conformance, implementations can support POSIX, PCRE or any other - dialects of regular expressions. Please read the implementation's - documentation to determine the supported dialect. enum: - - Exact - - RegularExpression + - Exact + - PathPrefix + - RegularExpression type: string value: - description: Value is the value of HTTP query param to be matched. + default: / + description: Value of the HTTP path to match against. maxLength: 1024 - minLength: 1 type: string - required: - - name - - value type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - type: object - maxItems: 8 - type: array - stableTraffic: - description: StableTraffic indicate the base traffic rule - properties: - filters: - description: |- - Filters define the filters that are applied to requests that match - this rule. - - - The effects of ordering of multiple behaviors are currently unspecified. - This can change in the future based on feedback during the alpha stage. - - - Conformance-levels at this level are defined based on the type of filter: - - - - ALL core filters MUST be supported by all implementations. - - Implementers are encouraged to support extended filters. - - Implementation-specific custom filters have no API guarantees across - implementations. - - - Specifying the same filter multiple times is not supported unless explicitly - indicated in the filter. - - - All filters are expected to be compatible with each other except for the - URLRewrite and RequestRedirect filters, which may not be combined. If an - implementation can not support other combinations of filters, they must clearly - document that limitation. In cases where incompatible or unsupported - filters are specified and cause the `Accepted` condition to be set to status - `False`, implementations may use the `IncompatibleFilters` reason to specify - this configuration error. - - - Support: Core - items: - description: |- - HTTPRouteFilter defines processing steps that must be completed during the - request or response lifecycle. HTTPRouteFilters are meant as an extension - point to express processing that may be done in Gateway implementations. Some - examples include request or response modification, implementing - authentication strategies, rate-limiting, and traffic shaping. API - guarantee/conformance is defined based on the type of the filter. - properties: - extensionRef: + queryParams: + description: |- + QueryParams specifies HTTP query parameter matchers. Multiple match + values are ANDed together, meaning, a request must match all the + specified query parameters to select the route. + + + Support: Extended + items: description: |- - ExtensionRef is an optional, implementation-specific extension to the - "filter" behavior. For example, resource "myroutefilter" in group - "networking.example.net"). ExtensionRef MUST NOT be used for core and - extended filters. - - - This filter can be used multiple times within the same rule. - - - Support: Implementation-specific + HTTPQueryParamMatch describes how to select a HTTP route by matching HTTP + query parameters. properties: - group: + name: description: |- - Group is the group of the referent. For example, "gateway.networking.k8s.io". - When unspecified or empty string, core API group is inferred. - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - description: Kind is kind of the referent. For example "HTTPRoute" or "Service". - maxLength: 63 + Name is the name of the HTTP query param to be matched. This must be an + exact string match. (See + https://tools.ietf.org/html/rfc7230#section-2.7.3). + + + If multiple entries specify equivalent query param names, only the first + entry with an equivalent name MUST be considered for a match. Subsequent + entries with an equivalent query param name MUST be ignored. + + + If a query param is repeated in an HTTP request, the behavior is + purposely left undefined, since different data planes have different + capabilities. However, it is *recommended* that implementations should + match against the first value of the param if the data plane supports it, + as this behavior is expected in other load balancing contexts outside of + the Gateway API. + + + Users SHOULD NOT route traffic based on repeated query params to guard + themselves against potential differences in the implementations. + maxLength: 256 minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ type: string - name: - description: Name is the name of the referent. - maxLength: 253 + type: + default: Exact + description: |- + Type specifies how to match against the value of the query parameter. + + + Support: Extended (Exact) + + + Support: Implementation-specific (RegularExpression) + + + Since RegularExpression QueryParamMatchType has Implementation-specific + conformance, implementations can support POSIX, PCRE or any other + dialects of regular expressions. Please read the implementation's + documentation to determine the supported dialect. + enum: + - Exact + - RegularExpression + type: string + value: + description: Value is the value of HTTP query param to be matched. + maxLength: 1024 minLength: 1 type: string required: - - group - - kind - - name + - name + - value type: object - requestHeaderModifier: - description: |- - RequestHeaderModifier defines a schema for a filter that modifies request - headers. - - - Support: Core - properties: - add: - description: |- - Add adds the given header(s) (name, value) to the request - before the action. It appends to any existing values associated - with the header name. - - - Input: - GET /foo HTTP/1.1 - my-header: foo - - - Config: - add: - - name: "my-header" - value: "bar,baz" - - - Output: - GET /foo HTTP/1.1 - my-header: foo,bar,baz - items: - description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. - properties: - name: - description: |- - Name is the name of the HTTP Header to be matched. Name matching MUST be - case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). - - - If multiple entries specify equivalent header names, the first entry with - an equivalent name MUST be considered for a match. Subsequent entries - with an equivalent header name MUST be ignored. Due to the - case-insensitivity of header names, "foo" and "Foo" are considered - equivalent. - maxLength: 256 - minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ - type: string - value: - description: Value is the value of HTTP Header to be matched. - maxLength: 4096 - minLength: 1 - type: string - required: - - name - - value - type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - remove: - description: |- - Remove the given header(s) from the HTTP request before the action. The - value of Remove is a list of HTTP header names. Note that the header - names are case-insensitive (see - https://datatracker.ietf.org/doc/html/rfc2616#section-4.2). - - - Input: - GET /foo HTTP/1.1 - my-header1: foo - my-header2: bar - my-header3: baz - - - Config: - remove: ["my-header1", "my-header3"] - - - Output: - GET /foo HTTP/1.1 - my-header2: bar - items: + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + type: object + maxItems: 8 + type: array + stableTraffic: + description: StableTraffic indicate the base traffic rule + properties: + filters: + description: |- + Filters define the filters that are applied to requests that match + this rule. + + + The effects of ordering of multiple behaviors are currently unspecified. + This can change in the future based on feedback during the alpha stage. + + + Conformance-levels at this level are defined based on the type of filter: + + + - ALL core filters MUST be supported by all implementations. + - Implementers are encouraged to support extended filters. + - Implementation-specific custom filters have no API guarantees across + implementations. + + + Specifying the same filter multiple times is not supported unless explicitly + indicated in the filter. + + + All filters are expected to be compatible with each other except for the + URLRewrite and RequestRedirect filters, which may not be combined. If an + implementation can not support other combinations of filters, they must clearly + document that limitation. In cases where incompatible or unsupported + filters are specified and cause the `Accepted` condition to be set to status + `False`, implementations may use the `IncompatibleFilters` reason to specify + this configuration error. + + + Support: Core + items: + description: |- + HTTPRouteFilter defines processing steps that must be completed during the + request or response lifecycle. HTTPRouteFilters are meant as an extension + point to express processing that may be done in Gateway implementations. Some + examples include request or response modification, implementing + authentication strategies, rate-limiting, and traffic shaping. API + guarantee/conformance is defined based on the type of the filter. + properties: + extensionRef: + description: |- + ExtensionRef is an optional, implementation-specific extension to the + "filter" behavior. For example, resource "myroutefilter" in group + "networking.example.net"). ExtensionRef MUST NOT be used for core and + extended filters. + + + This filter can be used multiple times within the same rule. + + + Support: Implementation-specific + properties: + group: + description: |- + Group is the group of the referent. For example, "gateway.networking.k8s.io". + When unspecified or empty string, core API group is inferred. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ type: string - maxItems: 16 - type: array - x-kubernetes-list-type: set - set: - description: |- - Set overwrites the request with the given header (name, value) - before the action. - - - Input: - GET /foo HTTP/1.1 - my-header: foo - - - Config: - set: - - name: "my-header" - value: "bar" - - - Output: - GET /foo HTTP/1.1 - my-header: bar - items: - description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. - properties: - name: - description: |- - Name is the name of the HTTP Header to be matched. Name matching MUST be - case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). - - - If multiple entries specify equivalent header names, the first entry with - an equivalent name MUST be considered for a match. Subsequent entries - with an equivalent header name MUST be ignored. Due to the - case-insensitivity of header names, "foo" and "Foo" are considered - equivalent. - maxLength: 256 - minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ - type: string - value: - description: Value is the value of HTTP Header to be matched. - maxLength: 4096 - minLength: 1 - type: string - required: - - name - - value - type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - type: object - requestMirror: - description: |- - RequestMirror defines a schema for a filter that mirrors requests. - Requests are sent to the specified destination, but responses from - that destination are ignored. - - - This filter can be used multiple times within the same rule. Note that - not all implementations will be able to support mirroring to multiple - backends. - - - Support: Extended - - - - properties: - backendRef: - description: |- - BackendRef references a resource where mirrored requests are sent. - - - Mirrored requests must be sent only to a single destination endpoint - within this BackendRef, irrespective of how many endpoints are present - within this BackendRef. - - - If the referent cannot be found, this BackendRef is invalid and must be - dropped from the Gateway. The controller must ensure the "ResolvedRefs" - condition on the Route status is set to `status: False` and not configure - this backend in the underlying implementation. - - - If there is a cross-namespace reference to an *existing* object - that is not allowed by a ReferenceGrant, the controller must ensure the - "ResolvedRefs" condition on the Route is set to `status: False`, - with the "RefNotPermitted" reason and not configure this backend in the - underlying implementation. - - - In either error case, the Message of the `ResolvedRefs` Condition - should be used to provide more detail about the problem. - - - Support: Extended for Kubernetes Service - - - Support: Implementation-specific for any other resource - properties: - group: - default: "" - description: |- - Group is the group of the referent. For example, "gateway.networking.k8s.io". - When unspecified or empty string, core API group is inferred. - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - default: Service - description: |- - Kind is the Kubernetes resource kind of the referent. For example - "Service". - - - Defaults to "Service" when not specified. - - - ExternalName services can refer to CNAME DNS records that may live - outside of the cluster and as such are difficult to reason about in - terms of conformance. They also may not be safe to forward to (see - CVE-2021-25740 for more information). Implementations SHOULD NOT - support ExternalName Services. - - - Support: Core (Services with a type other than ExternalName) - - - Support: Implementation-specific (Services with type ExternalName) - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - type: string - name: - description: Name is the name of the referent. - maxLength: 253 - minLength: 1 - type: string - namespace: - description: |- - Namespace is the namespace of the backend. When unspecified, the local - namespace is inferred. - - - Note that when a namespace different than the local namespace is specified, - a ReferenceGrant object is required in the referent namespace to allow that - namespace's owner to accept the reference. See the ReferenceGrant - documentation for details. - - - Support: Core - maxLength: 63 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ - type: string - port: - description: |- - Port specifies the destination port number to use for this resource. - Port is required when the referent is a Kubernetes Service. In this - case, the port number is the service port number, not the target port. - For other resources, destination port might be derived from the referent - resource or this field. - format: int32 - maximum: 65535 - minimum: 1 - type: integer - required: + kind: + description: Kind is kind of the referent. For example "HTTPRoute" or "Service". + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: Name is the name of the referent. + maxLength: 253 + minLength: 1 + type: string + required: + - group + - kind - name - type: object - fraction: - description: |- - Fraction represents the fraction of requests that should be - mirrored to BackendRef. - - - Only one of Fraction or Percent may be specified. If neither field - is specified, 100% of requests will be mirrored. - - - - properties: - denominator: - default: 100 - format: int32 - minimum: 1 - type: integer - numerator: - format: int32 - minimum: 0 - type: integer - required: - - numerator - type: object - percent: - description: |- - Percent represents the percentage of requests that should be - mirrored to BackendRef. Its minimum value is 0 (indicating 0% of - requests) and its maximum value is 100 (indicating 100% of requests). - - - Only one of Fraction or Percent may be specified. If neither field - is specified, 100% of requests will be mirrored. - - - - format: int32 - maximum: 100 - minimum: 0 - type: integer - required: - - backendRef - type: object - requestRedirect: - description: |- - RequestRedirect defines a schema for a filter that responds to the - request with an HTTP redirection. - - - Support: Core - properties: - hostname: - description: |- - Hostname is the hostname to be used in the value of the `Location` - header in the response. - When empty, the hostname in the `Host` header of the request is used. - - - Support: Core - maxLength: 253 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - path: - description: |- - Path defines parameters used to modify the path of the incoming request. - The modified path is then used to construct the `Location` header. When - empty, the request path is used as-is. - - - Support: Extended - properties: - replaceFullPath: - description: |- - ReplaceFullPath specifies the value with which to replace the full path - of a request during a rewrite or redirect. - maxLength: 1024 - type: string - replacePrefixMatch: - description: |- - ReplacePrefixMatch specifies the value with which to replace the prefix - match of a request during a rewrite or redirect. For example, a request - to "/foo/bar" with a prefix match of "/foo" and a ReplacePrefixMatch - of "/xyz" would be modified to "/xyz/bar". - - - Note that this matches the behavior of the PathPrefix match type. This - matches full path elements. A path element refers to the list of labels - in the path split by the `/` separator. When specified, a trailing `/` is - ignored. For example, the paths `/abc`, `/abc/`, and `/abc/def` would all - match the prefix `/abc`, but the path `/abcd` would not. - - - ReplacePrefixMatch is only compatible with a `PathPrefix` HTTPRouteMatch. - Using any other HTTPRouteMatch type on the same HTTPRouteRule will result in - the implementation setting the Accepted Condition for the Route to `status: False`. - - - Request Path | Prefix Match | Replace Prefix | Modified Path - -------------|--------------|----------------|---------- - /foo/bar | /foo | /xyz | /xyz/bar - /foo/bar | /foo | /xyz/ | /xyz/bar - /foo/bar | /foo/ | /xyz | /xyz/bar - /foo/bar | /foo/ | /xyz/ | /xyz/bar - /foo | /foo | /xyz | /xyz - /foo/ | /foo | /xyz | /xyz/ - /foo/bar | /foo | | /bar - /foo/ | /foo | | / - /foo | /foo | | / - /foo/ | /foo | / | / - /foo | /foo | / | / - maxLength: 1024 + type: object + requestHeaderModifier: + description: |- + RequestHeaderModifier defines a schema for a filter that modifies request + headers. + + + Support: Core + properties: + add: + description: |- + Add adds the given header(s) (name, value) to the request + before the action. It appends to any existing values associated + with the header name. + + + Input: + GET /foo HTTP/1.1 + my-header: foo + + + Config: + add: + - name: "my-header" + value: "bar,baz" + + + Output: + GET /foo HTTP/1.1 + my-header: foo,bar,baz + items: + description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + + If multiple entries specify equivalent header names, the first entry with + an equivalent name MUST be considered for a match. Subsequent entries + with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + description: Value is the value of HTTP Header to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + remove: + description: |- + Remove the given header(s) from the HTTP request before the action. The + value of Remove is a list of HTTP header names. Note that the header + names are case-insensitive (see + https://datatracker.ietf.org/doc/html/rfc2616#section-4.2). + + + Input: + GET /foo HTTP/1.1 + my-header1: foo + my-header2: bar + my-header3: baz + + + Config: + remove: ["my-header1", "my-header3"] + + + Output: + GET /foo HTTP/1.1 + my-header2: bar + items: type: string - type: - description: |- - Type defines the type of path modifier. Additional types may be - added in a future release of the API. - - - Note that values may be added to this enum, implementations - must ensure that unknown values will not cause a crash. - - - Unknown values here must result in the implementation setting the - Accepted Condition for the Route to `status: False`, with a - Reason of `UnsupportedValue`. - enum: - - ReplaceFullPath - - ReplacePrefixMatch + maxItems: 16 + type: array + x-kubernetes-list-type: set + set: + description: |- + Set overwrites the request with the given header (name, value) + before the action. + + + Input: + GET /foo HTTP/1.1 + my-header: foo + + + Config: + set: + - name: "my-header" + value: "bar" + + + Output: + GET /foo HTTP/1.1 + my-header: bar + items: + description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + + If multiple entries specify equivalent header names, the first entry with + an equivalent name MUST be considered for a match. Subsequent entries + with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + description: Value is the value of HTTP Header to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + type: object + requestMirror: + description: |- + RequestMirror defines a schema for a filter that mirrors requests. + Requests are sent to the specified destination, but responses from + that destination are ignored. + + + This filter can be used multiple times within the same rule. Note that + not all implementations will be able to support mirroring to multiple + backends. + + + Support: Extended + + + + properties: + backendRef: + description: |- + BackendRef references a resource where mirrored requests are sent. + + + Mirrored requests must be sent only to a single destination endpoint + within this BackendRef, irrespective of how many endpoints are present + within this BackendRef. + + + If the referent cannot be found, this BackendRef is invalid and must be + dropped from the Gateway. The controller must ensure the "ResolvedRefs" + condition on the Route status is set to `status: False` and not configure + this backend in the underlying implementation. + + + If there is a cross-namespace reference to an *existing* object + that is not allowed by a ReferenceGrant, the controller must ensure the + "ResolvedRefs" condition on the Route is set to `status: False`, + with the "RefNotPermitted" reason and not configure this backend in the + underlying implementation. + + + In either error case, the Message of the `ResolvedRefs` Condition + should be used to provide more detail about the problem. + + + Support: Extended for Kubernetes Service + + + Support: Implementation-specific for any other resource + properties: + group: + default: "" + description: |- + Group is the group of the referent. For example, "gateway.networking.k8s.io". + When unspecified or empty string, core API group is inferred. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + default: Service + description: |- + Kind is the Kubernetes resource kind of the referent. For example + "Service". + + + Defaults to "Service" when not specified. + + + ExternalName services can refer to CNAME DNS records that may live + outside of the cluster and as such are difficult to reason about in + terms of conformance. They also may not be safe to forward to (see + CVE-2021-25740 for more information). Implementations SHOULD NOT + support ExternalName Services. + + + Support: Core (Services with a type other than ExternalName) + + + Support: Implementation-specific (Services with type ExternalName) + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: Name is the name of the referent. + maxLength: 253 + minLength: 1 + type: string + namespace: + description: |- + Namespace is the namespace of the backend. When unspecified, the local + namespace is inferred. + + + Note that when a namespace different than the local namespace is specified, + a ReferenceGrant object is required in the referent namespace to allow that + namespace's owner to accept the reference. See the ReferenceGrant + documentation for details. + + + Support: Core + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + port: + description: |- + Port specifies the destination port number to use for this resource. + Port is required when the referent is a Kubernetes Service. In this + case, the port number is the service port number, not the target port. + For other resources, destination port might be derived from the referent + resource or this field. + format: int32 + maximum: 65535 + minimum: 1 + type: integer + required: + - name + type: object + fraction: + description: |- + Fraction represents the fraction of requests that should be + mirrored to BackendRef. + + + Only one of Fraction or Percent may be specified. If neither field + is specified, 100% of requests will be mirrored. + + + + properties: + denominator: + default: 100 + format: int32 + minimum: 1 + type: integer + numerator: + format: int32 + minimum: 0 + type: integer + required: + - numerator + type: object + percent: + description: |- + Percent represents the percentage of requests that should be + mirrored to BackendRef. Its minimum value is 0 (indicating 0% of + requests) and its maximum value is 100 (indicating 100% of requests). + + + Only one of Fraction or Percent may be specified. If neither field + is specified, 100% of requests will be mirrored. + + + + format: int32 + maximum: 100 + minimum: 0 + type: integer + required: + - backendRef + type: object + requestRedirect: + description: |- + RequestRedirect defines a schema for a filter that responds to the + request with an HTTP redirection. + + + Support: Core + properties: + hostname: + description: |- + Hostname is the hostname to be used in the value of the `Location` + header in the response. + When empty, the hostname in the `Host` header of the request is used. + + + Support: Core + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + path: + description: |- + Path defines parameters used to modify the path of the incoming request. + The modified path is then used to construct the `Location` header. When + empty, the request path is used as-is. + + + Support: Extended + properties: + replaceFullPath: + description: |- + ReplaceFullPath specifies the value with which to replace the full path + of a request during a rewrite or redirect. + maxLength: 1024 + type: string + replacePrefixMatch: + description: |- + ReplacePrefixMatch specifies the value with which to replace the prefix + match of a request during a rewrite or redirect. For example, a request + to "/foo/bar" with a prefix match of "/foo" and a ReplacePrefixMatch + of "/xyz" would be modified to "/xyz/bar". + + + Note that this matches the behavior of the PathPrefix match type. This + matches full path elements. A path element refers to the list of labels + in the path split by the `/` separator. When specified, a trailing `/` is + ignored. For example, the paths `/abc`, `/abc/`, and `/abc/def` would all + match the prefix `/abc`, but the path `/abcd` would not. + + + ReplacePrefixMatch is only compatible with a `PathPrefix` HTTPRouteMatch. + Using any other HTTPRouteMatch type on the same HTTPRouteRule will result in + the implementation setting the Accepted Condition for the Route to `status: False`. + + + Request Path | Prefix Match | Replace Prefix | Modified Path + -------------|--------------|----------------|---------- + /foo/bar | /foo | /xyz | /xyz/bar + /foo/bar | /foo | /xyz/ | /xyz/bar + /foo/bar | /foo/ | /xyz | /xyz/bar + /foo/bar | /foo/ | /xyz/ | /xyz/bar + /foo | /foo | /xyz | /xyz + /foo/ | /foo | /xyz | /xyz/ + /foo/bar | /foo | | /bar + /foo/ | /foo | | / + /foo | /foo | | / + /foo/ | /foo | / | / + /foo | /foo | / | / + maxLength: 1024 + type: string + type: + description: |- + Type defines the type of path modifier. Additional types may be + added in a future release of the API. + + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + enum: + - ReplaceFullPath + - ReplacePrefixMatch + type: string + required: + - type + type: object + port: + description: |- + Port is the port to be used in the value of the `Location` + header in the response. + + + If no port is specified, the redirect port MUST be derived using the + following rules: + + + * If redirect scheme is not-empty, the redirect port MUST be the well-known + port associated with the redirect scheme. Specifically "http" to port 80 + and "https" to port 443. If the redirect scheme does not have a + well-known port, the listener port of the Gateway SHOULD be used. + * If redirect scheme is empty, the redirect port MUST be the Gateway + Listener port. + + + Implementations SHOULD NOT add the port number in the 'Location' + header in the following cases: + + + * A Location header that will use HTTP (whether that is determined via + the Listener protocol or the Scheme field) _and_ use port 80. + * A Location header that will use HTTPS (whether that is determined via + the Listener protocol or the Scheme field) _and_ use port 443. + + + Support: Extended + format: int32 + maximum: 65535 + minimum: 1 + type: integer + scheme: + description: |- + Scheme is the scheme to be used in the value of the `Location` header in + the response. When empty, the scheme of the request is used. + + + Scheme redirects can affect the port of the redirect, for more information, + refer to the documentation for the port field of this filter. + + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + + + Support: Extended + enum: + - http + - https + type: string + statusCode: + default: 302 + description: |- + StatusCode is the HTTP status code to be used in response. + + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + + + Support: Core + enum: + - 301 + - 302 + type: integer + type: object + responseHeaderModifier: + description: |- + ResponseHeaderModifier defines a schema for a filter that modifies response + headers. + + + Support: Extended + properties: + add: + description: |- + Add adds the given header(s) (name, value) to the request + before the action. It appends to any existing values associated + with the header name. + + + Input: + GET /foo HTTP/1.1 + my-header: foo + + + Config: + add: + - name: "my-header" + value: "bar,baz" + + + Output: + GET /foo HTTP/1.1 + my-header: foo,bar,baz + items: + description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + + If multiple entries specify equivalent header names, the first entry with + an equivalent name MUST be considered for a match. Subsequent entries + with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + description: Value is the value of HTTP Header to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + remove: + description: |- + Remove the given header(s) from the HTTP request before the action. The + value of Remove is a list of HTTP header names. Note that the header + names are case-insensitive (see + https://datatracker.ietf.org/doc/html/rfc2616#section-4.2). + + + Input: + GET /foo HTTP/1.1 + my-header1: foo + my-header2: bar + my-header3: baz + + + Config: + remove: ["my-header1", "my-header3"] + + + Output: + GET /foo HTTP/1.1 + my-header2: bar + items: type: string - required: - - type - type: object - port: - description: |- - Port is the port to be used in the value of the `Location` - header in the response. - - - If no port is specified, the redirect port MUST be derived using the - following rules: - - - * If redirect scheme is not-empty, the redirect port MUST be the well-known - port associated with the redirect scheme. Specifically "http" to port 80 - and "https" to port 443. If the redirect scheme does not have a - well-known port, the listener port of the Gateway SHOULD be used. - * If redirect scheme is empty, the redirect port MUST be the Gateway - Listener port. - - - Implementations SHOULD NOT add the port number in the 'Location' - header in the following cases: - - - * A Location header that will use HTTP (whether that is determined via - the Listener protocol or the Scheme field) _and_ use port 80. - * A Location header that will use HTTPS (whether that is determined via - the Listener protocol or the Scheme field) _and_ use port 443. - - - Support: Extended - format: int32 - maximum: 65535 - minimum: 1 - type: integer - scheme: - description: |- - Scheme is the scheme to be used in the value of the `Location` header in - the response. When empty, the scheme of the request is used. - - - Scheme redirects can affect the port of the redirect, for more information, - refer to the documentation for the port field of this filter. - - - Note that values may be added to this enum, implementations - must ensure that unknown values will not cause a crash. - - - Unknown values here must result in the implementation setting the - Accepted Condition for the Route to `status: False`, with a - Reason of `UnsupportedValue`. - - - Support: Extended - enum: - - http - - https - type: string - statusCode: - default: 302 - description: |- - StatusCode is the HTTP status code to be used in response. - - - Note that values may be added to this enum, implementations - must ensure that unknown values will not cause a crash. - - - Unknown values here must result in the implementation setting the - Accepted Condition for the Route to `status: False`, with a - Reason of `UnsupportedValue`. - - - Support: Core - enum: - - 301 - - 302 - type: integer - type: object - responseHeaderModifier: - description: |- - ResponseHeaderModifier defines a schema for a filter that modifies response - headers. - - - Support: Extended - properties: - add: - description: |- - Add adds the given header(s) (name, value) to the request - before the action. It appends to any existing values associated - with the header name. - - - Input: - GET /foo HTTP/1.1 - my-header: foo - - - Config: - add: - - name: "my-header" - value: "bar,baz" - - - Output: - GET /foo HTTP/1.1 - my-header: foo,bar,baz - items: - description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. + maxItems: 16 + type: array + x-kubernetes-list-type: set + set: + description: |- + Set overwrites the request with the given header (name, value) + before the action. + + + Input: + GET /foo HTTP/1.1 + my-header: foo + + + Config: + set: + - name: "my-header" + value: "bar" + + + Output: + GET /foo HTTP/1.1 + my-header: bar + items: + description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + + If multiple entries specify equivalent header names, the first entry with + an equivalent name MUST be considered for a match. Subsequent entries + with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + description: Value is the value of HTTP Header to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + type: object + type: + description: |- + Type identifies the type of filter to apply. As with other API fields, + types are classified into three conformance levels: + + + - Core: Filter types and their corresponding configuration defined by + "Support: Core" in this package, e.g. "RequestHeaderModifier". All + implementations must support core filters. + + + - Extended: Filter types and their corresponding configuration defined by + "Support: Extended" in this package, e.g. "RequestMirror". Implementers + are encouraged to support extended filters. + + + - Implementation-specific: Filters that are defined and supported by + specific vendors. + In the future, filters showing convergence in behavior across multiple + implementations will be considered for inclusion in extended or core + conformance levels. Filter-specific configuration for such filters + is specified using the ExtensionRef field. `Type` should be set to + "ExtensionRef" for custom filters. + + + Implementers are encouraged to define custom implementation types to + extend the core API with implementation-specific behavior. + + + If a reference to a custom filter type cannot be resolved, the filter + MUST NOT be skipped. Instead, requests that would have been processed by + that filter MUST receive a HTTP error response. + + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + enum: + - RequestHeaderModifier + - ResponseHeaderModifier + - RequestMirror + - RequestRedirect + - URLRewrite + - ExtensionRef + type: string + urlRewrite: + description: |- + URLRewrite defines a schema for a filter that modifies a request during forwarding. + + + Support: Extended + properties: + hostname: + description: |- + Hostname is the value to be used to replace the Host header value during + forwarding. + + + Support: Extended + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + path: + description: |- + Path defines a path rewrite. + + + Support: Extended properties: - name: + replaceFullPath: description: |- - Name is the name of the HTTP Header to be matched. Name matching MUST be - case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). - - - If multiple entries specify equivalent header names, the first entry with - an equivalent name MUST be considered for a match. Subsequent entries - with an equivalent header name MUST be ignored. Due to the - case-insensitivity of header names, "foo" and "Foo" are considered - equivalent. - maxLength: 256 - minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ - type: string - value: - description: Value is the value of HTTP Header to be matched. - maxLength: 4096 - minLength: 1 + ReplaceFullPath specifies the value with which to replace the full path + of a request during a rewrite or redirect. + maxLength: 1024 type: string - required: - - name - - value - type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - remove: - description: |- - Remove the given header(s) from the HTTP request before the action. The - value of Remove is a list of HTTP header names. Note that the header - names are case-insensitive (see - https://datatracker.ietf.org/doc/html/rfc2616#section-4.2). - - - Input: - GET /foo HTTP/1.1 - my-header1: foo - my-header2: bar - my-header3: baz - - - Config: - remove: ["my-header1", "my-header3"] - - - Output: - GET /foo HTTP/1.1 - my-header2: bar - items: - type: string - maxItems: 16 - type: array - x-kubernetes-list-type: set - set: - description: |- - Set overwrites the request with the given header (name, value) - before the action. - - - Input: - GET /foo HTTP/1.1 - my-header: foo - - - Config: - set: - - name: "my-header" - value: "bar" - - - Output: - GET /foo HTTP/1.1 - my-header: bar - items: - description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. - properties: - name: + replacePrefixMatch: description: |- - Name is the name of the HTTP Header to be matched. Name matching MUST be - case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). - - - If multiple entries specify equivalent header names, the first entry with - an equivalent name MUST be considered for a match. Subsequent entries - with an equivalent header name MUST be ignored. Due to the - case-insensitivity of header names, "foo" and "Foo" are considered - equivalent. - maxLength: 256 - minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + ReplacePrefixMatch specifies the value with which to replace the prefix + match of a request during a rewrite or redirect. For example, a request + to "/foo/bar" with a prefix match of "/foo" and a ReplacePrefixMatch + of "/xyz" would be modified to "/xyz/bar". + + + Note that this matches the behavior of the PathPrefix match type. This + matches full path elements. A path element refers to the list of labels + in the path split by the `/` separator. When specified, a trailing `/` is + ignored. For example, the paths `/abc`, `/abc/`, and `/abc/def` would all + match the prefix `/abc`, but the path `/abcd` would not. + + + ReplacePrefixMatch is only compatible with a `PathPrefix` HTTPRouteMatch. + Using any other HTTPRouteMatch type on the same HTTPRouteRule will result in + the implementation setting the Accepted Condition for the Route to `status: False`. + + + Request Path | Prefix Match | Replace Prefix | Modified Path + -------------|--------------|----------------|---------- + /foo/bar | /foo | /xyz | /xyz/bar + /foo/bar | /foo | /xyz/ | /xyz/bar + /foo/bar | /foo/ | /xyz | /xyz/bar + /foo/bar | /foo/ | /xyz/ | /xyz/bar + /foo | /foo | /xyz | /xyz + /foo/ | /foo | /xyz | /xyz/ + /foo/bar | /foo | | /bar + /foo/ | /foo | | / + /foo | /foo | | / + /foo/ | /foo | / | / + /foo | /foo | / | / + maxLength: 1024 type: string - value: - description: Value is the value of HTTP Header to be matched. - maxLength: 4096 - minLength: 1 + type: + description: |- + Type defines the type of path modifier. Additional types may be + added in a future release of the API. + + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + enum: + - ReplaceFullPath + - ReplacePrefixMatch type: string required: - - name - - value + - type type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - type: object - type: - description: |- - Type identifies the type of filter to apply. As with other API fields, - types are classified into three conformance levels: - - - - Core: Filter types and their corresponding configuration defined by - "Support: Core" in this package, e.g. "RequestHeaderModifier". All - implementations must support core filters. - - - - Extended: Filter types and their corresponding configuration defined by - "Support: Extended" in this package, e.g. "RequestMirror". Implementers - are encouraged to support extended filters. - - - - Implementation-specific: Filters that are defined and supported by - specific vendors. - In the future, filters showing convergence in behavior across multiple - implementations will be considered for inclusion in extended or core - conformance levels. Filter-specific configuration for such filters - is specified using the ExtensionRef field. `Type` should be set to - "ExtensionRef" for custom filters. - - - Implementers are encouraged to define custom implementation types to - extend the core API with implementation-specific behavior. - - - If a reference to a custom filter type cannot be resolved, the filter - MUST NOT be skipped. Instead, requests that would have been processed by - that filter MUST receive a HTTP error response. - - - Note that values may be added to this enum, implementations - must ensure that unknown values will not cause a crash. - - - Unknown values here must result in the implementation setting the - Accepted Condition for the Route to `status: False`, with a - Reason of `UnsupportedValue`. - enum: - - RequestHeaderModifier - - ResponseHeaderModifier - - RequestMirror - - RequestRedirect - - URLRewrite - - ExtensionRef - type: string - urlRewrite: - description: |- - URLRewrite defines a schema for a filter that modifies a request during forwarding. - - - Support: Extended - properties: - hostname: - description: |- - Hostname is the value to be used to replace the Host header value during - forwarding. - - - Support: Extended - maxLength: 253 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - path: + type: object + required: + - type + type: object + maxItems: 16 + type: array + matches: + description: |- + Matches define conditions used for matching the rule against incoming + HTTP requests. Each match is independent, i.e. this rule will be matched + if **any** one of the matches is satisfied. + + + For example, take the following matches configuration: + + + ``` + matches: + - path: + value: "/foo" + headers: + - name: "version" + value: "v2" + - path: + value: "/v2/foo" + ``` + + + For a request to match against this rule, a request must satisfy + EITHER of the two conditions: + + + - path prefixed with `/foo` AND contains the header `version: v2` + - path prefix of `/v2/foo` + + + See the documentation for HTTPRouteMatch on how to specify multiple + match conditions that should be ANDed together. + + + If no matches are specified, the default is a prefix + path match on "/", which has the effect of matching every + HTTP request. + + + Proxy or Load Balancer routing configuration generated from HTTPRoutes + MUST prioritize matches based on the following criteria, continuing on + ties. Across all rules specified on applicable Routes, precedence must be + given to the match having: + + + * "Exact" path match. + * "Prefix" path match with largest number of characters. + * Method match. + * Largest number of header matches. + * Largest number of query param matches. + + + Note: The precedence of RegularExpression path matches are implementation-specific. + + + If ties still exist across multiple Routes, matching precedence MUST be + determined in order of the following criteria, continuing on ties: + + + * The oldest Route based on creation timestamp. + * The Route appearing first in alphabetical order by + "{namespace}/{name}". + + + If ties still exist within an HTTPRoute, matching precedence MUST be granted + to the FIRST matching rule (in list order) with a match meeting the above + criteria. + + + When no rules matching a request have been successfully attached to the + parent a request is coming from, a HTTP 404 status code MUST be returned. + items: + properties: + headers: + description: |- + Headers specifies HTTP request header matchers. Multiple match values are + ANDed together, meaning, a request must match all the specified headers + to select the route. + items: description: |- - Path defines a path rewrite. - - - Support: Extended + HTTPHeaderMatch describes how to select a HTTP route by matching HTTP request + headers. properties: - replaceFullPath: - description: |- - ReplaceFullPath specifies the value with which to replace the full path - of a request during a rewrite or redirect. - maxLength: 1024 - type: string - replacePrefixMatch: + name: description: |- - ReplacePrefixMatch specifies the value with which to replace the prefix - match of a request during a rewrite or redirect. For example, a request - to "/foo/bar" with a prefix match of "/foo" and a ReplacePrefixMatch - of "/xyz" would be modified to "/xyz/bar". - - - Note that this matches the behavior of the PathPrefix match type. This - matches full path elements. A path element refers to the list of labels - in the path split by the `/` separator. When specified, a trailing `/` is - ignored. For example, the paths `/abc`, `/abc/`, and `/abc/def` would all - match the prefix `/abc`, but the path `/abcd` would not. - - - ReplacePrefixMatch is only compatible with a `PathPrefix` HTTPRouteMatch. - Using any other HTTPRouteMatch type on the same HTTPRouteRule will result in - the implementation setting the Accepted Condition for the Route to `status: False`. - - - Request Path | Prefix Match | Replace Prefix | Modified Path - -------------|--------------|----------------|---------- - /foo/bar | /foo | /xyz | /xyz/bar - /foo/bar | /foo | /xyz/ | /xyz/bar - /foo/bar | /foo/ | /xyz | /xyz/bar - /foo/bar | /foo/ | /xyz/ | /xyz/bar - /foo | /foo | /xyz | /xyz - /foo/ | /foo | /xyz | /xyz/ - /foo/bar | /foo | | /bar - /foo/ | /foo | | / - /foo | /foo | | / - /foo/ | /foo | / | / - /foo | /foo | / | / - maxLength: 1024 + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + + If multiple entries specify equivalent header names, only the first + entry with an equivalent name MUST be considered for a match. Subsequent + entries with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + + + When a header is repeated in an HTTP request, it is + implementation-specific behavior as to how this is represented. + Generally, proxies should follow the guidance from the RFC: + https://www.rfc-editor.org/rfc/rfc7230.html#section-3.2.2 regarding + processing a repeated header, with special handling for "Set-Cookie". + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ type: string type: + default: Exact description: |- - Type defines the type of path modifier. Additional types may be - added in a future release of the API. - - - Note that values may be added to this enum, implementations - must ensure that unknown values will not cause a crash. - - - Unknown values here must result in the implementation setting the - Accepted Condition for the Route to `status: False`, with a - Reason of `UnsupportedValue`. + Type specifies how to match against the value of the header. + + + Support: Core (Exact) + + + Support: Implementation-specific (RegularExpression) + + + Since RegularExpression HeaderMatchType has implementation-specific + conformance, implementations can support POSIX, PCRE or any other dialects + of regular expressions. Please read the implementation's documentation to + determine the supported dialect. enum: - - ReplaceFullPath - - ReplacePrefixMatch + - Exact + - RegularExpression + type: string + value: + description: Value is the value of HTTP Header to be matched. + maxLength: 4096 + minLength: 1 type: string required: - - type + - name + - value type: object - type: object - required: - - type - type: object - maxItems: 16 - type: array - matches: - description: |- - Matches define conditions used for matching the rule against incoming - HTTP requests. Each match is independent, i.e. this rule will be matched - if **any** one of the matches is satisfied. - - - For example, take the following matches configuration: - - - ``` - matches: - - path: - value: "/foo" - headers: - - name: "version" - value: "v2" - - path: - value: "/v2/foo" - ``` - - - For a request to match against this rule, a request must satisfy - EITHER of the two conditions: - - - - path prefixed with `/foo` AND contains the header `version: v2` - - path prefix of `/v2/foo` - - - See the documentation for HTTPRouteMatch on how to specify multiple - match conditions that should be ANDed together. - - - If no matches are specified, the default is a prefix - path match on "/", which has the effect of matching every - HTTP request. - - - Proxy or Load Balancer routing configuration generated from HTTPRoutes - MUST prioritize matches based on the following criteria, continuing on - ties. Across all rules specified on applicable Routes, precedence must be - given to the match having: - - - * "Exact" path match. - * "Prefix" path match with largest number of characters. - * Method match. - * Largest number of header matches. - * Largest number of query param matches. - - - Note: The precedence of RegularExpression path matches are implementation-specific. - - - If ties still exist across multiple Routes, matching precedence MUST be - determined in order of the following criteria, continuing on ties: - - - * The oldest Route based on creation timestamp. - * The Route appearing first in alphabetical order by - "{namespace}/{name}". - - - If ties still exist within an HTTPRoute, matching precedence MUST be granted - to the FIRST matching rule (in list order) with a match meeting the above - criteria. - - - When no rules matching a request have been successfully attached to the - parent a request is coming from, a HTTP 404 status code MUST be returned. - items: - properties: - headers: - description: |- - Headers specifies HTTP request header matchers. Multiple match values are - ANDed together, meaning, a request must match all the specified headers - to select the route. - items: - description: |- - HTTPHeaderMatch describes how to select a HTTP route by matching HTTP request - headers. - properties: - name: - description: |- - Name is the name of the HTTP Header to be matched. Name matching MUST be - case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). - - - If multiple entries specify equivalent header names, only the first - entry with an equivalent name MUST be considered for a match. Subsequent - entries with an equivalent header name MUST be ignored. Due to the - case-insensitivity of header names, "foo" and "Foo" are considered - equivalent. - - - When a header is repeated in an HTTP request, it is - implementation-specific behavior as to how this is represented. - Generally, proxies should follow the guidance from the RFC: - https://www.rfc-editor.org/rfc/rfc7230.html#section-3.2.2 regarding - processing a repeated header, with special handling for "Set-Cookie". - maxLength: 256 - minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ - type: string - type: - default: Exact - description: |- - Type specifies how to match against the value of the header. - - - Support: Core (Exact) - - - Support: Implementation-specific (RegularExpression) - - - Since RegularExpression HeaderMatchType has implementation-specific - conformance, implementations can support POSIX, PCRE or any other dialects - of regular expressions. Please read the implementation's documentation to - determine the supported dialect. - enum: - - Exact - - RegularExpression - type: string - value: - description: Value is the value of HTTP Header to be matched. - maxLength: 4096 - minLength: 1 - type: string - required: - - name - - value - type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - path: - description: Path specifies a HTTP request path matcher. - properties: - type: - default: PathPrefix - description: |- - Type specifies how to match against the path Value. - - - Support: Core (Exact, PathPrefix) - - - Support: Implementation-specific (RegularExpression) - enum: - - Exact - - PathPrefix - - RegularExpression - type: string - value: - default: / - description: Value of the HTTP path to match against. - maxLength: 1024 - type: string - type: object - queryParams: - description: |- - QueryParams specifies HTTP query parameter matchers. Multiple match - values are ANDed together, meaning, a request must match all the - specified query parameters to select the route. - - - Support: Extended - items: - description: |- - HTTPQueryParamMatch describes how to select a HTTP route by matching HTTP - query parameters. + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + path: + description: Path specifies a HTTP request path matcher. properties: - name: - description: |- - Name is the name of the HTTP query param to be matched. This must be an - exact string match. (See - https://tools.ietf.org/html/rfc7230#section-2.7.3). - - - If multiple entries specify equivalent query param names, only the first - entry with an equivalent name MUST be considered for a match. Subsequent - entries with an equivalent query param name MUST be ignored. - - - If a query param is repeated in an HTTP request, the behavior is - purposely left undefined, since different data planes have different - capabilities. However, it is *recommended* that implementations should - match against the first value of the param if the data plane supports it, - as this behavior is expected in other load balancing contexts outside of - the Gateway API. - - - Users SHOULD NOT route traffic based on repeated query params to guard - themselves against potential differences in the implementations. - maxLength: 256 - minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ - type: string type: - default: Exact + default: PathPrefix description: |- - Type specifies how to match against the value of the query parameter. - - - Support: Extended (Exact) - - + Type specifies how to match against the path Value. + + + Support: Core (Exact, PathPrefix) + + Support: Implementation-specific (RegularExpression) - - - Since RegularExpression QueryParamMatchType has Implementation-specific - conformance, implementations can support POSIX, PCRE or any other - dialects of regular expressions. Please read the implementation's - documentation to determine the supported dialect. enum: - - Exact - - RegularExpression + - Exact + - PathPrefix + - RegularExpression type: string value: - description: Value is the value of HTTP query param to be matched. + default: / + description: Value of the HTTP path to match against. maxLength: 1024 - minLength: 1 type: string - required: - - name - - value type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - type: object - maxItems: 8 - type: array - type: object - weight: - description: Weight indicate how many percentage of traffic the canary pods should receive + queryParams: + description: |- + QueryParams specifies HTTP query parameter matchers. Multiple match + values are ANDed together, meaning, a request must match all the + specified query parameters to select the route. + + + Support: Extended + items: + description: |- + HTTPQueryParamMatch describes how to select a HTTP route by matching HTTP + query parameters. + properties: + name: + description: |- + Name is the name of the HTTP query param to be matched. This must be an + exact string match. (See + https://tools.ietf.org/html/rfc7230#section-2.7.3). + + + If multiple entries specify equivalent query param names, only the first + entry with an equivalent name MUST be considered for a match. Subsequent + entries with an equivalent query param name MUST be ignored. + + + If a query param is repeated in an HTTP request, the behavior is + purposely left undefined, since different data planes have different + capabilities. However, it is *recommended* that implementations should + match against the first value of the param if the data plane supports it, + as this behavior is expected in other load balancing contexts outside of + the Gateway API. + + + Users SHOULD NOT route traffic based on repeated query params to guard + themselves against potential differences in the implementations. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + type: + default: Exact + description: |- + Type specifies how to match against the value of the query parameter. + + + Support: Extended (Exact) + + + Support: Implementation-specific (RegularExpression) + + + Since RegularExpression QueryParamMatchType has Implementation-specific + conformance, implementations can support POSIX, PCRE or any other + dialects of regular expressions. Please read the implementation's + documentation to determine the supported dialect. + enum: + - Exact + - RegularExpression + type: string + value: + description: Value is the value of HTTP query param to be matched. + maxLength: 1024 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + type: object + maxItems: 8 + type: array + type: object + weight: + description: Weight indicate how many percentage of traffic the canary pods should receive + format: int32 + maximum: 100 + minimum: 0 + type: integer + type: object + type: object + required: + - targets + type: object + targetType: + description: TargetType defines the GroupVersionKind of target resource + properties: + apiVersion: + description: |- + APIVersion is the group/version for the resource being referenced. + If APIVersion is not specified, the specified Kind must be in the core API group. + For any other third-party types, APIVersion is required. + type: string + kind: + description: Kind is the type of resource being referenced + type: string + required: + - kind + type: object + trafficTopologyRefs: + description: |- + TrafficTopologyRefs defines the networking traffic relationships between + workloads, backend services, and routes. + items: + type: string + type: array + webhooks: + description: Webhooks defines rollout webhook configuration + items: + properties: + clientConfig: + description: |- + ClientConfig defines how to communicate with the hook. + Required + properties: + caBundle: + description: |- + `caBundle` is a PEM encoded CA bundle which will be used to validate the webhook's server certificate. + If unspecified, system trust roots' CA on the node. + format: byte + type: string + periodSeconds: + default: 10 + description: |- + How often (in seconds) to perform the probe. + Default to 10 seconds. Minimum value is 1. + format: int32 + minimum: 1 + type: integer + timeoutSeconds: + default: 10 + description: |- + TimeoutSeconds specifies the timeout for this webhook. After the timeout passes, + the webhook call will be ignored or the API call will fail based on the + failure policy. format: int32 - maximum: 100 - minimum: 0 type: integer + url: + description: |- + `url` gives the location of the webhook, in standard URL form + (`scheme://host:port/path`). Exactly one of `url` or `service` + must be specified. + + + The `host` should not refer to a service running in the cluster; use + the `service` field instead. The host might be resolved via external + DNS in some apiservers (e.g., `kube-apiserver` cannot resolve + in-cluster DNS as that would be a layering violation). `host` may + also be an IP address. + + + Please note that using `localhost` or `127.0.0.1` as a `host` is + risky unless you take great care to run this webhook on all hosts + which run an apiserver which might need to make calls to this + webhook. Such installs are likely to be non-portable, i.e., not easy + to turn up in a new cluster. + + + The scheme must be "https"; the URL must begin with "https://". + + + A path is optional, and if present may be any string permissible in + a URL. You may use the path to pass an arbitrary string to the + webhook, for example, a cluster identifier. + + + Attempting to use a user or basic auth e.g. "user:password@" is not + allowed. Fragments ("#...") and query parameters ("?...") are not + allowed, either. + type: string type: object - type: object - required: - - targets - type: object - targetType: - description: TargetType defines the GroupVersionKind of target resource - properties: - apiVersion: - description: |- - APIVersion is the group/version for the resource being referenced. - If APIVersion is not specified, the specified Kind must be in the core API group. - For any other third-party types, APIVersion is required. - type: string - kind: - description: Kind is the type of resource being referenced - type: string - required: - - kind - type: object - trafficTopologyRefs: - description: |- - TrafficTopologyRefs defines the networking traffic relationships between - workloads, backend services, and routes. - items: - type: string - type: array - webhooks: - description: Webhooks defines rollout webhook configuration - items: - properties: - clientConfig: - description: |- - ClientConfig defines how to communicate with the hook. - Required - properties: - caBundle: - description: |- - `caBundle` is a PEM encoded CA bundle which will be used to validate the webhook's server certificate. - If unspecified, system trust roots' CA on the node. - format: byte + failurePolicy: + description: |- + FailurePolicy defines how unrecognized errors from the admission endpoint are handled - + allowed values are Ignore or Fail. Defaults to Ignore. + type: string + failureThreshold: + default: 3 + description: |- + Minimum consecutive failures for the probe to be considered failed after having succeeded. + Defaults to 3. Minimum value is 1. + format: int32 + minimum: 1 + type: integer + hookTypes: + description: |- + HookTypes defines when to communicate with the hook, specifies the types of events + that trigger the webhook. + Required + items: + description: Webhook type type: string - periodSeconds: - default: 10 - description: |- - How often (in seconds) to perform the probe. - Default to 10 seconds. Minimum value is 1. - format: int32 - minimum: 1 - type: integer - timeoutSeconds: - default: 10 - description: |- - TimeoutSeconds specifies the timeout for this webhook. After the timeout passes, - the webhook call will be ignored or the API call will fail based on the - failure policy. - format: int32 - type: integer - url: - description: |- - `url` gives the location of the webhook, in standard URL form - (`scheme://host:port/path`). Exactly one of `url` or `service` - must be specified. - - - The `host` should not refer to a service running in the cluster; use - the `service` field instead. The host might be resolved via external - DNS in some apiservers (e.g., `kube-apiserver` cannot resolve - in-cluster DNS as that would be a layering violation). `host` may - also be an IP address. - - - Please note that using `localhost` or `127.0.0.1` as a `host` is - risky unless you take great care to run this webhook on all hosts - which run an apiserver which might need to make calls to this - webhook. Such installs are likely to be non-portable, i.e., not easy - to turn up in a new cluster. - - - The scheme must be "https"; the URL must begin with "https://". - - - A path is optional, and if present may be any string permissible in - a URL. You may use the path to pass an arbitrary string to the - webhook, for example, a cluster identifier. - - - Attempting to use a user or basic auth e.g. "user:password@" is not - allowed. Fragments ("#...") and query parameters ("?...") are not - allowed, either. + type: array + name: + description: Name is the identity of webhook + type: string + properties: + additionalProperties: type: string - type: object - failurePolicy: - description: |- - FailurePolicy defines how unrecognized errors from the admission endpoint are handled - - allowed values are Ignore or Fail. Defaults to Ignore. - type: string - failureThreshold: - default: 3 - description: |- - Minimum consecutive failures for the probe to be considered failed after having succeeded. - Defaults to 3. Minimum value is 1. + description: Properties provide additional data for webhook. + type: object + provider: + description: |- + By default, rollout communicates with the webhook through the structure RolloutWebhookReview. + If provider is set, then the protocol of the interaction will be determined by the provider + type: string + type: object + type: array + type: object + status: + properties: + batchStatus: + description: BatchStatus describes the state of the active batch release + properties: + currentBatchIndex: + description: CurrentBatchIndex defines the current batch index of batch release progress. format: int32 - minimum: 1 type: integer - hookTypes: - description: |- - HookTypes defines when to communicate with the hook, specifies the types of events - that trigger the webhook. - Required + currentBatchState: + description: CurrentBatchState indicates the current batch state. + type: string + records: + description: Records contains all batches status details. items: - description: Webhook type - type: string + properties: + finishTime: + description: FinishTime is the time when the stage finished + format: date-time + type: string + index: + description: Index is the id of the batch + format: int32 + type: integer + startTime: + description: StartTime is the time when the stage started + format: date-time + type: string + state: + description: State is Rollout step state + type: string + targets: + description: WorkloadDetails contains release details for each workload + items: + properties: + availableReplicas: + description: AvailableReplicas is the number of service available pods targeted by workload. + format: int32 + type: integer + cluster: + description: Cluster defines which cluster the workload is in. + type: string + generation: + description: Generation is the found in workload metadata. + format: int64 + type: integer + name: + description: Name is the workload name + type: string + observedGeneration: + description: ObservedGeneration is the most recent generation observed for this workload. + format: int64 + type: integer + replicas: + description: Replicas is the desired number of pods targeted by workload + format: int32 + type: integer + stableRevision: + description: StableRevision is the old stable revision used to generate pods. + type: string + updatedAvailableReplicas: + description: UpdatedAvailableReplicas is the number of service available pods targeted by workload that have the updated template spec. + format: int32 + type: integer + updatedReadyReplicas: + description: UpdatedReadyReplicas is the number of ready pods targeted by workload that have the updated template spec. + format: int32 + type: integer + updatedReplicas: + description: UpdatedReplicas is the number of pods targeted by workload that have the updated template spec. + format: int32 + type: integer + updatedRevision: + description: UpdatedRevision is the updated template revision used to generate pods. + type: string + type: object + type: array + webhooks: + description: Webhooks contains webhook status + items: + properties: + code: + description: Code is a globally unique identifier + type: string + failureCount: + description: Failure count + format: int32 + type: integer + finishTime: + description: FinishTime is the time when the hook finished + format: date-time + type: string + hookType: + description: Webhook Type + type: string + message: + description: A human-readable message indicating details about the transition. + type: string + name: + description: Webhook Name + type: string + reason: + description: A human-readable short word + type: string + startTime: + description: StartTime is the time when the hook started + format: date-time + type: string + state: + description: Current webhook worker state + type: string + type: object + type: array + type: object type: array - name: - description: Name is the identity of webhook - type: string - properties: - additionalProperties: - type: string - description: Properties provide additional data for webhook. - type: object - provider: - description: |- - By default, rollout communicates with the webhook through the structure RolloutWebhookReview. - If provider is set, then the protocol of the interaction will be determined by the provider - type: string + required: + - currentBatchIndex type: object - type: array - type: object - status: - properties: - batchStatus: - description: BatchStatus describes the state of the active batch release - properties: - currentBatchIndex: - description: CurrentBatchIndex defines the current batch index of batch release progress. - format: int32 - type: integer - currentBatchState: - description: CurrentBatchState indicates the current batch state. - type: string - records: - description: Records contains all batches status details. - items: - properties: - finishTime: - description: FinishTime is the time when the stage finished - format: date-time - type: string - index: - description: Index is the id of the batch - format: int32 - type: integer - startTime: - description: StartTime is the time when the stage started - format: date-time - type: string - state: - description: State is Rollout step state - type: string - targets: - description: WorkloadDetails contains release details for each workload - items: - properties: - availableReplicas: - description: AvailableReplicas is the number of service available pods targeted by workload. - format: int32 - type: integer - cluster: - description: Cluster defines which cluster the workload is in. - type: string - generation: - description: Generation is the found in workload metadata. - format: int64 - type: integer - name: - description: Name is the workload name - type: string - observedGeneration: - description: ObservedGeneration is the most recent generation observed for this workload. - format: int64 - type: integer - replicas: - description: Replicas is the desired number of pods targeted by workload - format: int32 - type: integer - stableRevision: - description: StableRevision is the old stable revision used to generate pods. - type: string - updatedAvailableReplicas: - description: UpdatedAvailableReplicas is the number of service available pods targeted by workload that have the updated template spec. - format: int32 - type: integer - updatedReadyReplicas: - description: UpdatedReadyReplicas is the number of ready pods targeted by workload that have the updated template spec. - format: int32 - type: integer - updatedReplicas: - description: UpdatedReplicas is the number of pods targeted by workload that have the updated template spec. - format: int32 - type: integer - updatedRevision: - description: UpdatedRevision is the updated template revision used to generate pods. - type: string - required: - - replicas - - updatedAvailableReplicas - - updatedReadyReplicas - - updatedReplicas - type: object - type: array - webhooks: - description: Webhooks contains webhook status - items: - properties: - code: - description: Code is a globally unique identifier - type: string - failureCount: - description: Failure count - format: int32 - type: integer - finishTime: - description: FinishTime is the time when the hook finished - format: date-time - type: string - hookType: - description: Webhook Type - type: string - message: - description: A human-readable message indicating details about the transition. - type: string - name: - description: Webhook Name - type: string - reason: - description: A human-readable short word - type: string - startTime: - description: StartTime is the time when the hook started - format: date-time - type: string - state: - description: Current webhook worker state - type: string - type: object - type: array - type: object - type: array - required: - - currentBatchIndex - type: object - canaryStatus: - description: CanaryStatus describes the state of the active canary release - properties: - finishTime: - description: FinishTime is the time when the stage finished - format: date-time - type: string - index: - description: Index is the id of the batch - format: int32 - type: integer - startTime: - description: StartTime is the time when the stage started - format: date-time - type: string - state: - description: State is Rollout step state - type: string - targets: - description: WorkloadDetails contains release details for each workload - items: - properties: - availableReplicas: - description: AvailableReplicas is the number of service available pods targeted by workload. - format: int32 - type: integer - cluster: - description: Cluster defines which cluster the workload is in. - type: string - generation: - description: Generation is the found in workload metadata. - format: int64 - type: integer - name: - description: Name is the workload name - type: string - observedGeneration: - description: ObservedGeneration is the most recent generation observed for this workload. - format: int64 - type: integer - replicas: - description: Replicas is the desired number of pods targeted by workload - format: int32 - type: integer - stableRevision: - description: StableRevision is the old stable revision used to generate pods. - type: string - updatedAvailableReplicas: - description: UpdatedAvailableReplicas is the number of service available pods targeted by workload that have the updated template spec. - format: int32 - type: integer - updatedReadyReplicas: - description: UpdatedReadyReplicas is the number of ready pods targeted by workload that have the updated template spec. - format: int32 - type: integer - updatedReplicas: - description: UpdatedReplicas is the number of pods targeted by workload that have the updated template spec. - format: int32 - type: integer - updatedRevision: - description: UpdatedRevision is the updated template revision used to generate pods. - type: string - required: - - replicas - - updatedAvailableReplicas - - updatedReadyReplicas - - updatedReplicas - type: object - type: array - webhooks: - description: Webhooks contains webhook status - items: - properties: - code: - description: Code is a globally unique identifier - type: string - failureCount: - description: Failure count - format: int32 - type: integer - finishTime: - description: FinishTime is the time when the hook finished - format: date-time - type: string - hookType: - description: Webhook Type - type: string - message: - description: A human-readable message indicating details about the transition. - type: string - name: - description: Webhook Name - type: string - reason: - description: A human-readable short word - type: string - startTime: - description: StartTime is the time when the hook started - format: date-time - type: string - state: - description: Current webhook worker state - type: string - type: object - type: array - type: object - conditions: - description: Conditions is the list of conditions - items: - description: |- - Condition defines the condition of a resource - See: https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#typical-status-properties + canaryStatus: + description: CanaryStatus describes the state of the active canary release properties: - lastTransitionTime: - description: Last time the condition transitioned from one status to another. + finishTime: + description: FinishTime is the time when the stage finished format: date-time type: string - lastUpdateTime: - description: The last time this condition was updated. + index: + description: Index is the id of the batch + format: int32 + type: integer + startTime: + description: StartTime is the time when the stage started format: date-time type: string - message: - description: A human-readable message indicating details about the transition. - type: string - reason: - description: The reason for the condition's last transition. - type: string - status: - description: Status of the condition, one of True, False, Unknown. + state: + description: State is Rollout step state type: string - type: - description: Type of the condition. - type: string - required: - - status - - type + targets: + description: WorkloadDetails contains release details for each workload + items: + properties: + availableReplicas: + description: AvailableReplicas is the number of service available pods targeted by workload. + format: int32 + type: integer + cluster: + description: Cluster defines which cluster the workload is in. + type: string + generation: + description: Generation is the found in workload metadata. + format: int64 + type: integer + name: + description: Name is the workload name + type: string + observedGeneration: + description: ObservedGeneration is the most recent generation observed for this workload. + format: int64 + type: integer + replicas: + description: Replicas is the desired number of pods targeted by workload + format: int32 + type: integer + stableRevision: + description: StableRevision is the old stable revision used to generate pods. + type: string + updatedAvailableReplicas: + description: UpdatedAvailableReplicas is the number of service available pods targeted by workload that have the updated template spec. + format: int32 + type: integer + updatedReadyReplicas: + description: UpdatedReadyReplicas is the number of ready pods targeted by workload that have the updated template spec. + format: int32 + type: integer + updatedReplicas: + description: UpdatedReplicas is the number of pods targeted by workload that have the updated template spec. + format: int32 + type: integer + updatedRevision: + description: UpdatedRevision is the updated template revision used to generate pods. + type: string + type: object + type: array + webhooks: + description: Webhooks contains webhook status + items: + properties: + code: + description: Code is a globally unique identifier + type: string + failureCount: + description: Failure count + format: int32 + type: integer + finishTime: + description: FinishTime is the time when the hook finished + format: date-time + type: string + hookType: + description: Webhook Type + type: string + message: + description: A human-readable message indicating details about the transition. + type: string + name: + description: Webhook Name + type: string + reason: + description: A human-readable short word + type: string + startTime: + description: StartTime is the time when the hook started + format: date-time + type: string + state: + description: Current webhook worker state + type: string + type: object + type: array type: object - type: array - error: - description: Error indicates the error info of progressing - properties: - code: - description: Code is a globally unique identifier - type: string - message: - description: A human-readable message indicating details about the transition. - type: string - reason: - description: A human-readable short word - type: string - type: object - lastUpdateTime: - description: The last time this status was updated. - format: date-time - type: string - observedGeneration: - description: |- - ObservedGeneration is the most recent generation observed for this Rollout. It corresponds to the - Rollout's generation, which is updated on mutation by the API Server. - format: int64 - type: integer - phase: - description: Phase indecates the current phase of rollout - type: string - targetStatuses: - description: TargetStatuses describes the referenced workloads status - items: + conditions: + description: Conditions is the list of conditions + items: + description: |- + Condition defines the condition of a resource + See: https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#typical-status-properties + properties: + lastTransitionTime: + description: Last time the condition transitioned from one status to another. + format: date-time + type: string + lastUpdateTime: + description: The last time this condition was updated. + format: date-time + type: string + message: + description: A human-readable message indicating details about the transition. + type: string + reason: + description: The reason for the condition's last transition. + type: string + status: + description: Status of the condition, one of True, False, Unknown. + type: string + type: + description: Type of the condition. + type: string + required: + - status + - type + type: object + type: array + error: + description: Error indicates the error info of progressing properties: - availableReplicas: - description: AvailableReplicas is the number of service available pods targeted by workload. - format: int32 - type: integer - cluster: - description: Cluster defines which cluster the workload is in. + code: + description: Code is a globally unique identifier type: string - generation: - description: Generation is the found in workload metadata. - format: int64 - type: integer - name: - description: Name is the workload name - type: string - observedGeneration: - description: ObservedGeneration is the most recent generation observed for this workload. - format: int64 - type: integer - replicas: - description: Replicas is the desired number of pods targeted by workload - format: int32 - type: integer - stableRevision: - description: StableRevision is the old stable revision used to generate pods. + message: + description: A human-readable message indicating details about the transition. type: string - updatedAvailableReplicas: - description: UpdatedAvailableReplicas is the number of service available pods targeted by workload that have the updated template spec. - format: int32 - type: integer - updatedReadyReplicas: - description: UpdatedReadyReplicas is the number of ready pods targeted by workload that have the updated template spec. - format: int32 - type: integer - updatedReplicas: - description: UpdatedReplicas is the number of pods targeted by workload that have the updated template spec. - format: int32 - type: integer - updatedRevision: - description: UpdatedRevision is the updated template revision used to generate pods. + reason: + description: A human-readable short word type: string - required: - - replicas - - updatedAvailableReplicas - - updatedReadyReplicas - - updatedReplicas type: object - type: array - type: object - type: object - served: true - storage: true - subresources: - status: {} + lastUpdateTime: + description: The last time this status was updated. + format: date-time + type: string + observedGeneration: + description: |- + ObservedGeneration is the most recent generation observed for this Rollout. It corresponds to the + Rollout's generation, which is updated on mutation by the API Server. + format: int64 + type: integer + phase: + description: Phase indecates the current phase of rollout + type: string + targetStatuses: + description: TargetStatuses describes the referenced workloads status + items: + properties: + availableReplicas: + description: AvailableReplicas is the number of service available pods targeted by workload. + format: int32 + type: integer + cluster: + description: Cluster defines which cluster the workload is in. + type: string + generation: + description: Generation is the found in workload metadata. + format: int64 + type: integer + name: + description: Name is the workload name + type: string + observedGeneration: + description: ObservedGeneration is the most recent generation observed for this workload. + format: int64 + type: integer + replicas: + description: Replicas is the desired number of pods targeted by workload + format: int32 + type: integer + stableRevision: + description: StableRevision is the old stable revision used to generate pods. + type: string + updatedAvailableReplicas: + description: UpdatedAvailableReplicas is the number of service available pods targeted by workload that have the updated template spec. + format: int32 + type: integer + updatedReadyReplicas: + description: UpdatedReadyReplicas is the number of ready pods targeted by workload that have the updated template spec. + format: int32 + type: integer + updatedReplicas: + description: UpdatedReplicas is the number of pods targeted by workload that have the updated template spec. + format: int32 + type: integer + updatedRevision: + description: UpdatedRevision is the updated template revision used to generate pods. + type: string + type: object + type: array + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/config/crd/bases/rollout.kusionstack.io_rollouts.yaml b/config/crd/bases/rollout.kusionstack.io_rollouts.yaml index 305b2fa..53eff15 100644 --- a/config/crd/bases/rollout.kusionstack.io_rollouts.yaml +++ b/config/crd/bases/rollout.kusionstack.io_rollouts.yaml @@ -1,4 +1,3 @@ ---- apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: @@ -12,276 +11,4705 @@ spec: listKind: RolloutList plural: rollouts shortNames: - - ro + - ro singular: rollout scope: Namespaced versions: - - additionalPrinterColumns: - - jsonPath: .status.conditions[?(@.type=='Available')].status - name: Available - type: string - - jsonPath: .status.phase - name: Phase - type: string - - jsonPath: .status.rolloutID - name: ID - type: string - - format: date-time - jsonPath: .metadata.creationTimestamp - name: AGE - type: date - name: v1alpha1 - schema: - openAPIV3Schema: - description: Rollout is the Schema for the rollouts API - properties: - apiVersion: - description: |- - APIVersion defines the versioned schema of this representation of an object. - Servers should convert recognized schemas to the latest internal value, and - may reject unrecognized values. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources - type: string - kind: - description: |- - Kind is a string value representing the REST resource this object represents. - Servers may infer this from the endpoint the client submits requests to. - Cannot be updated. - In CamelCase. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - type: string - metadata: - type: object - spec: - description: RolloutSpec defines the desired state of Rollout - properties: - disabled: - description: |- - Disabled means that rollout will not response for new event. - Default value is false. - type: boolean - historyLimit: - default: 10 - description: |- - HistoryLimit defines the maximum number of completed rolloutRun - history records to keep. - The HistoryLimit can start from 0 (no retained RolloutRun history). - When not set or set to math.MaxInt32, the Rollout will keep all RolloutRun history records. - format: int32 - type: integer - strategyRef: - description: StrategyRef is the reference to the rollout strategy - type: string - trafficTopologyRefs: - description: |- - TrafficTopologyRefs defines the networking traffic relationships between - workloads, backend services, and routes. - items: - type: string - type: array - triggerPolicy: - default: Auto - description: TriggerPolicy defines when rollout will be triggered - type: string - workloadRef: - description: WorkloadRef is a reference to a kind of workloads - properties: - apiVersion: - description: |- - APIVersion is the group/version for the resource being referenced. - If APIVersion is not specified, the specified Kind must be in the core API group. - For any other third-party types, APIVersion is required. - type: string - kind: - description: Kind is the type of resource being referenced - type: string - match: - description: Match indicates how to match workloads. only one - workload should be matches in one cluster - properties: - names: - description: Names is a list of workload name - items: - description: CrossClusterObjectNameReference contains cluster - and name reference to a k8s object + - additionalPrinterColumns: + - jsonPath: .status.conditions[?(@.type=='Available')].status + name: Available + type: string + - jsonPath: .status.phase + name: Phase + type: string + - jsonPath: .status.rolloutID + name: ID + type: string + - format: date-time + jsonPath: .metadata.creationTimestamp + name: AGE + type: date + name: v1alpha1 + schema: + openAPIV3Schema: + description: Rollout is the Schema for the rollouts API + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: RolloutSpec defines the desired state of Rollout + properties: + batchStrategy: + description: |- + BatchStrategy defines the inline batch strategy. + This allows specifying batch deployment details directly in Rollout + without requiring a separate RolloutStrategy resource. + Mutually exclusive with StrategyRef. + properties: + batches: + description: Batches define the order of phases to execute release in batch release + items: + properties: + breakpoint: + description: If set to true, the rollout will be paused before the step starts. + type: boolean properties: - cluster: - description: Cluster indicates the name of cluster - type: string - name: - description: Name is the resource name + additionalProperties: type: string - required: - - name - type: object - type: array - selector: - description: Selector is a label query over a set of resources, - in this case resource - properties: - matchExpressions: - description: matchExpressions is a list of label selector - requirements. The requirements are ANDed. + description: Properties contains additional information for step + type: object + targets: + description: desired target replicas items: - description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. properties: - key: - description: key is the label key that the selector - applies to. + cluster: + description: Cluster indicates the name of cluster type: string - operator: - description: |- - operator represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists and DoesNotExist. + name: + description: Name is the resource name type: string - values: + replicaSlidingWindow: + anyOf: + - type: integer + - type: string description: |- - values is an array of string values. If the operator is In or NotIn, - the values array must be non-empty. If the operator is Exists or DoesNotExist, - the values array must be empty. This array is replaced during a strategic - merge patch. - items: - type: string - type: array + ReplicaSlidingWindow used to control the number of pods that are allowed to be upgraded in + a sliding window for progressive rollout smoothly. + x-kubernetes-int-or-string: true + replicas: + anyOf: + - type: integer + - type: string + description: Replicas is the replicas of the rollout task, which represents the number of pods to be upgraded + x-kubernetes-int-or-string: true required: - - key - - operator + - name + - replicas type: object type: array - matchLabels: - additionalProperties: - type: string - description: |- - matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels - map is equivalent to an element of matchExpressions, whose key field is "key", the - operator is "In", and the values array contains only "value". The requirements are ANDed. + traffic: + description: traffic strategy + properties: + http: + properties: + filters: + description: |- + Filters define the filters that are applied to requests that match + this rule. + + + The effects of ordering of multiple behaviors are currently unspecified. + This can change in the future based on feedback during the alpha stage. + + + Conformance-levels at this level are defined based on the type of filter: + + + - ALL core filters MUST be supported by all implementations. + - Implementers are encouraged to support extended filters. + - Implementation-specific custom filters have no API guarantees across + implementations. + + + Specifying the same filter multiple times is not supported unless explicitly + indicated in the filter. + + + All filters are expected to be compatible with each other except for the + URLRewrite and RequestRedirect filters, which may not be combined. If an + implementation can not support other combinations of filters, they must clearly + document that limitation. In cases where incompatible or unsupported + filters are specified and cause the `Accepted` condition to be set to status + `False`, implementations may use the `IncompatibleFilters` reason to specify + this configuration error. + + + Support: Core + items: + description: |- + HTTPRouteFilter defines processing steps that must be completed during the + request or response lifecycle. HTTPRouteFilters are meant as an extension + point to express processing that may be done in Gateway implementations. Some + examples include request or response modification, implementing + authentication strategies, rate-limiting, and traffic shaping. API + guarantee/conformance is defined based on the type of the filter. + properties: + extensionRef: + description: |- + ExtensionRef is an optional, implementation-specific extension to the + "filter" behavior. For example, resource "myroutefilter" in group + "networking.example.net"). ExtensionRef MUST NOT be used for core and + extended filters. + + + This filter can be used multiple times within the same rule. + + + Support: Implementation-specific + properties: + group: + description: |- + Group is the group of the referent. For example, "gateway.networking.k8s.io". + When unspecified or empty string, core API group is inferred. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + description: Kind is kind of the referent. For example "HTTPRoute" or "Service". + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: Name is the name of the referent. + maxLength: 253 + minLength: 1 + type: string + required: + - group + - kind + - name + type: object + requestHeaderModifier: + description: |- + RequestHeaderModifier defines a schema for a filter that modifies request + headers. + + + Support: Core + properties: + add: + description: |- + Add adds the given header(s) (name, value) to the request + before the action. It appends to any existing values associated + with the header name. + + + Input: + GET /foo HTTP/1.1 + my-header: foo + + + Config: + add: + - name: "my-header" + value: "bar,baz" + + + Output: + GET /foo HTTP/1.1 + my-header: foo,bar,baz + items: + description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + + If multiple entries specify equivalent header names, the first entry with + an equivalent name MUST be considered for a match. Subsequent entries + with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + description: Value is the value of HTTP Header to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + remove: + description: |- + Remove the given header(s) from the HTTP request before the action. The + value of Remove is a list of HTTP header names. Note that the header + names are case-insensitive (see + https://datatracker.ietf.org/doc/html/rfc2616#section-4.2). + + + Input: + GET /foo HTTP/1.1 + my-header1: foo + my-header2: bar + my-header3: baz + + + Config: + remove: ["my-header1", "my-header3"] + + + Output: + GET /foo HTTP/1.1 + my-header2: bar + items: + type: string + maxItems: 16 + type: array + x-kubernetes-list-type: set + set: + description: |- + Set overwrites the request with the given header (name, value) + before the action. + + + Input: + GET /foo HTTP/1.1 + my-header: foo + + + Config: + set: + - name: "my-header" + value: "bar" + + + Output: + GET /foo HTTP/1.1 + my-header: bar + items: + description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + + If multiple entries specify equivalent header names, the first entry with + an equivalent name MUST be considered for a match. Subsequent entries + with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + description: Value is the value of HTTP Header to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + type: object + requestMirror: + description: |- + RequestMirror defines a schema for a filter that mirrors requests. + Requests are sent to the specified destination, but responses from + that destination are ignored. + + + This filter can be used multiple times within the same rule. Note that + not all implementations will be able to support mirroring to multiple + backends. + + + Support: Extended + + + + properties: + backendRef: + description: |- + BackendRef references a resource where mirrored requests are sent. + + + Mirrored requests must be sent only to a single destination endpoint + within this BackendRef, irrespective of how many endpoints are present + within this BackendRef. + + + If the referent cannot be found, this BackendRef is invalid and must be + dropped from the Gateway. The controller must ensure the "ResolvedRefs" + condition on the Route status is set to `status: False` and not configure + this backend in the underlying implementation. + + + If there is a cross-namespace reference to an *existing* object + that is not allowed by a ReferenceGrant, the controller must ensure the + "ResolvedRefs" condition on the Route is set to `status: False`, + with the "RefNotPermitted" reason and not configure this backend in the + underlying implementation. + + + In either error case, the Message of the `ResolvedRefs` Condition + should be used to provide more detail about the problem. + + + Support: Extended for Kubernetes Service + + + Support: Implementation-specific for any other resource + properties: + group: + default: "" + description: |- + Group is the group of the referent. For example, "gateway.networking.k8s.io". + When unspecified or empty string, core API group is inferred. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + default: Service + description: |- + Kind is the Kubernetes resource kind of the referent. For example + "Service". + + + Defaults to "Service" when not specified. + + + ExternalName services can refer to CNAME DNS records that may live + outside of the cluster and as such are difficult to reason about in + terms of conformance. They also may not be safe to forward to (see + CVE-2021-25740 for more information). Implementations SHOULD NOT + support ExternalName Services. + + + Support: Core (Services with a type other than ExternalName) + + + Support: Implementation-specific (Services with type ExternalName) + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: Name is the name of the referent. + maxLength: 253 + minLength: 1 + type: string + namespace: + description: |- + Namespace is the namespace of the backend. When unspecified, the local + namespace is inferred. + + + Note that when a namespace different than the local namespace is specified, + a ReferenceGrant object is required in the referent namespace to allow that + namespace's owner to accept the reference. See the ReferenceGrant + documentation for details. + + + Support: Core + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + port: + description: |- + Port specifies the destination port number to use for this resource. + Port is required when the referent is a Kubernetes Service. In this + case, the port number is the service port number, not the target port. + For other resources, destination port might be derived from the referent + resource or this field. + format: int32 + maximum: 65535 + minimum: 1 + type: integer + required: + - name + type: object + fraction: + description: |- + Fraction represents the fraction of requests that should be + mirrored to BackendRef. + + + Only one of Fraction or Percent may be specified. If neither field + is specified, 100% of requests will be mirrored. + + + + properties: + denominator: + default: 100 + format: int32 + minimum: 1 + type: integer + numerator: + format: int32 + minimum: 0 + type: integer + required: + - numerator + type: object + percent: + description: |- + Percent represents the percentage of requests that should be + mirrored to BackendRef. Its minimum value is 0 (indicating 0% of + requests) and its maximum value is 100 (indicating 100% of requests). + + + Only one of Fraction or Percent may be specified. If neither field + is specified, 100% of requests will be mirrored. + + + + format: int32 + maximum: 100 + minimum: 0 + type: integer + required: + - backendRef + type: object + requestRedirect: + description: |- + RequestRedirect defines a schema for a filter that responds to the + request with an HTTP redirection. + + + Support: Core + properties: + hostname: + description: |- + Hostname is the hostname to be used in the value of the `Location` + header in the response. + When empty, the hostname in the `Host` header of the request is used. + + + Support: Core + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + path: + description: |- + Path defines parameters used to modify the path of the incoming request. + The modified path is then used to construct the `Location` header. When + empty, the request path is used as-is. + + + Support: Extended + properties: + replaceFullPath: + description: |- + ReplaceFullPath specifies the value with which to replace the full path + of a request during a rewrite or redirect. + maxLength: 1024 + type: string + replacePrefixMatch: + description: |- + ReplacePrefixMatch specifies the value with which to replace the prefix + match of a request during a rewrite or redirect. For example, a request + to "/foo/bar" with a prefix match of "/foo" and a ReplacePrefixMatch + of "/xyz" would be modified to "/xyz/bar". + + + Note that this matches the behavior of the PathPrefix match type. This + matches full path elements. A path element refers to the list of labels + in the path split by the `/` separator. When specified, a trailing `/` is + ignored. For example, the paths `/abc`, `/abc/`, and `/abc/def` would all + match the prefix `/abc`, but the path `/abcd` would not. + + + ReplacePrefixMatch is only compatible with a `PathPrefix` HTTPRouteMatch. + Using any other HTTPRouteMatch type on the same HTTPRouteRule will result in + the implementation setting the Accepted Condition for the Route to `status: False`. + + + Request Path | Prefix Match | Replace Prefix | Modified Path + -------------|--------------|----------------|---------- + /foo/bar | /foo | /xyz | /xyz/bar + /foo/bar | /foo | /xyz/ | /xyz/bar + /foo/bar | /foo/ | /xyz | /xyz/bar + /foo/bar | /foo/ | /xyz/ | /xyz/bar + /foo | /foo | /xyz | /xyz + /foo/ | /foo | /xyz | /xyz/ + /foo/bar | /foo | | /bar + /foo/ | /foo | | / + /foo | /foo | | / + /foo/ | /foo | / | / + /foo | /foo | / | / + maxLength: 1024 + type: string + type: + description: |- + Type defines the type of path modifier. Additional types may be + added in a future release of the API. + + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + enum: + - ReplaceFullPath + - ReplacePrefixMatch + type: string + required: + - type + type: object + port: + description: |- + Port is the port to be used in the value of the `Location` + header in the response. + + + If no port is specified, the redirect port MUST be derived using the + following rules: + + + * If redirect scheme is not-empty, the redirect port MUST be the well-known + port associated with the redirect scheme. Specifically "http" to port 80 + and "https" to port 443. If the redirect scheme does not have a + well-known port, the listener port of the Gateway SHOULD be used. + * If redirect scheme is empty, the redirect port MUST be the Gateway + Listener port. + + + Implementations SHOULD NOT add the port number in the 'Location' + header in the following cases: + + + * A Location header that will use HTTP (whether that is determined via + the Listener protocol or the Scheme field) _and_ use port 80. + * A Location header that will use HTTPS (whether that is determined via + the Listener protocol or the Scheme field) _and_ use port 443. + + + Support: Extended + format: int32 + maximum: 65535 + minimum: 1 + type: integer + scheme: + description: |- + Scheme is the scheme to be used in the value of the `Location` header in + the response. When empty, the scheme of the request is used. + + + Scheme redirects can affect the port of the redirect, for more information, + refer to the documentation for the port field of this filter. + + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + + + Support: Extended + enum: + - http + - https + type: string + statusCode: + default: 302 + description: |- + StatusCode is the HTTP status code to be used in response. + + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + + + Support: Core + enum: + - 301 + - 302 + type: integer + type: object + responseHeaderModifier: + description: |- + ResponseHeaderModifier defines a schema for a filter that modifies response + headers. + + + Support: Extended + properties: + add: + description: |- + Add adds the given header(s) (name, value) to the request + before the action. It appends to any existing values associated + with the header name. + + + Input: + GET /foo HTTP/1.1 + my-header: foo + + + Config: + add: + - name: "my-header" + value: "bar,baz" + + + Output: + GET /foo HTTP/1.1 + my-header: foo,bar,baz + items: + description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + + If multiple entries specify equivalent header names, the first entry with + an equivalent name MUST be considered for a match. Subsequent entries + with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + description: Value is the value of HTTP Header to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + remove: + description: |- + Remove the given header(s) from the HTTP request before the action. The + value of Remove is a list of HTTP header names. Note that the header + names are case-insensitive (see + https://datatracker.ietf.org/doc/html/rfc2616#section-4.2). + + + Input: + GET /foo HTTP/1.1 + my-header1: foo + my-header2: bar + my-header3: baz + + + Config: + remove: ["my-header1", "my-header3"] + + + Output: + GET /foo HTTP/1.1 + my-header2: bar + items: + type: string + maxItems: 16 + type: array + x-kubernetes-list-type: set + set: + description: |- + Set overwrites the request with the given header (name, value) + before the action. + + + Input: + GET /foo HTTP/1.1 + my-header: foo + + + Config: + set: + - name: "my-header" + value: "bar" + + + Output: + GET /foo HTTP/1.1 + my-header: bar + items: + description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + + If multiple entries specify equivalent header names, the first entry with + an equivalent name MUST be considered for a match. Subsequent entries + with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + description: Value is the value of HTTP Header to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + type: object + type: + description: |- + Type identifies the type of filter to apply. As with other API fields, + types are classified into three conformance levels: + + + - Core: Filter types and their corresponding configuration defined by + "Support: Core" in this package, e.g. "RequestHeaderModifier". All + implementations must support core filters. + + + - Extended: Filter types and their corresponding configuration defined by + "Support: Extended" in this package, e.g. "RequestMirror". Implementers + are encouraged to support extended filters. + + + - Implementation-specific: Filters that are defined and supported by + specific vendors. + In the future, filters showing convergence in behavior across multiple + implementations will be considered for inclusion in extended or core + conformance levels. Filter-specific configuration for such filters + is specified using the ExtensionRef field. `Type` should be set to + "ExtensionRef" for custom filters. + + + Implementers are encouraged to define custom implementation types to + extend the core API with implementation-specific behavior. + + + If a reference to a custom filter type cannot be resolved, the filter + MUST NOT be skipped. Instead, requests that would have been processed by + that filter MUST receive a HTTP error response. + + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + enum: + - RequestHeaderModifier + - ResponseHeaderModifier + - RequestMirror + - RequestRedirect + - URLRewrite + - ExtensionRef + type: string + urlRewrite: + description: |- + URLRewrite defines a schema for a filter that modifies a request during forwarding. + + + Support: Extended + properties: + hostname: + description: |- + Hostname is the value to be used to replace the Host header value during + forwarding. + + + Support: Extended + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + path: + description: |- + Path defines a path rewrite. + + + Support: Extended + properties: + replaceFullPath: + description: |- + ReplaceFullPath specifies the value with which to replace the full path + of a request during a rewrite or redirect. + maxLength: 1024 + type: string + replacePrefixMatch: + description: |- + ReplacePrefixMatch specifies the value with which to replace the prefix + match of a request during a rewrite or redirect. For example, a request + to "/foo/bar" with a prefix match of "/foo" and a ReplacePrefixMatch + of "/xyz" would be modified to "/xyz/bar". + + + Note that this matches the behavior of the PathPrefix match type. This + matches full path elements. A path element refers to the list of labels + in the path split by the `/` separator. When specified, a trailing `/` is + ignored. For example, the paths `/abc`, `/abc/`, and `/abc/def` would all + match the prefix `/abc`, but the path `/abcd` would not. + + + ReplacePrefixMatch is only compatible with a `PathPrefix` HTTPRouteMatch. + Using any other HTTPRouteMatch type on the same HTTPRouteRule will result in + the implementation setting the Accepted Condition for the Route to `status: False`. + + + Request Path | Prefix Match | Replace Prefix | Modified Path + -------------|--------------|----------------|---------- + /foo/bar | /foo | /xyz | /xyz/bar + /foo/bar | /foo | /xyz/ | /xyz/bar + /foo/bar | /foo/ | /xyz | /xyz/bar + /foo/bar | /foo/ | /xyz/ | /xyz/bar + /foo | /foo | /xyz | /xyz + /foo/ | /foo | /xyz | /xyz/ + /foo/bar | /foo | | /bar + /foo/ | /foo | | / + /foo | /foo | | / + /foo/ | /foo | / | / + /foo | /foo | / | / + maxLength: 1024 + type: string + type: + description: |- + Type defines the type of path modifier. Additional types may be + added in a future release of the API. + + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + enum: + - ReplaceFullPath + - ReplacePrefixMatch + type: string + required: + - type + type: object + type: object + required: + - type + type: object + maxItems: 16 + type: array + matches: + description: |- + Matches define conditions used for matching the rule against incoming + HTTP requests. Each match is independent, i.e. this rule will be matched + if **any** one of the matches is satisfied. + + + For example, take the following matches configuration: + + + ``` + matches: + - path: + value: "/foo" + headers: + - name: "version" + value: "v2" + - path: + value: "/v2/foo" + ``` + + + For a request to match against this rule, a request must satisfy + EITHER of the two conditions: + + + - path prefixed with `/foo` AND contains the header `version: v2` + - path prefix of `/v2/foo` + + + See the documentation for HTTPRouteMatch on how to specify multiple + match conditions that should be ANDed together. + + + If no matches are specified, the default is a prefix + path match on "/", which has the effect of matching every + HTTP request. + + + Proxy or Load Balancer routing configuration generated from HTTPRoutes + MUST prioritize matches based on the following criteria, continuing on + ties. Across all rules specified on applicable Routes, precedence must be + given to the match having: + + + * "Exact" path match. + * "Prefix" path match with largest number of characters. + * Method match. + * Largest number of header matches. + * Largest number of query param matches. + + + Note: The precedence of RegularExpression path matches are implementation-specific. + + + If ties still exist across multiple Routes, matching precedence MUST be + determined in order of the following criteria, continuing on ties: + + + * The oldest Route based on creation timestamp. + * The Route appearing first in alphabetical order by + "{namespace}/{name}". + + + If ties still exist within an HTTPRoute, matching precedence MUST be granted + to the FIRST matching rule (in list order) with a match meeting the above + criteria. + + + When no rules matching a request have been successfully attached to the + parent a request is coming from, a HTTP 404 status code MUST be returned. + items: + properties: + headers: + description: |- + Headers specifies HTTP request header matchers. Multiple match values are + ANDed together, meaning, a request must match all the specified headers + to select the route. + items: + description: |- + HTTPHeaderMatch describes how to select a HTTP route by matching HTTP request + headers. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + + If multiple entries specify equivalent header names, only the first + entry with an equivalent name MUST be considered for a match. Subsequent + entries with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + + + When a header is repeated in an HTTP request, it is + implementation-specific behavior as to how this is represented. + Generally, proxies should follow the guidance from the RFC: + https://www.rfc-editor.org/rfc/rfc7230.html#section-3.2.2 regarding + processing a repeated header, with special handling for "Set-Cookie". + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + type: + default: Exact + description: |- + Type specifies how to match against the value of the header. + + + Support: Core (Exact) + + + Support: Implementation-specific (RegularExpression) + + + Since RegularExpression HeaderMatchType has implementation-specific + conformance, implementations can support POSIX, PCRE or any other dialects + of regular expressions. Please read the implementation's documentation to + determine the supported dialect. + enum: + - Exact + - RegularExpression + type: string + value: + description: Value is the value of HTTP Header to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + path: + description: Path specifies a HTTP request path matcher. + properties: + type: + default: PathPrefix + description: |- + Type specifies how to match against the path Value. + + + Support: Core (Exact, PathPrefix) + + + Support: Implementation-specific (RegularExpression) + enum: + - Exact + - PathPrefix + - RegularExpression + type: string + value: + default: / + description: Value of the HTTP path to match against. + maxLength: 1024 + type: string + type: object + queryParams: + description: |- + QueryParams specifies HTTP query parameter matchers. Multiple match + values are ANDed together, meaning, a request must match all the + specified query parameters to select the route. + + + Support: Extended + items: + description: |- + HTTPQueryParamMatch describes how to select a HTTP route by matching HTTP + query parameters. + properties: + name: + description: |- + Name is the name of the HTTP query param to be matched. This must be an + exact string match. (See + https://tools.ietf.org/html/rfc7230#section-2.7.3). + + + If multiple entries specify equivalent query param names, only the first + entry with an equivalent name MUST be considered for a match. Subsequent + entries with an equivalent query param name MUST be ignored. + + + If a query param is repeated in an HTTP request, the behavior is + purposely left undefined, since different data planes have different + capabilities. However, it is *recommended* that implementations should + match against the first value of the param if the data plane supports it, + as this behavior is expected in other load balancing contexts outside of + the Gateway API. + + + Users SHOULD NOT route traffic based on repeated query params to guard + themselves against potential differences in the implementations. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + type: + default: Exact + description: |- + Type specifies how to match against the value of the query parameter. + + + Support: Extended (Exact) + + + Support: Implementation-specific (RegularExpression) + + + Since RegularExpression QueryParamMatchType has Implementation-specific + conformance, implementations can support POSIX, PCRE or any other + dialects of regular expressions. Please read the implementation's + documentation to determine the supported dialect. + enum: + - Exact + - RegularExpression + type: string + value: + description: Value is the value of HTTP query param to be matched. + maxLength: 1024 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + type: object + maxItems: 8 + type: array + stableTraffic: + description: StableTraffic indicate the base traffic rule + properties: + filters: + description: |- + Filters define the filters that are applied to requests that match + this rule. + + + The effects of ordering of multiple behaviors are currently unspecified. + This can change in the future based on feedback during the alpha stage. + + + Conformance-levels at this level are defined based on the type of filter: + + + - ALL core filters MUST be supported by all implementations. + - Implementers are encouraged to support extended filters. + - Implementation-specific custom filters have no API guarantees across + implementations. + + + Specifying the same filter multiple times is not supported unless explicitly + indicated in the filter. + + + All filters are expected to be compatible with each other except for the + URLRewrite and RequestRedirect filters, which may not be combined. If an + implementation can not support other combinations of filters, they must clearly + document that limitation. In cases where incompatible or unsupported + filters are specified and cause the `Accepted` condition to be set to status + `False`, implementations may use the `IncompatibleFilters` reason to specify + this configuration error. + + + Support: Core + items: + description: |- + HTTPRouteFilter defines processing steps that must be completed during the + request or response lifecycle. HTTPRouteFilters are meant as an extension + point to express processing that may be done in Gateway implementations. Some + examples include request or response modification, implementing + authentication strategies, rate-limiting, and traffic shaping. API + guarantee/conformance is defined based on the type of the filter. + properties: + extensionRef: + description: |- + ExtensionRef is an optional, implementation-specific extension to the + "filter" behavior. For example, resource "myroutefilter" in group + "networking.example.net"). ExtensionRef MUST NOT be used for core and + extended filters. + + + This filter can be used multiple times within the same rule. + + + Support: Implementation-specific + properties: + group: + description: |- + Group is the group of the referent. For example, "gateway.networking.k8s.io". + When unspecified or empty string, core API group is inferred. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + description: Kind is kind of the referent. For example "HTTPRoute" or "Service". + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: Name is the name of the referent. + maxLength: 253 + minLength: 1 + type: string + required: + - group + - kind + - name + type: object + requestHeaderModifier: + description: |- + RequestHeaderModifier defines a schema for a filter that modifies request + headers. + + + Support: Core + properties: + add: + description: |- + Add adds the given header(s) (name, value) to the request + before the action. It appends to any existing values associated + with the header name. + + + Input: + GET /foo HTTP/1.1 + my-header: foo + + + Config: + add: + - name: "my-header" + value: "bar,baz" + + + Output: + GET /foo HTTP/1.1 + my-header: foo,bar,baz + items: + description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + + If multiple entries specify equivalent header names, the first entry with + an equivalent name MUST be considered for a match. Subsequent entries + with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + description: Value is the value of HTTP Header to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + remove: + description: |- + Remove the given header(s) from the HTTP request before the action. The + value of Remove is a list of HTTP header names. Note that the header + names are case-insensitive (see + https://datatracker.ietf.org/doc/html/rfc2616#section-4.2). + + + Input: + GET /foo HTTP/1.1 + my-header1: foo + my-header2: bar + my-header3: baz + + + Config: + remove: ["my-header1", "my-header3"] + + + Output: + GET /foo HTTP/1.1 + my-header2: bar + items: + type: string + maxItems: 16 + type: array + x-kubernetes-list-type: set + set: + description: |- + Set overwrites the request with the given header (name, value) + before the action. + + + Input: + GET /foo HTTP/1.1 + my-header: foo + + + Config: + set: + - name: "my-header" + value: "bar" + + + Output: + GET /foo HTTP/1.1 + my-header: bar + items: + description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + + If multiple entries specify equivalent header names, the first entry with + an equivalent name MUST be considered for a match. Subsequent entries + with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + description: Value is the value of HTTP Header to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + type: object + requestMirror: + description: |- + RequestMirror defines a schema for a filter that mirrors requests. + Requests are sent to the specified destination, but responses from + that destination are ignored. + + + This filter can be used multiple times within the same rule. Note that + not all implementations will be able to support mirroring to multiple + backends. + + + Support: Extended + + + + properties: + backendRef: + description: |- + BackendRef references a resource where mirrored requests are sent. + + + Mirrored requests must be sent only to a single destination endpoint + within this BackendRef, irrespective of how many endpoints are present + within this BackendRef. + + + If the referent cannot be found, this BackendRef is invalid and must be + dropped from the Gateway. The controller must ensure the "ResolvedRefs" + condition on the Route status is set to `status: False` and not configure + this backend in the underlying implementation. + + + If there is a cross-namespace reference to an *existing* object + that is not allowed by a ReferenceGrant, the controller must ensure the + "ResolvedRefs" condition on the Route is set to `status: False`, + with the "RefNotPermitted" reason and not configure this backend in the + underlying implementation. + + + In either error case, the Message of the `ResolvedRefs` Condition + should be used to provide more detail about the problem. + + + Support: Extended for Kubernetes Service + + + Support: Implementation-specific for any other resource + properties: + group: + default: "" + description: |- + Group is the group of the referent. For example, "gateway.networking.k8s.io". + When unspecified or empty string, core API group is inferred. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + default: Service + description: |- + Kind is the Kubernetes resource kind of the referent. For example + "Service". + + + Defaults to "Service" when not specified. + + + ExternalName services can refer to CNAME DNS records that may live + outside of the cluster and as such are difficult to reason about in + terms of conformance. They also may not be safe to forward to (see + CVE-2021-25740 for more information). Implementations SHOULD NOT + support ExternalName Services. + + + Support: Core (Services with a type other than ExternalName) + + + Support: Implementation-specific (Services with type ExternalName) + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: Name is the name of the referent. + maxLength: 253 + minLength: 1 + type: string + namespace: + description: |- + Namespace is the namespace of the backend. When unspecified, the local + namespace is inferred. + + + Note that when a namespace different than the local namespace is specified, + a ReferenceGrant object is required in the referent namespace to allow that + namespace's owner to accept the reference. See the ReferenceGrant + documentation for details. + + + Support: Core + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + port: + description: |- + Port specifies the destination port number to use for this resource. + Port is required when the referent is a Kubernetes Service. In this + case, the port number is the service port number, not the target port. + For other resources, destination port might be derived from the referent + resource or this field. + format: int32 + maximum: 65535 + minimum: 1 + type: integer + required: + - name + type: object + fraction: + description: |- + Fraction represents the fraction of requests that should be + mirrored to BackendRef. + + + Only one of Fraction or Percent may be specified. If neither field + is specified, 100% of requests will be mirrored. + + + + properties: + denominator: + default: 100 + format: int32 + minimum: 1 + type: integer + numerator: + format: int32 + minimum: 0 + type: integer + required: + - numerator + type: object + percent: + description: |- + Percent represents the percentage of requests that should be + mirrored to BackendRef. Its minimum value is 0 (indicating 0% of + requests) and its maximum value is 100 (indicating 100% of requests). + + + Only one of Fraction or Percent may be specified. If neither field + is specified, 100% of requests will be mirrored. + + + + format: int32 + maximum: 100 + minimum: 0 + type: integer + required: + - backendRef + type: object + requestRedirect: + description: |- + RequestRedirect defines a schema for a filter that responds to the + request with an HTTP redirection. + + + Support: Core + properties: + hostname: + description: |- + Hostname is the hostname to be used in the value of the `Location` + header in the response. + When empty, the hostname in the `Host` header of the request is used. + + + Support: Core + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + path: + description: |- + Path defines parameters used to modify the path of the incoming request. + The modified path is then used to construct the `Location` header. When + empty, the request path is used as-is. + + + Support: Extended + properties: + replaceFullPath: + description: |- + ReplaceFullPath specifies the value with which to replace the full path + of a request during a rewrite or redirect. + maxLength: 1024 + type: string + replacePrefixMatch: + description: |- + ReplacePrefixMatch specifies the value with which to replace the prefix + match of a request during a rewrite or redirect. For example, a request + to "/foo/bar" with a prefix match of "/foo" and a ReplacePrefixMatch + of "/xyz" would be modified to "/xyz/bar". + + + Note that this matches the behavior of the PathPrefix match type. This + matches full path elements. A path element refers to the list of labels + in the path split by the `/` separator. When specified, a trailing `/` is + ignored. For example, the paths `/abc`, `/abc/`, and `/abc/def` would all + match the prefix `/abc`, but the path `/abcd` would not. + + + ReplacePrefixMatch is only compatible with a `PathPrefix` HTTPRouteMatch. + Using any other HTTPRouteMatch type on the same HTTPRouteRule will result in + the implementation setting the Accepted Condition for the Route to `status: False`. + + + Request Path | Prefix Match | Replace Prefix | Modified Path + -------------|--------------|----------------|---------- + /foo/bar | /foo | /xyz | /xyz/bar + /foo/bar | /foo | /xyz/ | /xyz/bar + /foo/bar | /foo/ | /xyz | /xyz/bar + /foo/bar | /foo/ | /xyz/ | /xyz/bar + /foo | /foo | /xyz | /xyz + /foo/ | /foo | /xyz | /xyz/ + /foo/bar | /foo | | /bar + /foo/ | /foo | | / + /foo | /foo | | / + /foo/ | /foo | / | / + /foo | /foo | / | / + maxLength: 1024 + type: string + type: + description: |- + Type defines the type of path modifier. Additional types may be + added in a future release of the API. + + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + enum: + - ReplaceFullPath + - ReplacePrefixMatch + type: string + required: + - type + type: object + port: + description: |- + Port is the port to be used in the value of the `Location` + header in the response. + + + If no port is specified, the redirect port MUST be derived using the + following rules: + + + * If redirect scheme is not-empty, the redirect port MUST be the well-known + port associated with the redirect scheme. Specifically "http" to port 80 + and "https" to port 443. If the redirect scheme does not have a + well-known port, the listener port of the Gateway SHOULD be used. + * If redirect scheme is empty, the redirect port MUST be the Gateway + Listener port. + + + Implementations SHOULD NOT add the port number in the 'Location' + header in the following cases: + + + * A Location header that will use HTTP (whether that is determined via + the Listener protocol or the Scheme field) _and_ use port 80. + * A Location header that will use HTTPS (whether that is determined via + the Listener protocol or the Scheme field) _and_ use port 443. + + + Support: Extended + format: int32 + maximum: 65535 + minimum: 1 + type: integer + scheme: + description: |- + Scheme is the scheme to be used in the value of the `Location` header in + the response. When empty, the scheme of the request is used. + + + Scheme redirects can affect the port of the redirect, for more information, + refer to the documentation for the port field of this filter. + + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + + + Support: Extended + enum: + - http + - https + type: string + statusCode: + default: 302 + description: |- + StatusCode is the HTTP status code to be used in response. + + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + + + Support: Core + enum: + - 301 + - 302 + type: integer + type: object + responseHeaderModifier: + description: |- + ResponseHeaderModifier defines a schema for a filter that modifies response + headers. + + + Support: Extended + properties: + add: + description: |- + Add adds the given header(s) (name, value) to the request + before the action. It appends to any existing values associated + with the header name. + + + Input: + GET /foo HTTP/1.1 + my-header: foo + + + Config: + add: + - name: "my-header" + value: "bar,baz" + + + Output: + GET /foo HTTP/1.1 + my-header: foo,bar,baz + items: + description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + + If multiple entries specify equivalent header names, the first entry with + an equivalent name MUST be considered for a match. Subsequent entries + with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + description: Value is the value of HTTP Header to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + remove: + description: |- + Remove the given header(s) from the HTTP request before the action. The + value of Remove is a list of HTTP header names. Note that the header + names are case-insensitive (see + https://datatracker.ietf.org/doc/html/rfc2616#section-4.2). + + + Input: + GET /foo HTTP/1.1 + my-header1: foo + my-header2: bar + my-header3: baz + + + Config: + remove: ["my-header1", "my-header3"] + + + Output: + GET /foo HTTP/1.1 + my-header2: bar + items: + type: string + maxItems: 16 + type: array + x-kubernetes-list-type: set + set: + description: |- + Set overwrites the request with the given header (name, value) + before the action. + + + Input: + GET /foo HTTP/1.1 + my-header: foo + + + Config: + set: + - name: "my-header" + value: "bar" + + + Output: + GET /foo HTTP/1.1 + my-header: bar + items: + description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + + If multiple entries specify equivalent header names, the first entry with + an equivalent name MUST be considered for a match. Subsequent entries + with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + description: Value is the value of HTTP Header to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + type: object + type: + description: |- + Type identifies the type of filter to apply. As with other API fields, + types are classified into three conformance levels: + + + - Core: Filter types and their corresponding configuration defined by + "Support: Core" in this package, e.g. "RequestHeaderModifier". All + implementations must support core filters. + + + - Extended: Filter types and their corresponding configuration defined by + "Support: Extended" in this package, e.g. "RequestMirror". Implementers + are encouraged to support extended filters. + + + - Implementation-specific: Filters that are defined and supported by + specific vendors. + In the future, filters showing convergence in behavior across multiple + implementations will be considered for inclusion in extended or core + conformance levels. Filter-specific configuration for such filters + is specified using the ExtensionRef field. `Type` should be set to + "ExtensionRef" for custom filters. + + + Implementers are encouraged to define custom implementation types to + extend the core API with implementation-specific behavior. + + + If a reference to a custom filter type cannot be resolved, the filter + MUST NOT be skipped. Instead, requests that would have been processed by + that filter MUST receive a HTTP error response. + + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + enum: + - RequestHeaderModifier + - ResponseHeaderModifier + - RequestMirror + - RequestRedirect + - URLRewrite + - ExtensionRef + type: string + urlRewrite: + description: |- + URLRewrite defines a schema for a filter that modifies a request during forwarding. + + + Support: Extended + properties: + hostname: + description: |- + Hostname is the value to be used to replace the Host header value during + forwarding. + + + Support: Extended + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + path: + description: |- + Path defines a path rewrite. + + + Support: Extended + properties: + replaceFullPath: + description: |- + ReplaceFullPath specifies the value with which to replace the full path + of a request during a rewrite or redirect. + maxLength: 1024 + type: string + replacePrefixMatch: + description: |- + ReplacePrefixMatch specifies the value with which to replace the prefix + match of a request during a rewrite or redirect. For example, a request + to "/foo/bar" with a prefix match of "/foo" and a ReplacePrefixMatch + of "/xyz" would be modified to "/xyz/bar". + + + Note that this matches the behavior of the PathPrefix match type. This + matches full path elements. A path element refers to the list of labels + in the path split by the `/` separator. When specified, a trailing `/` is + ignored. For example, the paths `/abc`, `/abc/`, and `/abc/def` would all + match the prefix `/abc`, but the path `/abcd` would not. + + + ReplacePrefixMatch is only compatible with a `PathPrefix` HTTPRouteMatch. + Using any other HTTPRouteMatch type on the same HTTPRouteRule will result in + the implementation setting the Accepted Condition for the Route to `status: False`. + + + Request Path | Prefix Match | Replace Prefix | Modified Path + -------------|--------------|----------------|---------- + /foo/bar | /foo | /xyz | /xyz/bar + /foo/bar | /foo | /xyz/ | /xyz/bar + /foo/bar | /foo/ | /xyz | /xyz/bar + /foo/bar | /foo/ | /xyz/ | /xyz/bar + /foo | /foo | /xyz | /xyz + /foo/ | /foo | /xyz | /xyz/ + /foo/bar | /foo | | /bar + /foo/ | /foo | | / + /foo | /foo | | / + /foo/ | /foo | / | / + /foo | /foo | / | / + maxLength: 1024 + type: string + type: + description: |- + Type defines the type of path modifier. Additional types may be + added in a future release of the API. + + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + enum: + - ReplaceFullPath + - ReplacePrefixMatch + type: string + required: + - type + type: object + type: object + required: + - type + type: object + maxItems: 16 + type: array + matches: + description: |- + Matches define conditions used for matching the rule against incoming + HTTP requests. Each match is independent, i.e. this rule will be matched + if **any** one of the matches is satisfied. + + + For example, take the following matches configuration: + + + ``` + matches: + - path: + value: "/foo" + headers: + - name: "version" + value: "v2" + - path: + value: "/v2/foo" + ``` + + + For a request to match against this rule, a request must satisfy + EITHER of the two conditions: + + + - path prefixed with `/foo` AND contains the header `version: v2` + - path prefix of `/v2/foo` + + + See the documentation for HTTPRouteMatch on how to specify multiple + match conditions that should be ANDed together. + + + If no matches are specified, the default is a prefix + path match on "/", which has the effect of matching every + HTTP request. + + + Proxy or Load Balancer routing configuration generated from HTTPRoutes + MUST prioritize matches based on the following criteria, continuing on + ties. Across all rules specified on applicable Routes, precedence must be + given to the match having: + + + * "Exact" path match. + * "Prefix" path match with largest number of characters. + * Method match. + * Largest number of header matches. + * Largest number of query param matches. + + + Note: The precedence of RegularExpression path matches are implementation-specific. + + + If ties still exist across multiple Routes, matching precedence MUST be + determined in order of the following criteria, continuing on ties: + + + * The oldest Route based on creation timestamp. + * The Route appearing first in alphabetical order by + "{namespace}/{name}". + + + If ties still exist within an HTTPRoute, matching precedence MUST be granted + to the FIRST matching rule (in list order) with a match meeting the above + criteria. + + + When no rules matching a request have been successfully attached to the + parent a request is coming from, a HTTP 404 status code MUST be returned. + items: + properties: + headers: + description: |- + Headers specifies HTTP request header matchers. Multiple match values are + ANDed together, meaning, a request must match all the specified headers + to select the route. + items: + description: |- + HTTPHeaderMatch describes how to select a HTTP route by matching HTTP request + headers. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + + If multiple entries specify equivalent header names, only the first + entry with an equivalent name MUST be considered for a match. Subsequent + entries with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + + + When a header is repeated in an HTTP request, it is + implementation-specific behavior as to how this is represented. + Generally, proxies should follow the guidance from the RFC: + https://www.rfc-editor.org/rfc/rfc7230.html#section-3.2.2 regarding + processing a repeated header, with special handling for "Set-Cookie". + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + type: + default: Exact + description: |- + Type specifies how to match against the value of the header. + + + Support: Core (Exact) + + + Support: Implementation-specific (RegularExpression) + + + Since RegularExpression HeaderMatchType has implementation-specific + conformance, implementations can support POSIX, PCRE or any other dialects + of regular expressions. Please read the implementation's documentation to + determine the supported dialect. + enum: + - Exact + - RegularExpression + type: string + value: + description: Value is the value of HTTP Header to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + path: + description: Path specifies a HTTP request path matcher. + properties: + type: + default: PathPrefix + description: |- + Type specifies how to match against the path Value. + + + Support: Core (Exact, PathPrefix) + + + Support: Implementation-specific (RegularExpression) + enum: + - Exact + - PathPrefix + - RegularExpression + type: string + value: + default: / + description: Value of the HTTP path to match against. + maxLength: 1024 + type: string + type: object + queryParams: + description: |- + QueryParams specifies HTTP query parameter matchers. Multiple match + values are ANDed together, meaning, a request must match all the + specified query parameters to select the route. + + + Support: Extended + items: + description: |- + HTTPQueryParamMatch describes how to select a HTTP route by matching HTTP + query parameters. + properties: + name: + description: |- + Name is the name of the HTTP query param to be matched. This must be an + exact string match. (See + https://tools.ietf.org/html/rfc7230#section-2.7.3). + + + If multiple entries specify equivalent query param names, only the first + entry with an equivalent name MUST be considered for a match. Subsequent + entries with an equivalent query param name MUST be ignored. + + + If a query param is repeated in an HTTP request, the behavior is + purposely left undefined, since different data planes have different + capabilities. However, it is *recommended* that implementations should + match against the first value of the param if the data plane supports it, + as this behavior is expected in other load balancing contexts outside of + the Gateway API. + + + Users SHOULD NOT route traffic based on repeated query params to guard + themselves against potential differences in the implementations. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + type: + default: Exact + description: |- + Type specifies how to match against the value of the query parameter. + + + Support: Extended (Exact) + + + Support: Implementation-specific (RegularExpression) + + + Since RegularExpression QueryParamMatchType has Implementation-specific + conformance, implementations can support POSIX, PCRE or any other + dialects of regular expressions. Please read the implementation's + documentation to determine the supported dialect. + enum: + - Exact + - RegularExpression + type: string + value: + description: Value is the value of HTTP query param to be matched. + maxLength: 1024 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + type: object + maxItems: 8 + type: array + type: object + weight: + description: Weight indicate how many percentage of traffic the canary pods should receive + format: int32 + maximum: 100 + minimum: 0 + type: integer + type: object type: object + required: + - targets type: object - x-kubernetes-map-type: atomic - type: object - required: - - kind - - match - type: object - type: object - status: - description: RolloutStatus defines the observed state of Rollout - properties: - conditions: - description: Conditions is the list of conditions - items: + type: array + toleration: + description: Toleration is the toleration policy of the canary strategy + properties: + initialDelaySeconds: + description: Number of seconds after the toleration check has started before the task are initiated. + format: int32 + type: integer + taskFailureThreshold: + anyOf: + - type: integer + - type: string + description: |- + FailureThreshold indicates how many failed pods can be tolerated before marking the rollout task as success + If not set, the default value is 0, which means no failed pods can be tolerated + This is a task level threshold. + x-kubernetes-int-or-string: true + workloadTotalFailureThreshold: + anyOf: + - type: integer + - type: string + description: |- + WorkloadFailureThreshold indicates how many failed pods can be tolerated in all upgraded pods of one workload. + The default value is 0, which means no failed pods can be tolerated. + This is a workload level threshold. + x-kubernetes-int-or-string: true + type: object + type: object + canaryStrategy: description: |- - Condition defines the condition of a resource - See: https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#typical-status-properties + CanaryStrategy defines the inline canary strategy. + This allows specifying canary deployment details directly in Rollout + without requiring a separate RolloutStrategy resource. + Mutually exclusive with StrategyRef. properties: - lastTransitionTime: - description: Last time the condition transitioned from one status - to another. - format: date-time - type: string - lastUpdateTime: - description: The last time this condition was updated. - format: date-time - type: string - message: - description: A human-readable message indicating details about - the transition. - type: string - reason: - description: The reason for the condition's last transition. - type: string - status: - description: Status of the condition, one of True, False, Unknown. - type: string - type: - description: Type of the condition. - type: string + podTemplateMetadataPatch: + description: PodTemplateMetadataPatch defines a patch for workload podTemplate metadata. + properties: + annotations: + additionalProperties: + type: string + description: Annotations are additional metadata that can be included. + type: object + labels: + additionalProperties: + type: string + description: Labels are additional metadata that can be included. + type: object + type: object + properties: + additionalProperties: + type: string + description: Properties contains additional information for step + type: object + targets: + description: desired target replicas + items: + properties: + cluster: + description: Cluster indicates the name of cluster + type: string + name: + description: Name is the resource name + type: string + replicaSlidingWindow: + anyOf: + - type: integer + - type: string + description: |- + ReplicaSlidingWindow used to control the number of pods that are allowed to be upgraded in + a sliding window for progressive rollout smoothly. + x-kubernetes-int-or-string: true + replicas: + anyOf: + - type: integer + - type: string + description: Replicas is the replicas of the rollout task, which represents the number of pods to be upgraded + x-kubernetes-int-or-string: true + required: + - name + - replicas + type: object + type: array + traffic: + description: traffic strategy + properties: + http: + properties: + filters: + description: |- + Filters define the filters that are applied to requests that match + this rule. + + + The effects of ordering of multiple behaviors are currently unspecified. + This can change in the future based on feedback during the alpha stage. + + + Conformance-levels at this level are defined based on the type of filter: + + + - ALL core filters MUST be supported by all implementations. + - Implementers are encouraged to support extended filters. + - Implementation-specific custom filters have no API guarantees across + implementations. + + + Specifying the same filter multiple times is not supported unless explicitly + indicated in the filter. + + + All filters are expected to be compatible with each other except for the + URLRewrite and RequestRedirect filters, which may not be combined. If an + implementation can not support other combinations of filters, they must clearly + document that limitation. In cases where incompatible or unsupported + filters are specified and cause the `Accepted` condition to be set to status + `False`, implementations may use the `IncompatibleFilters` reason to specify + this configuration error. + + + Support: Core + items: + description: |- + HTTPRouteFilter defines processing steps that must be completed during the + request or response lifecycle. HTTPRouteFilters are meant as an extension + point to express processing that may be done in Gateway implementations. Some + examples include request or response modification, implementing + authentication strategies, rate-limiting, and traffic shaping. API + guarantee/conformance is defined based on the type of the filter. + properties: + extensionRef: + description: |- + ExtensionRef is an optional, implementation-specific extension to the + "filter" behavior. For example, resource "myroutefilter" in group + "networking.example.net"). ExtensionRef MUST NOT be used for core and + extended filters. + + + This filter can be used multiple times within the same rule. + + + Support: Implementation-specific + properties: + group: + description: |- + Group is the group of the referent. For example, "gateway.networking.k8s.io". + When unspecified or empty string, core API group is inferred. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + description: Kind is kind of the referent. For example "HTTPRoute" or "Service". + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: Name is the name of the referent. + maxLength: 253 + minLength: 1 + type: string + required: + - group + - kind + - name + type: object + requestHeaderModifier: + description: |- + RequestHeaderModifier defines a schema for a filter that modifies request + headers. + + + Support: Core + properties: + add: + description: |- + Add adds the given header(s) (name, value) to the request + before the action. It appends to any existing values associated + with the header name. + + + Input: + GET /foo HTTP/1.1 + my-header: foo + + + Config: + add: + - name: "my-header" + value: "bar,baz" + + + Output: + GET /foo HTTP/1.1 + my-header: foo,bar,baz + items: + description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + + If multiple entries specify equivalent header names, the first entry with + an equivalent name MUST be considered for a match. Subsequent entries + with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + description: Value is the value of HTTP Header to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + remove: + description: |- + Remove the given header(s) from the HTTP request before the action. The + value of Remove is a list of HTTP header names. Note that the header + names are case-insensitive (see + https://datatracker.ietf.org/doc/html/rfc2616#section-4.2). + + + Input: + GET /foo HTTP/1.1 + my-header1: foo + my-header2: bar + my-header3: baz + + + Config: + remove: ["my-header1", "my-header3"] + + + Output: + GET /foo HTTP/1.1 + my-header2: bar + items: + type: string + maxItems: 16 + type: array + x-kubernetes-list-type: set + set: + description: |- + Set overwrites the request with the given header (name, value) + before the action. + + + Input: + GET /foo HTTP/1.1 + my-header: foo + + + Config: + set: + - name: "my-header" + value: "bar" + + + Output: + GET /foo HTTP/1.1 + my-header: bar + items: + description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + + If multiple entries specify equivalent header names, the first entry with + an equivalent name MUST be considered for a match. Subsequent entries + with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + description: Value is the value of HTTP Header to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + type: object + requestMirror: + description: |- + RequestMirror defines a schema for a filter that mirrors requests. + Requests are sent to the specified destination, but responses from + that destination are ignored. + + + This filter can be used multiple times within the same rule. Note that + not all implementations will be able to support mirroring to multiple + backends. + + + Support: Extended + + + + properties: + backendRef: + description: |- + BackendRef references a resource where mirrored requests are sent. + + + Mirrored requests must be sent only to a single destination endpoint + within this BackendRef, irrespective of how many endpoints are present + within this BackendRef. + + + If the referent cannot be found, this BackendRef is invalid and must be + dropped from the Gateway. The controller must ensure the "ResolvedRefs" + condition on the Route status is set to `status: False` and not configure + this backend in the underlying implementation. + + + If there is a cross-namespace reference to an *existing* object + that is not allowed by a ReferenceGrant, the controller must ensure the + "ResolvedRefs" condition on the Route is set to `status: False`, + with the "RefNotPermitted" reason and not configure this backend in the + underlying implementation. + + + In either error case, the Message of the `ResolvedRefs` Condition + should be used to provide more detail about the problem. + + + Support: Extended for Kubernetes Service + + + Support: Implementation-specific for any other resource + properties: + group: + default: "" + description: |- + Group is the group of the referent. For example, "gateway.networking.k8s.io". + When unspecified or empty string, core API group is inferred. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + default: Service + description: |- + Kind is the Kubernetes resource kind of the referent. For example + "Service". + + + Defaults to "Service" when not specified. + + + ExternalName services can refer to CNAME DNS records that may live + outside of the cluster and as such are difficult to reason about in + terms of conformance. They also may not be safe to forward to (see + CVE-2021-25740 for more information). Implementations SHOULD NOT + support ExternalName Services. + + + Support: Core (Services with a type other than ExternalName) + + + Support: Implementation-specific (Services with type ExternalName) + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: Name is the name of the referent. + maxLength: 253 + minLength: 1 + type: string + namespace: + description: |- + Namespace is the namespace of the backend. When unspecified, the local + namespace is inferred. + + + Note that when a namespace different than the local namespace is specified, + a ReferenceGrant object is required in the referent namespace to allow that + namespace's owner to accept the reference. See the ReferenceGrant + documentation for details. + + + Support: Core + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + port: + description: |- + Port specifies the destination port number to use for this resource. + Port is required when the referent is a Kubernetes Service. In this + case, the port number is the service port number, not the target port. + For other resources, destination port might be derived from the referent + resource or this field. + format: int32 + maximum: 65535 + minimum: 1 + type: integer + required: + - name + type: object + fraction: + description: |- + Fraction represents the fraction of requests that should be + mirrored to BackendRef. + + + Only one of Fraction or Percent may be specified. If neither field + is specified, 100% of requests will be mirrored. + + + + properties: + denominator: + default: 100 + format: int32 + minimum: 1 + type: integer + numerator: + format: int32 + minimum: 0 + type: integer + required: + - numerator + type: object + percent: + description: |- + Percent represents the percentage of requests that should be + mirrored to BackendRef. Its minimum value is 0 (indicating 0% of + requests) and its maximum value is 100 (indicating 100% of requests). + + + Only one of Fraction or Percent may be specified. If neither field + is specified, 100% of requests will be mirrored. + + + + format: int32 + maximum: 100 + minimum: 0 + type: integer + required: + - backendRef + type: object + requestRedirect: + description: |- + RequestRedirect defines a schema for a filter that responds to the + request with an HTTP redirection. + + + Support: Core + properties: + hostname: + description: |- + Hostname is the hostname to be used in the value of the `Location` + header in the response. + When empty, the hostname in the `Host` header of the request is used. + + + Support: Core + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + path: + description: |- + Path defines parameters used to modify the path of the incoming request. + The modified path is then used to construct the `Location` header. When + empty, the request path is used as-is. + + + Support: Extended + properties: + replaceFullPath: + description: |- + ReplaceFullPath specifies the value with which to replace the full path + of a request during a rewrite or redirect. + maxLength: 1024 + type: string + replacePrefixMatch: + description: |- + ReplacePrefixMatch specifies the value with which to replace the prefix + match of a request during a rewrite or redirect. For example, a request + to "/foo/bar" with a prefix match of "/foo" and a ReplacePrefixMatch + of "/xyz" would be modified to "/xyz/bar". + + + Note that this matches the behavior of the PathPrefix match type. This + matches full path elements. A path element refers to the list of labels + in the path split by the `/` separator. When specified, a trailing `/` is + ignored. For example, the paths `/abc`, `/abc/`, and `/abc/def` would all + match the prefix `/abc`, but the path `/abcd` would not. + + + ReplacePrefixMatch is only compatible with a `PathPrefix` HTTPRouteMatch. + Using any other HTTPRouteMatch type on the same HTTPRouteRule will result in + the implementation setting the Accepted Condition for the Route to `status: False`. + + + Request Path | Prefix Match | Replace Prefix | Modified Path + -------------|--------------|----------------|---------- + /foo/bar | /foo | /xyz | /xyz/bar + /foo/bar | /foo | /xyz/ | /xyz/bar + /foo/bar | /foo/ | /xyz | /xyz/bar + /foo/bar | /foo/ | /xyz/ | /xyz/bar + /foo | /foo | /xyz | /xyz + /foo/ | /foo | /xyz | /xyz/ + /foo/bar | /foo | | /bar + /foo/ | /foo | | / + /foo | /foo | | / + /foo/ | /foo | / | / + /foo | /foo | / | / + maxLength: 1024 + type: string + type: + description: |- + Type defines the type of path modifier. Additional types may be + added in a future release of the API. + + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + enum: + - ReplaceFullPath + - ReplacePrefixMatch + type: string + required: + - type + type: object + port: + description: |- + Port is the port to be used in the value of the `Location` + header in the response. + + + If no port is specified, the redirect port MUST be derived using the + following rules: + + + * If redirect scheme is not-empty, the redirect port MUST be the well-known + port associated with the redirect scheme. Specifically "http" to port 80 + and "https" to port 443. If the redirect scheme does not have a + well-known port, the listener port of the Gateway SHOULD be used. + * If redirect scheme is empty, the redirect port MUST be the Gateway + Listener port. + + + Implementations SHOULD NOT add the port number in the 'Location' + header in the following cases: + + + * A Location header that will use HTTP (whether that is determined via + the Listener protocol or the Scheme field) _and_ use port 80. + * A Location header that will use HTTPS (whether that is determined via + the Listener protocol or the Scheme field) _and_ use port 443. + + + Support: Extended + format: int32 + maximum: 65535 + minimum: 1 + type: integer + scheme: + description: |- + Scheme is the scheme to be used in the value of the `Location` header in + the response. When empty, the scheme of the request is used. + + + Scheme redirects can affect the port of the redirect, for more information, + refer to the documentation for the port field of this filter. + + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + + + Support: Extended + enum: + - http + - https + type: string + statusCode: + default: 302 + description: |- + StatusCode is the HTTP status code to be used in response. + + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + + + Support: Core + enum: + - 301 + - 302 + type: integer + type: object + responseHeaderModifier: + description: |- + ResponseHeaderModifier defines a schema for a filter that modifies response + headers. + + + Support: Extended + properties: + add: + description: |- + Add adds the given header(s) (name, value) to the request + before the action. It appends to any existing values associated + with the header name. + + + Input: + GET /foo HTTP/1.1 + my-header: foo + + + Config: + add: + - name: "my-header" + value: "bar,baz" + + + Output: + GET /foo HTTP/1.1 + my-header: foo,bar,baz + items: + description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + + If multiple entries specify equivalent header names, the first entry with + an equivalent name MUST be considered for a match. Subsequent entries + with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + description: Value is the value of HTTP Header to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + remove: + description: |- + Remove the given header(s) from the HTTP request before the action. The + value of Remove is a list of HTTP header names. Note that the header + names are case-insensitive (see + https://datatracker.ietf.org/doc/html/rfc2616#section-4.2). + + + Input: + GET /foo HTTP/1.1 + my-header1: foo + my-header2: bar + my-header3: baz + + + Config: + remove: ["my-header1", "my-header3"] + + + Output: + GET /foo HTTP/1.1 + my-header2: bar + items: + type: string + maxItems: 16 + type: array + x-kubernetes-list-type: set + set: + description: |- + Set overwrites the request with the given header (name, value) + before the action. + + + Input: + GET /foo HTTP/1.1 + my-header: foo + + + Config: + set: + - name: "my-header" + value: "bar" + + + Output: + GET /foo HTTP/1.1 + my-header: bar + items: + description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + + If multiple entries specify equivalent header names, the first entry with + an equivalent name MUST be considered for a match. Subsequent entries + with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + description: Value is the value of HTTP Header to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + type: object + type: + description: |- + Type identifies the type of filter to apply. As with other API fields, + types are classified into three conformance levels: + + + - Core: Filter types and their corresponding configuration defined by + "Support: Core" in this package, e.g. "RequestHeaderModifier". All + implementations must support core filters. + + + - Extended: Filter types and their corresponding configuration defined by + "Support: Extended" in this package, e.g. "RequestMirror". Implementers + are encouraged to support extended filters. + + + - Implementation-specific: Filters that are defined and supported by + specific vendors. + In the future, filters showing convergence in behavior across multiple + implementations will be considered for inclusion in extended or core + conformance levels. Filter-specific configuration for such filters + is specified using the ExtensionRef field. `Type` should be set to + "ExtensionRef" for custom filters. + + + Implementers are encouraged to define custom implementation types to + extend the core API with implementation-specific behavior. + + + If a reference to a custom filter type cannot be resolved, the filter + MUST NOT be skipped. Instead, requests that would have been processed by + that filter MUST receive a HTTP error response. + + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + enum: + - RequestHeaderModifier + - ResponseHeaderModifier + - RequestMirror + - RequestRedirect + - URLRewrite + - ExtensionRef + type: string + urlRewrite: + description: |- + URLRewrite defines a schema for a filter that modifies a request during forwarding. + + + Support: Extended + properties: + hostname: + description: |- + Hostname is the value to be used to replace the Host header value during + forwarding. + + + Support: Extended + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + path: + description: |- + Path defines a path rewrite. + + + Support: Extended + properties: + replaceFullPath: + description: |- + ReplaceFullPath specifies the value with which to replace the full path + of a request during a rewrite or redirect. + maxLength: 1024 + type: string + replacePrefixMatch: + description: |- + ReplacePrefixMatch specifies the value with which to replace the prefix + match of a request during a rewrite or redirect. For example, a request + to "/foo/bar" with a prefix match of "/foo" and a ReplacePrefixMatch + of "/xyz" would be modified to "/xyz/bar". + + + Note that this matches the behavior of the PathPrefix match type. This + matches full path elements. A path element refers to the list of labels + in the path split by the `/` separator. When specified, a trailing `/` is + ignored. For example, the paths `/abc`, `/abc/`, and `/abc/def` would all + match the prefix `/abc`, but the path `/abcd` would not. + + + ReplacePrefixMatch is only compatible with a `PathPrefix` HTTPRouteMatch. + Using any other HTTPRouteMatch type on the same HTTPRouteRule will result in + the implementation setting the Accepted Condition for the Route to `status: False`. + + + Request Path | Prefix Match | Replace Prefix | Modified Path + -------------|--------------|----------------|---------- + /foo/bar | /foo | /xyz | /xyz/bar + /foo/bar | /foo | /xyz/ | /xyz/bar + /foo/bar | /foo/ | /xyz | /xyz/bar + /foo/bar | /foo/ | /xyz/ | /xyz/bar + /foo | /foo | /xyz | /xyz + /foo/ | /foo | /xyz | /xyz/ + /foo/bar | /foo | | /bar + /foo/ | /foo | | / + /foo | /foo | | / + /foo/ | /foo | / | / + /foo | /foo | / | / + maxLength: 1024 + type: string + type: + description: |- + Type defines the type of path modifier. Additional types may be + added in a future release of the API. + + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + enum: + - ReplaceFullPath + - ReplacePrefixMatch + type: string + required: + - type + type: object + type: object + required: + - type + type: object + maxItems: 16 + type: array + matches: + description: |- + Matches define conditions used for matching the rule against incoming + HTTP requests. Each match is independent, i.e. this rule will be matched + if **any** one of the matches is satisfied. + + + For example, take the following matches configuration: + + + ``` + matches: + - path: + value: "/foo" + headers: + - name: "version" + value: "v2" + - path: + value: "/v2/foo" + ``` + + + For a request to match against this rule, a request must satisfy + EITHER of the two conditions: + + + - path prefixed with `/foo` AND contains the header `version: v2` + - path prefix of `/v2/foo` + + + See the documentation for HTTPRouteMatch on how to specify multiple + match conditions that should be ANDed together. + + + If no matches are specified, the default is a prefix + path match on "/", which has the effect of matching every + HTTP request. + + + Proxy or Load Balancer routing configuration generated from HTTPRoutes + MUST prioritize matches based on the following criteria, continuing on + ties. Across all rules specified on applicable Routes, precedence must be + given to the match having: + + + * "Exact" path match. + * "Prefix" path match with largest number of characters. + * Method match. + * Largest number of header matches. + * Largest number of query param matches. + + + Note: The precedence of RegularExpression path matches are implementation-specific. + + + If ties still exist across multiple Routes, matching precedence MUST be + determined in order of the following criteria, continuing on ties: + + + * The oldest Route based on creation timestamp. + * The Route appearing first in alphabetical order by + "{namespace}/{name}". + + + If ties still exist within an HTTPRoute, matching precedence MUST be granted + to the FIRST matching rule (in list order) with a match meeting the above + criteria. + + + When no rules matching a request have been successfully attached to the + parent a request is coming from, a HTTP 404 status code MUST be returned. + items: + properties: + headers: + description: |- + Headers specifies HTTP request header matchers. Multiple match values are + ANDed together, meaning, a request must match all the specified headers + to select the route. + items: + description: |- + HTTPHeaderMatch describes how to select a HTTP route by matching HTTP request + headers. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + + If multiple entries specify equivalent header names, only the first + entry with an equivalent name MUST be considered for a match. Subsequent + entries with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + + + When a header is repeated in an HTTP request, it is + implementation-specific behavior as to how this is represented. + Generally, proxies should follow the guidance from the RFC: + https://www.rfc-editor.org/rfc/rfc7230.html#section-3.2.2 regarding + processing a repeated header, with special handling for "Set-Cookie". + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + type: + default: Exact + description: |- + Type specifies how to match against the value of the header. + + + Support: Core (Exact) + + + Support: Implementation-specific (RegularExpression) + + + Since RegularExpression HeaderMatchType has implementation-specific + conformance, implementations can support POSIX, PCRE or any other dialects + of regular expressions. Please read the implementation's documentation to + determine the supported dialect. + enum: + - Exact + - RegularExpression + type: string + value: + description: Value is the value of HTTP Header to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + path: + description: Path specifies a HTTP request path matcher. + properties: + type: + default: PathPrefix + description: |- + Type specifies how to match against the path Value. + + + Support: Core (Exact, PathPrefix) + + + Support: Implementation-specific (RegularExpression) + enum: + - Exact + - PathPrefix + - RegularExpression + type: string + value: + default: / + description: Value of the HTTP path to match against. + maxLength: 1024 + type: string + type: object + queryParams: + description: |- + QueryParams specifies HTTP query parameter matchers. Multiple match + values are ANDed together, meaning, a request must match all the + specified query parameters to select the route. + + + Support: Extended + items: + description: |- + HTTPQueryParamMatch describes how to select a HTTP route by matching HTTP + query parameters. + properties: + name: + description: |- + Name is the name of the HTTP query param to be matched. This must be an + exact string match. (See + https://tools.ietf.org/html/rfc7230#section-2.7.3). + + + If multiple entries specify equivalent query param names, only the first + entry with an equivalent name MUST be considered for a match. Subsequent + entries with an equivalent query param name MUST be ignored. + + + If a query param is repeated in an HTTP request, the behavior is + purposely left undefined, since different data planes have different + capabilities. However, it is *recommended* that implementations should + match against the first value of the param if the data plane supports it, + as this behavior is expected in other load balancing contexts outside of + the Gateway API. + + + Users SHOULD NOT route traffic based on repeated query params to guard + themselves against potential differences in the implementations. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + type: + default: Exact + description: |- + Type specifies how to match against the value of the query parameter. + + + Support: Extended (Exact) + + + Support: Implementation-specific (RegularExpression) + + + Since RegularExpression QueryParamMatchType has Implementation-specific + conformance, implementations can support POSIX, PCRE or any other + dialects of regular expressions. Please read the implementation's + documentation to determine the supported dialect. + enum: + - Exact + - RegularExpression + type: string + value: + description: Value is the value of HTTP query param to be matched. + maxLength: 1024 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + type: object + maxItems: 8 + type: array + stableTraffic: + description: StableTraffic indicate the base traffic rule + properties: + filters: + description: |- + Filters define the filters that are applied to requests that match + this rule. + + + The effects of ordering of multiple behaviors are currently unspecified. + This can change in the future based on feedback during the alpha stage. + + + Conformance-levels at this level are defined based on the type of filter: + + + - ALL core filters MUST be supported by all implementations. + - Implementers are encouraged to support extended filters. + - Implementation-specific custom filters have no API guarantees across + implementations. + + + Specifying the same filter multiple times is not supported unless explicitly + indicated in the filter. + + + All filters are expected to be compatible with each other except for the + URLRewrite and RequestRedirect filters, which may not be combined. If an + implementation can not support other combinations of filters, they must clearly + document that limitation. In cases where incompatible or unsupported + filters are specified and cause the `Accepted` condition to be set to status + `False`, implementations may use the `IncompatibleFilters` reason to specify + this configuration error. + + + Support: Core + items: + description: |- + HTTPRouteFilter defines processing steps that must be completed during the + request or response lifecycle. HTTPRouteFilters are meant as an extension + point to express processing that may be done in Gateway implementations. Some + examples include request or response modification, implementing + authentication strategies, rate-limiting, and traffic shaping. API + guarantee/conformance is defined based on the type of the filter. + properties: + extensionRef: + description: |- + ExtensionRef is an optional, implementation-specific extension to the + "filter" behavior. For example, resource "myroutefilter" in group + "networking.example.net"). ExtensionRef MUST NOT be used for core and + extended filters. + + + This filter can be used multiple times within the same rule. + + + Support: Implementation-specific + properties: + group: + description: |- + Group is the group of the referent. For example, "gateway.networking.k8s.io". + When unspecified or empty string, core API group is inferred. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + description: Kind is kind of the referent. For example "HTTPRoute" or "Service". + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: Name is the name of the referent. + maxLength: 253 + minLength: 1 + type: string + required: + - group + - kind + - name + type: object + requestHeaderModifier: + description: |- + RequestHeaderModifier defines a schema for a filter that modifies request + headers. + + + Support: Core + properties: + add: + description: |- + Add adds the given header(s) (name, value) to the request + before the action. It appends to any existing values associated + with the header name. + + + Input: + GET /foo HTTP/1.1 + my-header: foo + + + Config: + add: + - name: "my-header" + value: "bar,baz" + + + Output: + GET /foo HTTP/1.1 + my-header: foo,bar,baz + items: + description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + + If multiple entries specify equivalent header names, the first entry with + an equivalent name MUST be considered for a match. Subsequent entries + with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + description: Value is the value of HTTP Header to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + remove: + description: |- + Remove the given header(s) from the HTTP request before the action. The + value of Remove is a list of HTTP header names. Note that the header + names are case-insensitive (see + https://datatracker.ietf.org/doc/html/rfc2616#section-4.2). + + + Input: + GET /foo HTTP/1.1 + my-header1: foo + my-header2: bar + my-header3: baz + + + Config: + remove: ["my-header1", "my-header3"] + + + Output: + GET /foo HTTP/1.1 + my-header2: bar + items: + type: string + maxItems: 16 + type: array + x-kubernetes-list-type: set + set: + description: |- + Set overwrites the request with the given header (name, value) + before the action. + + + Input: + GET /foo HTTP/1.1 + my-header: foo + + + Config: + set: + - name: "my-header" + value: "bar" + + + Output: + GET /foo HTTP/1.1 + my-header: bar + items: + description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + + If multiple entries specify equivalent header names, the first entry with + an equivalent name MUST be considered for a match. Subsequent entries + with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + description: Value is the value of HTTP Header to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + type: object + requestMirror: + description: |- + RequestMirror defines a schema for a filter that mirrors requests. + Requests are sent to the specified destination, but responses from + that destination are ignored. + + + This filter can be used multiple times within the same rule. Note that + not all implementations will be able to support mirroring to multiple + backends. + + + Support: Extended + + + + properties: + backendRef: + description: |- + BackendRef references a resource where mirrored requests are sent. + + + Mirrored requests must be sent only to a single destination endpoint + within this BackendRef, irrespective of how many endpoints are present + within this BackendRef. + + + If the referent cannot be found, this BackendRef is invalid and must be + dropped from the Gateway. The controller must ensure the "ResolvedRefs" + condition on the Route status is set to `status: False` and not configure + this backend in the underlying implementation. + + + If there is a cross-namespace reference to an *existing* object + that is not allowed by a ReferenceGrant, the controller must ensure the + "ResolvedRefs" condition on the Route is set to `status: False`, + with the "RefNotPermitted" reason and not configure this backend in the + underlying implementation. + + + In either error case, the Message of the `ResolvedRefs` Condition + should be used to provide more detail about the problem. + + + Support: Extended for Kubernetes Service + + + Support: Implementation-specific for any other resource + properties: + group: + default: "" + description: |- + Group is the group of the referent. For example, "gateway.networking.k8s.io". + When unspecified or empty string, core API group is inferred. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + default: Service + description: |- + Kind is the Kubernetes resource kind of the referent. For example + "Service". + + + Defaults to "Service" when not specified. + + + ExternalName services can refer to CNAME DNS records that may live + outside of the cluster and as such are difficult to reason about in + terms of conformance. They also may not be safe to forward to (see + CVE-2021-25740 for more information). Implementations SHOULD NOT + support ExternalName Services. + + + Support: Core (Services with a type other than ExternalName) + + + Support: Implementation-specific (Services with type ExternalName) + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: Name is the name of the referent. + maxLength: 253 + minLength: 1 + type: string + namespace: + description: |- + Namespace is the namespace of the backend. When unspecified, the local + namespace is inferred. + + + Note that when a namespace different than the local namespace is specified, + a ReferenceGrant object is required in the referent namespace to allow that + namespace's owner to accept the reference. See the ReferenceGrant + documentation for details. + + + Support: Core + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + port: + description: |- + Port specifies the destination port number to use for this resource. + Port is required when the referent is a Kubernetes Service. In this + case, the port number is the service port number, not the target port. + For other resources, destination port might be derived from the referent + resource or this field. + format: int32 + maximum: 65535 + minimum: 1 + type: integer + required: + - name + type: object + fraction: + description: |- + Fraction represents the fraction of requests that should be + mirrored to BackendRef. + + + Only one of Fraction or Percent may be specified. If neither field + is specified, 100% of requests will be mirrored. + + + + properties: + denominator: + default: 100 + format: int32 + minimum: 1 + type: integer + numerator: + format: int32 + minimum: 0 + type: integer + required: + - numerator + type: object + percent: + description: |- + Percent represents the percentage of requests that should be + mirrored to BackendRef. Its minimum value is 0 (indicating 0% of + requests) and its maximum value is 100 (indicating 100% of requests). + + + Only one of Fraction or Percent may be specified. If neither field + is specified, 100% of requests will be mirrored. + + + + format: int32 + maximum: 100 + minimum: 0 + type: integer + required: + - backendRef + type: object + requestRedirect: + description: |- + RequestRedirect defines a schema for a filter that responds to the + request with an HTTP redirection. + + + Support: Core + properties: + hostname: + description: |- + Hostname is the hostname to be used in the value of the `Location` + header in the response. + When empty, the hostname in the `Host` header of the request is used. + + + Support: Core + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + path: + description: |- + Path defines parameters used to modify the path of the incoming request. + The modified path is then used to construct the `Location` header. When + empty, the request path is used as-is. + + + Support: Extended + properties: + replaceFullPath: + description: |- + ReplaceFullPath specifies the value with which to replace the full path + of a request during a rewrite or redirect. + maxLength: 1024 + type: string + replacePrefixMatch: + description: |- + ReplacePrefixMatch specifies the value with which to replace the prefix + match of a request during a rewrite or redirect. For example, a request + to "/foo/bar" with a prefix match of "/foo" and a ReplacePrefixMatch + of "/xyz" would be modified to "/xyz/bar". + + + Note that this matches the behavior of the PathPrefix match type. This + matches full path elements. A path element refers to the list of labels + in the path split by the `/` separator. When specified, a trailing `/` is + ignored. For example, the paths `/abc`, `/abc/`, and `/abc/def` would all + match the prefix `/abc`, but the path `/abcd` would not. + + + ReplacePrefixMatch is only compatible with a `PathPrefix` HTTPRouteMatch. + Using any other HTTPRouteMatch type on the same HTTPRouteRule will result in + the implementation setting the Accepted Condition for the Route to `status: False`. + + + Request Path | Prefix Match | Replace Prefix | Modified Path + -------------|--------------|----------------|---------- + /foo/bar | /foo | /xyz | /xyz/bar + /foo/bar | /foo | /xyz/ | /xyz/bar + /foo/bar | /foo/ | /xyz | /xyz/bar + /foo/bar | /foo/ | /xyz/ | /xyz/bar + /foo | /foo | /xyz | /xyz + /foo/ | /foo | /xyz | /xyz/ + /foo/bar | /foo | | /bar + /foo/ | /foo | | / + /foo | /foo | | / + /foo/ | /foo | / | / + /foo | /foo | / | / + maxLength: 1024 + type: string + type: + description: |- + Type defines the type of path modifier. Additional types may be + added in a future release of the API. + + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + enum: + - ReplaceFullPath + - ReplacePrefixMatch + type: string + required: + - type + type: object + port: + description: |- + Port is the port to be used in the value of the `Location` + header in the response. + + + If no port is specified, the redirect port MUST be derived using the + following rules: + + + * If redirect scheme is not-empty, the redirect port MUST be the well-known + port associated with the redirect scheme. Specifically "http" to port 80 + and "https" to port 443. If the redirect scheme does not have a + well-known port, the listener port of the Gateway SHOULD be used. + * If redirect scheme is empty, the redirect port MUST be the Gateway + Listener port. + + + Implementations SHOULD NOT add the port number in the 'Location' + header in the following cases: + + + * A Location header that will use HTTP (whether that is determined via + the Listener protocol or the Scheme field) _and_ use port 80. + * A Location header that will use HTTPS (whether that is determined via + the Listener protocol or the Scheme field) _and_ use port 443. + + + Support: Extended + format: int32 + maximum: 65535 + minimum: 1 + type: integer + scheme: + description: |- + Scheme is the scheme to be used in the value of the `Location` header in + the response. When empty, the scheme of the request is used. + + + Scheme redirects can affect the port of the redirect, for more information, + refer to the documentation for the port field of this filter. + + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + + + Support: Extended + enum: + - http + - https + type: string + statusCode: + default: 302 + description: |- + StatusCode is the HTTP status code to be used in response. + + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + + + Support: Core + enum: + - 301 + - 302 + type: integer + type: object + responseHeaderModifier: + description: |- + ResponseHeaderModifier defines a schema for a filter that modifies response + headers. + + + Support: Extended + properties: + add: + description: |- + Add adds the given header(s) (name, value) to the request + before the action. It appends to any existing values associated + with the header name. + + + Input: + GET /foo HTTP/1.1 + my-header: foo + + + Config: + add: + - name: "my-header" + value: "bar,baz" + + + Output: + GET /foo HTTP/1.1 + my-header: foo,bar,baz + items: + description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + + If multiple entries specify equivalent header names, the first entry with + an equivalent name MUST be considered for a match. Subsequent entries + with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + description: Value is the value of HTTP Header to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + remove: + description: |- + Remove the given header(s) from the HTTP request before the action. The + value of Remove is a list of HTTP header names. Note that the header + names are case-insensitive (see + https://datatracker.ietf.org/doc/html/rfc2616#section-4.2). + + + Input: + GET /foo HTTP/1.1 + my-header1: foo + my-header2: bar + my-header3: baz + + + Config: + remove: ["my-header1", "my-header3"] + + + Output: + GET /foo HTTP/1.1 + my-header2: bar + items: + type: string + maxItems: 16 + type: array + x-kubernetes-list-type: set + set: + description: |- + Set overwrites the request with the given header (name, value) + before the action. + + + Input: + GET /foo HTTP/1.1 + my-header: foo + + + Config: + set: + - name: "my-header" + value: "bar" + + + Output: + GET /foo HTTP/1.1 + my-header: bar + items: + description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + + If multiple entries specify equivalent header names, the first entry with + an equivalent name MUST be considered for a match. Subsequent entries + with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + description: Value is the value of HTTP Header to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + type: object + type: + description: |- + Type identifies the type of filter to apply. As with other API fields, + types are classified into three conformance levels: + + + - Core: Filter types and their corresponding configuration defined by + "Support: Core" in this package, e.g. "RequestHeaderModifier". All + implementations must support core filters. + + + - Extended: Filter types and their corresponding configuration defined by + "Support: Extended" in this package, e.g. "RequestMirror". Implementers + are encouraged to support extended filters. + + + - Implementation-specific: Filters that are defined and supported by + specific vendors. + In the future, filters showing convergence in behavior across multiple + implementations will be considered for inclusion in extended or core + conformance levels. Filter-specific configuration for such filters + is specified using the ExtensionRef field. `Type` should be set to + "ExtensionRef" for custom filters. + + + Implementers are encouraged to define custom implementation types to + extend the core API with implementation-specific behavior. + + + If a reference to a custom filter type cannot be resolved, the filter + MUST NOT be skipped. Instead, requests that would have been processed by + that filter MUST receive a HTTP error response. + + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + enum: + - RequestHeaderModifier + - ResponseHeaderModifier + - RequestMirror + - RequestRedirect + - URLRewrite + - ExtensionRef + type: string + urlRewrite: + description: |- + URLRewrite defines a schema for a filter that modifies a request during forwarding. + + + Support: Extended + properties: + hostname: + description: |- + Hostname is the value to be used to replace the Host header value during + forwarding. + + + Support: Extended + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + path: + description: |- + Path defines a path rewrite. + + + Support: Extended + properties: + replaceFullPath: + description: |- + ReplaceFullPath specifies the value with which to replace the full path + of a request during a rewrite or redirect. + maxLength: 1024 + type: string + replacePrefixMatch: + description: |- + ReplacePrefixMatch specifies the value with which to replace the prefix + match of a request during a rewrite or redirect. For example, a request + to "/foo/bar" with a prefix match of "/foo" and a ReplacePrefixMatch + of "/xyz" would be modified to "/xyz/bar". + + + Note that this matches the behavior of the PathPrefix match type. This + matches full path elements. A path element refers to the list of labels + in the path split by the `/` separator. When specified, a trailing `/` is + ignored. For example, the paths `/abc`, `/abc/`, and `/abc/def` would all + match the prefix `/abc`, but the path `/abcd` would not. + + + ReplacePrefixMatch is only compatible with a `PathPrefix` HTTPRouteMatch. + Using any other HTTPRouteMatch type on the same HTTPRouteRule will result in + the implementation setting the Accepted Condition for the Route to `status: False`. + + + Request Path | Prefix Match | Replace Prefix | Modified Path + -------------|--------------|----------------|---------- + /foo/bar | /foo | /xyz | /xyz/bar + /foo/bar | /foo | /xyz/ | /xyz/bar + /foo/bar | /foo/ | /xyz | /xyz/bar + /foo/bar | /foo/ | /xyz/ | /xyz/bar + /foo | /foo | /xyz | /xyz + /foo/ | /foo | /xyz | /xyz/ + /foo/bar | /foo | | /bar + /foo/ | /foo | | / + /foo | /foo | | / + /foo/ | /foo | / | / + /foo | /foo | / | / + maxLength: 1024 + type: string + type: + description: |- + Type defines the type of path modifier. Additional types may be + added in a future release of the API. + + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + enum: + - ReplaceFullPath + - ReplacePrefixMatch + type: string + required: + - type + type: object + type: object + required: + - type + type: object + maxItems: 16 + type: array + matches: + description: |- + Matches define conditions used for matching the rule against incoming + HTTP requests. Each match is independent, i.e. this rule will be matched + if **any** one of the matches is satisfied. + + + For example, take the following matches configuration: + + + ``` + matches: + - path: + value: "/foo" + headers: + - name: "version" + value: "v2" + - path: + value: "/v2/foo" + ``` + + + For a request to match against this rule, a request must satisfy + EITHER of the two conditions: + + + - path prefixed with `/foo` AND contains the header `version: v2` + - path prefix of `/v2/foo` + + + See the documentation for HTTPRouteMatch on how to specify multiple + match conditions that should be ANDed together. + + + If no matches are specified, the default is a prefix + path match on "/", which has the effect of matching every + HTTP request. + + + Proxy or Load Balancer routing configuration generated from HTTPRoutes + MUST prioritize matches based on the following criteria, continuing on + ties. Across all rules specified on applicable Routes, precedence must be + given to the match having: + + + * "Exact" path match. + * "Prefix" path match with largest number of characters. + * Method match. + * Largest number of header matches. + * Largest number of query param matches. + + + Note: The precedence of RegularExpression path matches are implementation-specific. + + + If ties still exist across multiple Routes, matching precedence MUST be + determined in order of the following criteria, continuing on ties: + + + * The oldest Route based on creation timestamp. + * The Route appearing first in alphabetical order by + "{namespace}/{name}". + + + If ties still exist within an HTTPRoute, matching precedence MUST be granted + to the FIRST matching rule (in list order) with a match meeting the above + criteria. + + + When no rules matching a request have been successfully attached to the + parent a request is coming from, a HTTP 404 status code MUST be returned. + items: + properties: + headers: + description: |- + Headers specifies HTTP request header matchers. Multiple match values are + ANDed together, meaning, a request must match all the specified headers + to select the route. + items: + description: |- + HTTPHeaderMatch describes how to select a HTTP route by matching HTTP request + headers. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + + If multiple entries specify equivalent header names, only the first + entry with an equivalent name MUST be considered for a match. Subsequent + entries with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + + + When a header is repeated in an HTTP request, it is + implementation-specific behavior as to how this is represented. + Generally, proxies should follow the guidance from the RFC: + https://www.rfc-editor.org/rfc/rfc7230.html#section-3.2.2 regarding + processing a repeated header, with special handling for "Set-Cookie". + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + type: + default: Exact + description: |- + Type specifies how to match against the value of the header. + + + Support: Core (Exact) + + + Support: Implementation-specific (RegularExpression) + + + Since RegularExpression HeaderMatchType has implementation-specific + conformance, implementations can support POSIX, PCRE or any other dialects + of regular expressions. Please read the implementation's documentation to + determine the supported dialect. + enum: + - Exact + - RegularExpression + type: string + value: + description: Value is the value of HTTP Header to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + path: + description: Path specifies a HTTP request path matcher. + properties: + type: + default: PathPrefix + description: |- + Type specifies how to match against the path Value. + + + Support: Core (Exact, PathPrefix) + + + Support: Implementation-specific (RegularExpression) + enum: + - Exact + - PathPrefix + - RegularExpression + type: string + value: + default: / + description: Value of the HTTP path to match against. + maxLength: 1024 + type: string + type: object + queryParams: + description: |- + QueryParams specifies HTTP query parameter matchers. Multiple match + values are ANDed together, meaning, a request must match all the + specified query parameters to select the route. + + + Support: Extended + items: + description: |- + HTTPQueryParamMatch describes how to select a HTTP route by matching HTTP + query parameters. + properties: + name: + description: |- + Name is the name of the HTTP query param to be matched. This must be an + exact string match. (See + https://tools.ietf.org/html/rfc7230#section-2.7.3). + + + If multiple entries specify equivalent query param names, only the first + entry with an equivalent name MUST be considered for a match. Subsequent + entries with an equivalent query param name MUST be ignored. + + + If a query param is repeated in an HTTP request, the behavior is + purposely left undefined, since different data planes have different + capabilities. However, it is *recommended* that implementations should + match against the first value of the param if the data plane supports it, + as this behavior is expected in other load balancing contexts outside of + the Gateway API. + + + Users SHOULD NOT route traffic based on repeated query params to guard + themselves against potential differences in the implementations. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + type: + default: Exact + description: |- + Type specifies how to match against the value of the query parameter. + + + Support: Extended (Exact) + + + Support: Implementation-specific (RegularExpression) + + + Since RegularExpression QueryParamMatchType has Implementation-specific + conformance, implementations can support POSIX, PCRE or any other + dialects of regular expressions. Please read the implementation's + documentation to determine the supported dialect. + enum: + - Exact + - RegularExpression + type: string + value: + description: Value is the value of HTTP query param to be matched. + maxLength: 1024 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + type: object + maxItems: 8 + type: array + type: object + weight: + description: Weight indicate how many percentage of traffic the canary pods should receive + format: int32 + maximum: 100 + minimum: 0 + type: integer + type: object + type: object required: - - status - - type + - targets type: object - type: array - lastUpdateTime: - description: The last time this status was updated. - format: date-time - type: string - observedGeneration: - description: |- - ObservedGeneration is the most recent generation observed for this Rollout. It corresponds to the - Rollout's generation, which is updated on mutation by the API Server. - format: int64 - type: integer - phase: - description: Phase indicates the current phase of rollout - type: string - rolloutID: - description: RolloutID is reference to rolloutRun name. - type: string - workloadStatuses: - description: WorkloadStatuses describes the referenced workloads status - items: + disabled: + description: |- + Disabled means that rollout will not response for new event. + Default value is false. + type: boolean + historyLimit: + default: 10 + description: |- + HistoryLimit defines the maximum number of completed rolloutRun + history records to keep. + The HistoryLimit can start from 0 (no retained RolloutRun history). + When not set or set to math.MaxInt32, the Rollout will keep all RolloutRun history records. + format: int32 + type: integer + strategyRef: + description: |- + StrategyRef is the reference to the rollout strategy. + Mutually exclusive with CanaryStrategy and BatchStrategy. + If specified, CanaryStrategy and BatchStrategy must be empty. + type: string + trafficTopologyRefs: + description: |- + TrafficTopologyRefs defines the networking traffic relationships between + workloads, backend services, and routes. + items: + type: string + type: array + triggerPolicy: + default: Auto + description: TriggerPolicy defines when rollout will be triggered + type: string + workloadRef: + description: WorkloadRef is a reference to a kind of workloads properties: - availableReplicas: - description: AvailableReplicas is the number of service available - pods targeted by workload. - format: int32 - type: integer - cluster: - description: Cluster defines which cluster the workload is in. + apiVersion: + description: |- + APIVersion is the group/version for the resource being referenced. + If APIVersion is not specified, the specified Kind must be in the core API group. + For any other third-party types, APIVersion is required. type: string - generation: - description: Generation is the found in workload metadata. - format: int64 - type: integer - name: - description: Name is the workload name - type: string - observedGeneration: - description: ObservedGeneration is the most recent generation - observed for this workload. - format: int64 - type: integer - replicas: - description: Replicas is the desired number of pods targeted - by workload - format: int32 - type: integer - stableRevision: - description: StableRevision is the old stable revision used - to generate pods. - type: string - updatedAvailableReplicas: - description: UpdatedAvailableReplicas is the number of service - available pods targeted by workload that have the updated - template spec. - format: int32 - type: integer - updatedReadyReplicas: - description: UpdatedReadyReplicas is the number of ready pods - targeted by workload that have the updated template spec. - format: int32 - type: integer - updatedReplicas: - description: UpdatedReplicas is the number of pods targeted - by workload that have the updated template spec. - format: int32 - type: integer - updatedRevision: - description: UpdatedRevision is the updated template revision - used to generate pods. + kind: + description: Kind is the type of resource being referenced type: string + match: + description: Match indicates how to match workloads. only one workload should be matches in one cluster + properties: + names: + description: Names is a list of workload name + items: + description: CrossClusterObjectNameReference contains cluster and name reference to a k8s object + properties: + cluster: + description: Cluster indicates the name of cluster + type: string + name: + description: Name is the resource name + type: string + required: + - name + type: object + type: array + selector: + description: Selector is a label query over a set of resources, in this case resource + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + type: object required: - - replicas - - updatedAvailableReplicas - - updatedReadyReplicas - - updatedReplicas + - kind + - match type: object - type: array - type: object - type: object - served: true - storage: true - subresources: - status: {} + type: object + status: + description: RolloutStatus defines the observed state of Rollout + properties: + conditions: + description: Conditions is the list of conditions + items: + description: |- + Condition defines the condition of a resource + See: https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#typical-status-properties + properties: + lastTransitionTime: + description: Last time the condition transitioned from one status to another. + format: date-time + type: string + lastUpdateTime: + description: The last time this condition was updated. + format: date-time + type: string + message: + description: A human-readable message indicating details about the transition. + type: string + reason: + description: The reason for the condition's last transition. + type: string + status: + description: Status of the condition, one of True, False, Unknown. + type: string + type: + description: Type of the condition. + type: string + required: + - status + - type + type: object + type: array + lastUpdateTime: + description: The last time this status was updated. + format: date-time + type: string + observedGeneration: + description: |- + ObservedGeneration is the most recent generation observed for this Rollout. It corresponds to the + Rollout's generation, which is updated on mutation by the API Server. + format: int64 + type: integer + phase: + description: Phase indicates the current phase of rollout + type: string + rolloutID: + description: RolloutID is reference to rolloutRun name. + type: string + workloadStatuses: + description: WorkloadStatuses describes the referenced workloads status + items: + properties: + availableReplicas: + description: AvailableReplicas is the number of service available pods targeted by workload. + format: int32 + type: integer + cluster: + description: Cluster defines which cluster the workload is in. + type: string + generation: + description: Generation is the found in workload metadata. + format: int64 + type: integer + name: + description: Name is the workload name + type: string + observedGeneration: + description: ObservedGeneration is the most recent generation observed for this workload. + format: int64 + type: integer + replicas: + description: Replicas is the desired number of pods targeted by workload + format: int32 + type: integer + stableRevision: + description: StableRevision is the old stable revision used to generate pods. + type: string + updatedAvailableReplicas: + description: UpdatedAvailableReplicas is the number of service available pods targeted by workload that have the updated template spec. + format: int32 + type: integer + updatedReadyReplicas: + description: UpdatedReadyReplicas is the number of ready pods targeted by workload that have the updated template spec. + format: int32 + type: integer + updatedReplicas: + description: UpdatedReplicas is the number of pods targeted by workload that have the updated template spec. + format: int32 + type: integer + updatedRevision: + description: UpdatedRevision is the updated template revision used to generate pods. + type: string + type: object + type: array + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/go.mod b/go.mod index 84f51fe..c4b22f3 100644 --- a/go.mod +++ b/go.mod @@ -23,7 +23,7 @@ require ( k8s.io/klog/v2 v2.130.1 k8s.io/kubernetes v1.22.2 k8s.io/utils v0.0.0-20241210054802-24370beab758 - kusionstack.io/kube-api v0.7.5-0.20251222101808-6d5bc2b4ac64 + kusionstack.io/kube-api v0.7.5-0.20260306081812-18b6128bc6fb kusionstack.io/kube-utils v0.2.1-0.20251125083928-1134a582b341 kusionstack.io/resourceconsist v0.0.4 sigs.k8s.io/controller-runtime v0.21.0 diff --git a/go.sum b/go.sum index e9c0315..210f4b5 100644 --- a/go.sum +++ b/go.sum @@ -1021,8 +1021,8 @@ k8s.io/sample-apiserver v0.22.2/go.mod h1:h+/DIV5EmuNq4vfPr5TSXy9mIBVXXlPAKQMPbj k8s.io/system-validators v1.5.0/go.mod h1:bPldcLgkIUK22ALflnsXk8pvkTEndYdNuaHH6gRrl0Q= k8s.io/utils v0.0.0-20240102154912-e7106e64919e h1:eQ/4ljkx21sObifjzXwlPKpdGLrCfRziVtos3ofG/sQ= k8s.io/utils v0.0.0-20240102154912-e7106e64919e/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= -kusionstack.io/kube-api v0.7.5-0.20251222101808-6d5bc2b4ac64 h1:iXxFN0KuDBLRlTs5lJgFBSitzSVn9kiV2l0uZZZo6Dg= -kusionstack.io/kube-api v0.7.5-0.20251222101808-6d5bc2b4ac64/go.mod h1:e1jtrQH2LK5fD2nTyfIXG6nYrYbU8VXShRxTRwVPaLk= +kusionstack.io/kube-api v0.7.5-0.20260306081812-18b6128bc6fb h1:ODxnOte9umQL5yjsNjnGj+OmNqZRx/NtjaYgJteemW8= +kusionstack.io/kube-api v0.7.5-0.20260306081812-18b6128bc6fb/go.mod h1:e1jtrQH2LK5fD2nTyfIXG6nYrYbU8VXShRxTRwVPaLk= kusionstack.io/kube-utils v0.2.1-0.20251125083928-1134a582b341 h1:dnMtHJvIpU3338WpqGiNN2qXWZFiXaoiuzR9jwhvWpg= kusionstack.io/kube-utils v0.2.1-0.20251125083928-1134a582b341/go.mod h1:Lz5SBYWg9+jw+kP0CAyf/b62D5DeUPf6+jE1d0WC4cI= kusionstack.io/resourceconsist v0.0.4 h1:wRqLJuNh8O4TT6p0uOklFpHUKiRdRxcAH71Sw/q9LhE= diff --git a/pkg/controllers/rollout/CLAUDE.md b/pkg/controllers/rollout/CLAUDE.md new file mode 100644 index 0000000..28bd03d --- /dev/null +++ b/pkg/controllers/rollout/CLAUDE.md @@ -0,0 +1,201 @@ +# Rollout Controller 目录逻辑说明 + +## 概述 + +Rollout Controller 是 KusionStack Rollout 的核心控制器之一,负责管理 Rollout 资源的生命周期,协调工作负载的渐进式发布流程。基于 [渐进式交付 Rollout 设计文档](https://yuque.antfin.com/antcloud-paas/dp4wap/ae5myagvwh96cugn),Rollout Controller 实现了跨集群的发布管理功能。 + +## 核心职责 + +1. **管理 Rollout 生命周期** - 监听 Rollout 资源变化,计算状态 +2. **关联工作负载** - 根据 WorkloadRef 匹配并标记受管工作负载 +3. **触发发布流程** - 根据触发策略创建 RolloutRun +4. **协调 RolloutRun** - 监控 RolloutRun 状态,处理用户命令 +5. **资源清理** - 清理历史 RolloutRun,处理 Finalizer + +## 目录结构 + +``` +rollout/ +├── rollout_controller.go # 主控制器逻辑 +├── event_handler.go # 事件处理器 +├── utils.go # 工具函数 +└── initializer.go # 控制器初始化 +``` + +## 核心数据结构 + +### RolloutReconciler + +```go +type RolloutReconciler struct { + *mixin.ReconcilerMixin // 混入基础控制器能力 + workloadRegistry registry.WorkloadRegistry // 工作负载注册表 + expectation expectations.ControllerExpectationsInterface // 控制器期望 + rvExpectation expectations.ResourceVersionExpectationInterface // 资源版本期望 +} +``` + +## Reconcile 流程 + +### SetupWithManager + +```go +func (r *RolloutReconciler) SetupWithManager(mgr ctrl.Manager) error +``` + +监听的资源: +- `Rollout` - 使用 `ResourceVersionChangedPredicate` 过滤 +- `RolloutRun` (跨集群) - 使用创建观察处理器 +- `RolloutStrategy` - 策略变化触发 +- 所有已注册的 workload 类型 (Deployment, CloneSet, CollaSet 等) + +### Reconcile 八步流程 + +```go +func (r *RolloutReconciler) Reconcile(ctx context.Context, req ctrl.Request) +``` + +1. **检查期望满足** + - 资源版本期望 + - 控制器期望 + +2. **计算新状态** + - 根据对象状态计算 Phase: `Initialized`/`Progressing`/`Disabled`/`Terminating` + +3. **管理 Finalizer** + - 添加/删除 `rollout.kusionstack.io/cleanup` finalizer + +4. **查找工作负载** (跨集群) + - 根据资源匹配规则查找关联的工作负载 + +5. **获取 RolloutRun 列表** + - 当前运行的 RolloutRun + - 历史完成的 RolloutRun + +6. **清理历史记录** + - 根据 `HistoryLimit` 删除旧的完成 RolloutRun + +7. **按阶段处理** + - `Disabled`: 仅同步状态 + - `Terminating`: 执行清理 + - `Progressing`/`Waiting`: 处理发布逻辑 + +8. **更新状态** + - 更新 RolloutStatus + +## 关键函数 + +### 状态计算 + +| 函数 | 说明 | +|------|------| +| `calculateStatus()` | 根据对象状态计算 Phase | +| `updateStatusOnly()` | 仅更新状态,不触发 reconcile 回头 | + +### Finalizer 管理 + +| 函数 | 说明 | +|------|------| +| `ensureFinalizer()` | 添加/删除 Finalizer | +| `handleFinalizing()` | 清理工作负载标签 | + +### 发布触发 + +| 函数 | 说明 | +|------|------| +| `shouldTrigger()` | 判断是否应该触发发布 | +| `syncRun()` | 同步 RolloutRun 创建/状态 | + +### 触发策略 + +#### Auto (自动触发) - 默认 +- 当所有关联的工作负载都标记为 `waiting for rollout` 时触发 + +#### Manual (手动触发) +- 禁止自动触发,完全由用户控制 + +#### Annotation (主动触发) +- 添加 annotation `rollout.kusionstack.io/trigger: "triggerName"` +- 强制创建 RolloutRun,即使工作负载未全部就绪 + +### 工作负载管理 + +| 函数 | 说明 | +|------|------| +| `findWorkloadsCrossCluster()` | 跨集群查找工作负载 | +| `ensureWorkloadsLabelAndAnnotations()` | 添加 rollout 管理标签 | + +### 历史清理 + +| 函数 | 说明 | +|------|------| +| `leanupHistory()` | 根据 HistoryLimit 删除旧记录 | +| `getAllRolloutRun()` | 获取所有 RolloutRun | + +### 命令处理 + +| 函数 | 说明 | +|------|------| +| `handleRunManualCommand()` | 处理用户手动命令 | +| `applyOneTimeStrategy()` | 应用一次性策略 | + +## Phase 状态机 + +``` +┌──────────────┐ +│ Disabled │ ← spec.disabled = true +└──────────────┘ + ↓ +┌──────────────┐ +│ Initialized │ ← 默认初始状态 +└──────────────┘ + ↓ (触发) +┌──────────────┐ +│ Progressing │ ← RolloutRun 运行中 +└──────────────┘ + ↓ +┌──────────────┐ +│ Terminating │ ← deletionTimestamp != nil +└──────────────┘ +``` + +## Annotation 用途 + +| Annotation | 说明 | +|------------|------| +| `rollout.kusionstack.io/trigger` | 主动触发 RolloutRun | +| `rollout.kusionstack.io/manual-command` | 手动命令传递 | +| `rollout.kusionstack.io/one-time-strategy` | 一次性策略 | + +## Label 用途 + +| Label | 说明 | +|-------|------| +| `rollout.kusionstack.io/workload` | 标记被 Rollout 管理的工作负载 | +| `rollout.kusionstack.io/disabled` | 跳过 Rollout 流程 | + +## 事件记录 + +通过 `recordCondition()` 记录以下条件: + +| Condition | 说明 | +|-----------|------| +| `Available` | 依赖资源是否就绪 | +| `Trigger` | 触发状态 | +| `Progressing` | 进度状态 | +| `Terminating` | 终止状态 | + +## Finalizer 用途 + +``` +rollout.kusionstack.io/cleanup +``` + +保证 Rollout 被删除时能正确清理工作负载的标签和 annotation。 + +## 关键设计决策 + +1. **期望机制** - 使用期望减少不必要的 reconcile +2. **ResourceVersion 过滤** - 只处理实际变化的资源 +3. **跨集群支持** - 通过 clusterinfo 管理多集群 +4. **createCommand 优先** - 处理命令优先于状态检查 \ No newline at end of file diff --git a/pkg/controllers/rollout/inline_strategy.go b/pkg/controllers/rollout/inline_strategy.go new file mode 100644 index 0000000..26fcab8 --- /dev/null +++ b/pkg/controllers/rollout/inline_strategy.go @@ -0,0 +1,184 @@ +// Copyright 2025 The KusionStack Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package rollout + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + rolloutapi "kusionstack.io/kube-api/rollout" + rolloutv1alpha1 "kusionstack.io/kube-api/rollout/v1alpha1" + + "kusionstack.io/rollout/pkg/features" + "kusionstack.io/rollout/pkg/features/ontimestrategy" + "kusionstack.io/rollout/pkg/workload" +) + +// constructRolloutRunFromInlineStrategy constructs RolloutRun from inline strategy +// Returns the constructed RolloutRun and a boolean indicating if inline strategy was used +func constructRolloutRunFromInlineStrategy( + obj *rolloutv1alpha1.Rollout, + workloadWrappers []*workload.Info, + rolloutId string, +) (*rolloutv1alpha1.RolloutRun, bool) { + if obj.Spec.BatchStrategy == nil { + return nil, false + } + + // Build workload map for validation + workloadMap := buildWorkloadMap(workloadWrappers) + + owner := metav1.NewControllerRef(obj, rolloutv1alpha1.SchemeGroupVersion.WithKind("Rollout")) + run := &rolloutv1alpha1.RolloutRun{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: obj.Namespace, + Name: rolloutId, + Labels: map[string]string{}, + Annotations: map[string]string{}, + OwnerReferences: []metav1.OwnerReference{*owner}, + Finalizers: []string{rolloutapi.FinalizerRolloutProtection}, + }, + Spec: rolloutv1alpha1.RolloutRunSpec{ + TargetType: rolloutv1alpha1.ObjectTypeRef{ + APIVersion: obj.Spec.WorkloadRef.APIVersion, + Kind: obj.Spec.WorkloadRef.Kind, + }, + TrafficTopologyRefs: obj.Spec.TrafficTopologyRefs, + Webhooks: []rolloutv1alpha1.RolloutWebhook{}, // Empty for inline strategy + }, + } + + if obj.Spec.CanaryStrategy != nil { + canary := validateAndCopyCanaryStrategy(obj.Spec.CanaryStrategy, workloadMap) + run.Spec.Canary = canary + } + + batch := validateAndCopyBatchStrategy(obj.Spec.BatchStrategy, workloadMap) + run.Spec.Batch = batch + + // Set OneTimeStrategy annotation for inline batch strategy + if features.DefaultFeatureGate.Enabled(features.OneTimeStrategy) { + onetime := ontimestrategy.ConvertFromInline(run.Spec.Batch) + data := onetime.JSONData() + run.Annotations[ontimestrategy.AnnoOneTimeStrategy] = string(data) + } + + if features.DefaultFeatureGate.Enabled(features.RolloutClassPredicate) { + class, ok := obj.Labels[rolloutapi.LabelRolloutClass] + if ok { + run.Labels[rolloutapi.LabelRolloutClass] = class + } + } + + return run, true +} + +// validateAndCopyCanaryStrategy validates targets and creates a copy for RolloutRun +// For inline strategy, targets are already pre-resolved by user +func validateAndCopyCanaryStrategy( + canary *rolloutv1alpha1.RolloutRunCanaryStrategy, + workloadMap map[string]*workload.Info, +) *rolloutv1alpha1.RolloutRunCanaryStrategy { + if canary == nil { + return nil + } + + // Validate targets exist + validatedTargets := make([]rolloutv1alpha1.RolloutRunStepTarget, 0, len(canary.Targets)) + for _, target := range canary.Targets { + key := workloadKey(target.Cluster, target.Name) + if _, exists := workloadMap[key]; !exists { + // Skip targets that don't exist in actual workloads + continue + } + // Direct copy - targets are already in correct format + validatedTargets = append(validatedTargets, target) + } + + return &rolloutv1alpha1.RolloutRunCanaryStrategy{ + Targets: validatedTargets, + Traffic: canary.Traffic, + Properties: canary.Properties, + TemplateMetadataPatch: canary.TemplateMetadataPatch, + } +} + +// validateAndCopyBatchStrategy validates and creates a copy for RolloutRun +// For inline strategy, targets are already pre-resolved by user +func validateAndCopyBatchStrategy( + batch *rolloutv1alpha1.RolloutRunBatchStrategy, + workloadMap map[string]*workload.Info, +) *rolloutv1alpha1.RolloutRunBatchStrategy { + if batch == nil { + return nil + } + + if len(batch.Batches) == 0 { + // Return as-is if no batches defined + return &rolloutv1alpha1.RolloutRunBatchStrategy{ + Toleration: batch.Toleration, + Batches: []rolloutv1alpha1.RolloutRunStep{}, + } + } + + validatedBatches := make([]rolloutv1alpha1.RolloutRunStep, 0, len(batch.Batches)) + + for _, step := range batch.Batches { + if len(step.Targets) == 0 { + // Skip steps without targets + continue + } + + // Validate and filter targets that exist + validatedTargets := make([]rolloutv1alpha1.RolloutRunStepTarget, 0, len(step.Targets)) + for _, target := range step.Targets { + key := workloadKey(target.Cluster, target.Name) + if _, exists := workloadMap[key]; !exists { + // Skip targets that don't exist in actual workloads + continue + } + // Direct copy - targets are already in correct format + validatedTargets = append(validatedTargets, target) + } + + if len(validatedTargets) > 0 { + validatedStep := rolloutv1alpha1.RolloutRunStep{ + Targets: validatedTargets, + Traffic: step.Traffic, + Breakpoint: step.Breakpoint, + Properties: step.Properties, + } + validatedBatches = append(validatedBatches, validatedStep) + } + } + + return &rolloutv1alpha1.RolloutRunBatchStrategy{ + Toleration: batch.Toleration, + Batches: validatedBatches, + } +} + +// Helper functions + +func buildWorkloadMap(workloads []*workload.Info) map[string]*workload.Info { + m := make(map[string]*workload.Info) + for _, wl := range workloads { + key := workloadKey(wl.ClusterName, wl.Name) + m[key] = wl + } + return m +} + +func workloadKey(cluster, name string) string { + return cluster + "/" + name +} diff --git a/pkg/controllers/rollout/inline_strategy_test.go b/pkg/controllers/rollout/inline_strategy_test.go new file mode 100644 index 0000000..0ca1aec --- /dev/null +++ b/pkg/controllers/rollout/inline_strategy_test.go @@ -0,0 +1,619 @@ +// Copyright 2025 The KusionStack Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package rollout + +import ( + "reflect" + "testing" + + "github.com/davecgh/go-spew/spew" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/intstr" + "k8s.io/utils/ptr" + rolloutv1alpha1 "kusionstack.io/kube-api/rollout/v1alpha1" + + "kusionstack.io/rollout/pkg/workload" +) + +func Test_constructRolloutRunFromInlineStrategy(t *testing.T) { + tests := []struct { + name string + obj *rolloutv1alpha1.Rollout + workloadWrappers []*workload.Info + rolloutId string + wantRun bool + wantCanary bool + wantBatch bool + }{ + { + name: "no inline strategy - return nil, false", + obj: &rolloutv1alpha1.Rollout{ + Spec: rolloutv1alpha1.RolloutSpec{ + StrategyRef: "default-strategy", + WorkloadRef: rolloutv1alpha1.WorkloadRef{ + APIVersion: "apps/v1", + Kind: "Deployment", + }, + }, + }, + workloadWrappers: []*workload.Info{ + newTestInfo("cluster-a", "test", "test-1"), + }, + rolloutId: "test-rollout-1", + wantRun: false, + }, + { + name: "only canary strategy - should return nil (batch strategy required)", + obj: &rolloutv1alpha1.Rollout{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "test", + Name: "test-rollout", + }, + Spec: rolloutv1alpha1.RolloutSpec{ + WorkloadRef: rolloutv1alpha1.WorkloadRef{ + APIVersion: "apps/v1", + Kind: "Deployment", + }, + CanaryStrategy: &rolloutv1alpha1.RolloutRunCanaryStrategy{ + Targets: []rolloutv1alpha1.RolloutRunStepTarget{ + { + CrossClusterObjectNameReference: rolloutv1alpha1.CrossClusterObjectNameReference{ + Cluster: "cluster-a", + Name: "test-1", + }, + Replicas: intstr.FromString("10%"), + }, + }, + }, + }, + }, + workloadWrappers: []*workload.Info{ + newTestInfo("cluster-a", "test", "test-1"), + }, + rolloutId: "test-rollout-1", + wantRun: false, // Canary alone is not supported, need BatchStrategy + wantCanary: false, + wantBatch: false, + }, + { + name: "only batch strategy", + obj: &rolloutv1alpha1.Rollout{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "test", + Name: "test-rollout", + }, + Spec: rolloutv1alpha1.RolloutSpec{ + WorkloadRef: rolloutv1alpha1.WorkloadRef{ + APIVersion: "apps/v1", + Kind: "Deployment", + }, + BatchStrategy: &rolloutv1alpha1.RolloutRunBatchStrategy{ + Batches: []rolloutv1alpha1.RolloutRunStep{ + { + Breakpoint: true, + Targets: []rolloutv1alpha1.RolloutRunStepTarget{ + { + CrossClusterObjectNameReference: rolloutv1alpha1.CrossClusterObjectNameReference{ + Cluster: "cluster-a", + Name: "test-1", + }, + Replicas: intstr.FromString("20%"), + }, + }, + }, + { + Targets: []rolloutv1alpha1.RolloutRunStepTarget{ + { + CrossClusterObjectNameReference: rolloutv1alpha1.CrossClusterObjectNameReference{ + Cluster: "cluster-a", + Name: "test-1", + }, + Replicas: intstr.FromString("100%"), + }, + }, + }, + }, + }, + }, + }, + workloadWrappers: []*workload.Info{ + newTestInfo("cluster-a", "test", "test-1"), + }, + rolloutId: "test-rollout-1", + wantRun: true, + wantCanary: false, + wantBatch: true, + }, + { + name: "canary + batch strategy together", + obj: &rolloutv1alpha1.Rollout{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "test", + Name: "test-rollout", + }, + Spec: rolloutv1alpha1.RolloutSpec{ + WorkloadRef: rolloutv1alpha1.WorkloadRef{ + APIVersion: "apps/v1", + Kind: "Deployment", + }, + CanaryStrategy: &rolloutv1alpha1.RolloutRunCanaryStrategy{ + Targets: []rolloutv1alpha1.RolloutRunStepTarget{ + { + CrossClusterObjectNameReference: rolloutv1alpha1.CrossClusterObjectNameReference{ + Cluster: "cluster-a", + Name: "test-1", + }, + Replicas: intstr.FromString("5%"), + }, + }, + }, + BatchStrategy: &rolloutv1alpha1.RolloutRunBatchStrategy{ + Batches: []rolloutv1alpha1.RolloutRunStep{ + { + Breakpoint: true, + Targets: []rolloutv1alpha1.RolloutRunStepTarget{ + { + CrossClusterObjectNameReference: rolloutv1alpha1.CrossClusterObjectNameReference{ + Cluster: "cluster-a", + Name: "test-1", + }, + Replicas: intstr.FromString("25%"), + }, + }, + }, + }, + }, + }, + }, + workloadWrappers: []*workload.Info{ + newTestInfo("cluster-a", "test", "test-1"), + }, + rolloutId: "test-rollout-1", + wantRun: true, + wantCanary: true, + wantBatch: true, + }, + { + name: "filter non-existent workloads", + obj: &rolloutv1alpha1.Rollout{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "test", + Name: "test-rollout", + }, + Spec: rolloutv1alpha1.RolloutSpec{ + WorkloadRef: rolloutv1alpha1.WorkloadRef{ + APIVersion: "apps/v1", + Kind: "Deployment", + }, + BatchStrategy: &rolloutv1alpha1.RolloutRunBatchStrategy{ + Batches: []rolloutv1alpha1.RolloutRunStep{ + { + Targets: []rolloutv1alpha1.RolloutRunStepTarget{ + { + CrossClusterObjectNameReference: rolloutv1alpha1.CrossClusterObjectNameReference{ + Cluster: "cluster-a", + Name: "test-1", + }, + Replicas: intstr.FromString("20%"), + }, + { + CrossClusterObjectNameReference: rolloutv1alpha1.CrossClusterObjectNameReference{ + Cluster: "cluster-b", // This workload doesn't exist + Name: "test-1", + }, + Replicas: intstr.FromString("30%"), + }, + }, + }, + }, + }, + }, + }, + workloadWrappers: []*workload.Info{ + newTestInfo("cluster-a", "test", "test-1"), + // cluster-b/test-1 is not in workloads + }, + rolloutId: "test-rollout-1", + wantRun: true, + wantCanary: false, + wantBatch: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + run, gotInline := constructRolloutRunFromInlineStrategy(tt.obj, tt.workloadWrappers, tt.rolloutId) + if gotInline != tt.wantRun { + t.Errorf("constructRolloutRunFromInlineStrategy() gotInline = %v, want %v", gotInline, tt.wantRun) + return + } + + if !tt.wantRun { + if run != nil { + t.Errorf("constructRolloutRunFromInlineStrategy() expected nil run, got %v", run) + } + return + } + + if run == nil { + t.Errorf("constructRolloutRunFromInlineStrategy() expected non-nil run, got nil") + return + } + + // Verify basic fields + if run.Name != tt.rolloutId { + t.Errorf("run.Name = %v, want %v", run.Name, tt.rolloutId) + } + if run.Namespace != tt.obj.Namespace { + t.Errorf("run.Namespace = %v, want %v", run.Namespace, tt.obj.Namespace) + } + + // Verify Canary + if tt.wantCanary { + if run.Spec.Canary == nil { + t.Errorf("run.Spec.Canary = nil, want non-nil") + } else if len(run.Spec.Canary.Targets) == 0 { + t.Errorf("run.Spec.Canary.Targets is empty") + } + } + + // Verify Batch + if tt.wantBatch { + if run.Spec.Batch == nil { + t.Errorf("run.Spec.Batch = nil, want non-nil") + } else if len(run.Spec.Batch.Batches) == 0 { + t.Errorf("run.Spec.Batch.Batches is empty") + } + } + + // Verify owner reference + if len(run.OwnerReferences) != 1 { + t.Errorf("len(run.OwnerReferences) = %v, want 1", len(run.OwnerReferences)) + } + }) + } +} + +func Test_validateAndCopyBatchStrategy(t *testing.T) { + tests := []struct { + name string + batch *rolloutv1alpha1.RolloutRunBatchStrategy + workloadMap map[string]*workload.Info + want *rolloutv1alpha1.RolloutRunBatchStrategy + }{ + { + name: "nil batch", + batch: nil, + workloadMap: map[string]*workload.Info{}, + want: nil, + }, + { + name: "empty batches", + batch: &rolloutv1alpha1.RolloutRunBatchStrategy{}, + workloadMap: map[string]*workload.Info{ + "cluster-a/test-1": newTestInfo("cluster-a", "test", "test-1"), + }, + want: &rolloutv1alpha1.RolloutRunBatchStrategy{ + Batches: []rolloutv1alpha1.RolloutRunStep{}, + }, + }, + { + name: "batch with targets - all exist", + batch: &rolloutv1alpha1.RolloutRunBatchStrategy{ + Batches: []rolloutv1alpha1.RolloutRunStep{ + { + Breakpoint: true, + Targets: []rolloutv1alpha1.RolloutRunStepTarget{ + { + CrossClusterObjectNameReference: rolloutv1alpha1.CrossClusterObjectNameReference{ + Cluster: "cluster-a", + Name: "test-1", + }, + Replicas: intstr.FromString("20%"), + }, + { + CrossClusterObjectNameReference: rolloutv1alpha1.CrossClusterObjectNameReference{ + Cluster: "cluster-b", + Name: "test-1", + }, + Replicas: intstr.FromString("30%"), + ReplicaSlidingWindow: ptr.To(intstr.FromString("10%")), + }, + }, + }, + }, + }, + workloadMap: map[string]*workload.Info{ + "cluster-a/test-1": newTestInfo("cluster-a", "test", "test-1"), + "cluster-b/test-1": newTestInfo("cluster-b", "test", "test-1"), + }, + want: &rolloutv1alpha1.RolloutRunBatchStrategy{ + Batches: []rolloutv1alpha1.RolloutRunStep{ + { + Breakpoint: true, + Targets: []rolloutv1alpha1.RolloutRunStepTarget{ + { + CrossClusterObjectNameReference: rolloutv1alpha1.CrossClusterObjectNameReference{ + Cluster: "cluster-a", + Name: "test-1", + }, + Replicas: intstr.FromString("20%"), + }, + { + CrossClusterObjectNameReference: rolloutv1alpha1.CrossClusterObjectNameReference{ + Cluster: "cluster-b", + Name: "test-1", + }, + Replicas: intstr.FromString("30%"), + ReplicaSlidingWindow: ptr.To(intstr.FromString("10%")), + }, + }, + }, + }, + }, + }, + { + name: "batch with targets - filter non-existent", + batch: &rolloutv1alpha1.RolloutRunBatchStrategy{ + Batches: []rolloutv1alpha1.RolloutRunStep{ + { + Targets: []rolloutv1alpha1.RolloutRunStepTarget{ + { + CrossClusterObjectNameReference: rolloutv1alpha1.CrossClusterObjectNameReference{ + Cluster: "cluster-a", + Name: "test-1", + }, + Replicas: intstr.FromString("20%"), + }, + { + CrossClusterObjectNameReference: rolloutv1alpha1.CrossClusterObjectNameReference{ + Cluster: "cluster-b", // Doesn't exist + Name: "test-1", + }, + Replicas: intstr.FromString("30%"), + }, + }, + }, + }, + }, + workloadMap: map[string]*workload.Info{ + "cluster-a/test-1": newTestInfo("cluster-a", "test", "test-1"), + // cluster-b/test-1 is missing + }, + want: &rolloutv1alpha1.RolloutRunBatchStrategy{ + Batches: []rolloutv1alpha1.RolloutRunStep{ + { + Targets: []rolloutv1alpha1.RolloutRunStepTarget{ + { + CrossClusterObjectNameReference: rolloutv1alpha1.CrossClusterObjectNameReference{ + Cluster: "cluster-a", + Name: "test-1", + }, + Replicas: intstr.FromString("20%"), + }, + }, + }, + }, + }, + }, + { + name: "batch with toleration preserved", + batch: &rolloutv1alpha1.RolloutRunBatchStrategy{ + Toleration: &rolloutv1alpha1.TolerationStrategy{ + WorkloadFailureThreshold: &intstr.IntOrString{Type: intstr.String, StrVal: "25%"}, + }, + Batches: []rolloutv1alpha1.RolloutRunStep{ + { + Targets: []rolloutv1alpha1.RolloutRunStepTarget{ + { + CrossClusterObjectNameReference: rolloutv1alpha1.CrossClusterObjectNameReference{ + Cluster: "cluster-a", + Name: "test-1", + }, + Replicas: intstr.FromString("50%"), + }, + }, + }, + }, + }, + workloadMap: map[string]*workload.Info{ + "cluster-a/test-1": newTestInfo("cluster-a", "test", "test-1"), + }, + want: &rolloutv1alpha1.RolloutRunBatchStrategy{ + Toleration: &rolloutv1alpha1.TolerationStrategy{ + WorkloadFailureThreshold: &intstr.IntOrString{Type: intstr.String, StrVal: "25%"}, + }, + Batches: []rolloutv1alpha1.RolloutRunStep{ + { + Targets: []rolloutv1alpha1.RolloutRunStepTarget{ + { + CrossClusterObjectNameReference: rolloutv1alpha1.CrossClusterObjectNameReference{ + Cluster: "cluster-a", + Name: "test-1", + }, + Replicas: intstr.FromString("50%"), + }, + }, + }, + }, + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := validateAndCopyBatchStrategy(tt.batch, tt.workloadMap) + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("validateAndCopyBatchStrategy() = %v, want %v", spew.Sdump(got), spew.Sdump(tt.want)) + } + }) + } +} + +func Test_validateAndCopyCanaryStrategy(t *testing.T) { + tests := []struct { + name string + canary *rolloutv1alpha1.RolloutRunCanaryStrategy + workloadMap map[string]*workload.Info + want *rolloutv1alpha1.RolloutRunCanaryStrategy + }{ + { + name: "nil canary", + canary: nil, + workloadMap: map[string]*workload.Info{}, + want: nil, + }, + { + name: "canary with all targets existing", + canary: &rolloutv1alpha1.RolloutRunCanaryStrategy{ + Targets: []rolloutv1alpha1.RolloutRunStepTarget{ + { + CrossClusterObjectNameReference: rolloutv1alpha1.CrossClusterObjectNameReference{ + Cluster: "cluster-a", + Name: "test-1", + }, + Replicas: intstr.FromString("10%"), + }, + }, + }, + workloadMap: map[string]*workload.Info{ + "cluster-a/test-1": newTestInfo("cluster-a", "test", "test-1"), + }, + want: &rolloutv1alpha1.RolloutRunCanaryStrategy{ + Targets: []rolloutv1alpha1.RolloutRunStepTarget{ + { + CrossClusterObjectNameReference: rolloutv1alpha1.CrossClusterObjectNameReference{ + Cluster: "cluster-a", + Name: "test-1", + }, + Replicas: intstr.FromString("10%"), + }, + }, + }, + }, + { + name: "canary with filtered targets", + canary: &rolloutv1alpha1.RolloutRunCanaryStrategy{ + Targets: []rolloutv1alpha1.RolloutRunStepTarget{ + { + CrossClusterObjectNameReference: rolloutv1alpha1.CrossClusterObjectNameReference{ + Cluster: "cluster-a", + Name: "test-1", + }, + Replicas: intstr.FromString("10%"), + }, + { + CrossClusterObjectNameReference: rolloutv1alpha1.CrossClusterObjectNameReference{ + Cluster: "cluster-b", // Doesn't exist + Name: "test-1", + }, + Replicas: intstr.FromString("20%"), + }, + }, + }, + workloadMap: map[string]*workload.Info{ + "cluster-a/test-1": newTestInfo("cluster-a", "test", "test-1"), + // cluster-b/test-1 is missing + }, + want: &rolloutv1alpha1.RolloutRunCanaryStrategy{ + Targets: []rolloutv1alpha1.RolloutRunStepTarget{ + { + CrossClusterObjectNameReference: rolloutv1alpha1.CrossClusterObjectNameReference{ + Cluster: "cluster-a", + Name: "test-1", + }, + Replicas: intstr.FromString("10%"), + }, + }, + }, + }, + { + name: "canary with all non-existent targets", + canary: &rolloutv1alpha1.RolloutRunCanaryStrategy{ + Targets: []rolloutv1alpha1.RolloutRunStepTarget{ + { + CrossClusterObjectNameReference: rolloutv1alpha1.CrossClusterObjectNameReference{ + Cluster: "cluster-b", + Name: "test-1", + }, + Replicas: intstr.FromString("10%"), + }, + }, + }, + workloadMap: map[string]*workload.Info{ + "cluster-a/test-1": newTestInfo("cluster-a", "test", "test-1"), + // cluster-b/test-1 is missing + }, + want: &rolloutv1alpha1.RolloutRunCanaryStrategy{ + Targets: []rolloutv1alpha1.RolloutRunStepTarget{}, + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := validateAndCopyCanaryStrategy(tt.canary, tt.workloadMap) + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("validateAndCopyCanaryStrategy() = %v, want %v", spew.Sdump(got), spew.Sdump(tt.want)) + } + }) + } +} + +func Test_buildWorkloadMap(t *testing.T) { + workloads := []*workload.Info{ + newTestInfo("cluster-a", "test", "test-1"), + newTestInfo("cluster-b", "test", "test-2"), + } + + m := buildWorkloadMap(workloads) + + if len(m) != 2 { + t.Errorf("len(m) = %v, want 2", len(m)) + } + + if _, ok := m["cluster-a/test-1"]; !ok { + t.Errorf("m['cluster-a/test-1'] not found") + } + + if _, ok := m["cluster-b/test-2"]; !ok { + t.Errorf("m['cluster-b/test-2'] not found") + } + + if _, ok := m["cluster-a/test-2"]; ok { + t.Errorf("m['cluster-a/test-2'] should not exist") + } +} + +func Test_workloadKey(t *testing.T) { + tests := []struct { + cluster string + name string + want string + }{ + {"cluster-a", "test-1", "cluster-a/test-1"}, + {"cluster-b", "test-2", "cluster-b/test-2"}, + {"cluster-a", "", "cluster-a/"}, + } + + for _, tt := range tests { + t.Run(tt.want, func(t *testing.T) { + got := workloadKey(tt.cluster, tt.name) + if got != tt.want { + t.Errorf("workloadKey() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/pkg/controllers/rollout/rollout_controller.go b/pkg/controllers/rollout/rollout_controller.go index 02aa7ce..13a45c4 100644 --- a/pkg/controllers/rollout/rollout_controller.go +++ b/pkg/controllers/rollout/rollout_controller.go @@ -327,16 +327,22 @@ func (r *RolloutReconciler) handleProgressing(ctx context.Context, obj *rolloutv func (r *RolloutReconciler) getDependentResources(ctx context.Context, obj *rolloutv1alpha1.Rollout) (ros *rolloutv1alpha1.RolloutStrategy, ttopos []*rolloutv1alpha1.TrafficTopology, errs []error) { ctx = clusterinfo.WithCluster(ctx, clusterinfo.Fed) - var strategy rolloutv1alpha1.RolloutStrategy - err := r.Client.Get( - ctx, - client.ObjectKey{Namespace: obj.Namespace, Name: obj.Spec.StrategyRef}, - &strategy, - ) - if err != nil { - errs = append(errs, err) - } else { - ros = &strategy + + // Check if using inline strategy (BatchStrategy) + // If using inline strategy, we don't need to fetch RolloutStrategy + if obj.Spec.BatchStrategy == nil && len(obj.Spec.StrategyRef) > 0 { + // Only fetch RolloutStrategy if using StrategyRef (not inline strategy) + var strategy rolloutv1alpha1.RolloutStrategy + err := r.Client.Get( + ctx, + client.ObjectKey{Namespace: obj.Namespace, Name: obj.Spec.StrategyRef}, + &strategy, + ) + if err != nil { + errs = append(errs, err) + } else { + ros = &strategy + } } for _, tt := range obj.Spec.TrafficTopologyRefs { @@ -670,12 +676,21 @@ func (r *RolloutReconciler) applyOneTimeStrategy(ctx context.Context, obj *rollo return nil } - batch := rolloutv1alpha1.RolloutRunBatchStrategy{ - Batches: constructRolloutRunBatches(&strategy.Batch, workloads), - Toleration: strategy.Batch.Toleration, + var batch *rolloutv1alpha1.RolloutRunBatchStrategy + + // Check if using InlineBatch (for inline batch strategy scenario) + if strategy.InlineBatch != nil { + workloadMap := buildWorkloadMap(workloads) + batch = validateAndCopyBatchStrategy(strategy.InlineBatch, workloadMap) + } else { + // Use original Batch field (for StrategyRef scenario) + batch = &rolloutv1alpha1.RolloutRunBatchStrategy{ + Batches: constructRolloutRunBatches(&strategy.Batch, workloads), + Toleration: strategy.Batch.Toleration, + } } - if batch.Toleration == nil { + if batch.Toleration == nil && run.Spec.Batch != nil { batch.Toleration = run.Spec.Batch.Toleration } @@ -693,7 +708,7 @@ func (r *RolloutReconciler) applyOneTimeStrategy(ctx context.Context, obj *rollo // update strategy in annotation in.Annotations[ontimestrategy.AnnoOneTimeStrategy] = strategyStr // update batch in spec - in.Spec.Batch = &batch + in.Spec.Batch = batch return nil }) if err != nil { diff --git a/pkg/controllers/rollout/rollout_controller_test.go b/pkg/controllers/rollout/rollout_controller_test.go new file mode 100644 index 0000000..ea65e85 --- /dev/null +++ b/pkg/controllers/rollout/rollout_controller_test.go @@ -0,0 +1,439 @@ +// Copyright 2023 The KusionStack Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package rollout + +import ( + "context" + "time" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + "k8s.io/apimachinery/pkg/util/intstr" + rolloutapi "kusionstack.io/kube-api/rollout" + rolloutv1alpha1 "kusionstack.io/kube-api/rollout/v1alpha1" + "kusionstack.io/kube-api/rollout/v1alpha1/condition" + "kusionstack.io/kube-utils/multicluster/clusterinfo" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +var _ = Describe("Rollout Controller Integration Tests", func() { + const ( + timeout = time.Second * 30 + interval = time.Millisecond * 250 + ) + + Context("Rollout initialize", func() { + var ( + namespace = "test-ns-rollout-init" + rolloutKey = types.NamespacedName{ + Namespace: namespace, + Name: "test-rollout-init", + } + ) + + It("should create rollout with finalizer", func() { + Expect(createNamespace(namespace)).Should(Succeed()) + + // Create a basic rollout + rollout := newTestRollout(rolloutKey.Name, namespace) + Expect(c.Create(ctx, rollout)).Should(Succeed()) + + // Wait for finalizer to be added + Eventually(func() bool { + r := &rolloutv1alpha1.Rollout{} + if err := c.Get(ctx, rolloutKey, r); err != nil { + return false + } + return containsString(r.Finalizers, rolloutapi.FinalizerRolloutProtection) + }, timeout, interval).Should(BeTrue()) + }) + + It("initialize rollout with correct phase", func() { + // Wait for rollout to be initialized + Eventually(func() bool { + r := &rolloutv1alpha1.Rollout{} + if err := c.Get(ctx, rolloutKey, r); err != nil { + return false + } + return r.Status.Phase == rolloutv1alpha1.RolloutPhaseInitialized + }, timeout, interval).Should(BeTrue()) + }) + }) + + Context("Rollout with StrategyRef", func() { + var ( + namespace = "test-ns-rollout-strategy" + rolloutKey = types.NamespacedName{Namespace: namespace, Name: "test-rollout"} + strategyKey = types.NamespacedName{Namespace: namespace, Name: "test-strategy"} + ) + + It("should resolve strategy reference successfully", func() { + Expect(createNamespace(namespace)).Should(Succeed()) + + // Create rollout strategy + strategy := newTestRolloutStrategy(strategyKey.Name, namespace) + Expect(c.Create(clusterinfo.WithCluster(ctx, clusterinfo.Fed), strategy)).Should(Succeed()) + + rollout := newTestRollout(rolloutKey.Name, namespace) + rollout.Spec.StrategyRef = strategyKey.Name + Expect(c.Create(ctx, rollout)).Should(Succeed()) + + // Wait for Available condition to become True + Eventually(func() bool { + r := &rolloutv1alpha1.Rollout{} + if err := c.Get(ctx, rolloutKey, r); err != nil { + return false + } + return condition.IsAvailable(r.Status.Conditions) + }, timeout, interval).Should(BeTrue()) + }) + + It("should fail when strategy reference does not exist", func() { + rolloutKey = types.NamespacedName{ + Namespace: namespace, + Name: "test-rollout-no-strategy", + } + rollout := newTestRollout(rolloutKey.Name, namespace) + rollout.Spec.StrategyRef = "non-existent-strategy" + Expect(c.Create(ctx, rollout)).Should(Succeed()) + + // Wait for Available condition to become False + Eventually(func() bool { + r := &rolloutv1alpha1.Rollout{} + if err := c.Get(ctx, rolloutKey, r); err != nil { + return false + } + return !condition.IsAvailable(r.Status.Conditions) + }, timeout, interval).Should(BeTrue()) + }) + + It("should create rolloutRun using strategyRef", func() { + rolloutKey = types.NamespacedName{ + Namespace: namespace, + Name: "test-rollout-with-run", + } + + rollout := newTestRollout(rolloutKey.Name, namespace) + rollout.Spec.StrategyRef = strategyKey.Name + rollout.Annotations = map[string]string{ + rolloutapi.AnnoRolloutTrigger: "trigger-from-strategy-ref", + } + Expect(c.Create(ctx, rollout)).Should(Succeed()) + + // Wait for rolloutRun to be created + Eventually(func() bool { + runList := &rolloutv1alpha1.RolloutRunList{} + if err := c.List(clusterinfo.WithCluster(ctx, clusterinfo.Fed), runList, client.InNamespace(namespace)); err != nil { + return false + } + for _, run := range runList.Items { + owner := metav1.GetControllerOf(&run) + if owner != nil && owner.Name == rolloutKey.Name && run.Name == "trigger-from-strategy-ref" { + return true + } + } + return false + }, timeout, interval).Should(BeTrue()) + }) + }) + + Context("Rollout with Inline Strategy", func() { + var ( + namespace = "test-ns-inline" + rolloutKey = types.NamespacedName{Namespace: namespace, Name: "test-rollout"} + ) + + It("should create rollout with inline batch strategy", func() { + Expect(createNamespace(namespace)).Should(Succeed()) + + rollout := newTestRolloutWithInlineBatch(rolloutKey.Name, namespace) + Expect(c.Create(ctx, rollout)).Should(Succeed()) + + // Verify rollout is created and has finalizer + Eventually(func() bool { + r := &rolloutv1alpha1.Rollout{} + if err := c.Get(ctx, rolloutKey, r); err != nil { + return false + } + return containsString(r.Finalizers, rolloutapi.FinalizerRolloutProtection) + }, timeout, interval).Should(BeTrue()) + }) + + It("should create rollout with inline canary strategy", func() { + rolloutKey = types.NamespacedName{Namespace: namespace, Name: "test-rollout-canary"} + rollout := newTestRolloutWithInlineCanary(rolloutKey.Name, namespace) + Expect(c.Create(ctx, rollout)).Should(Succeed()) + + // Verify rollout is created + Eventually(func() bool { + r := &rolloutv1alpha1.Rollout{} + if err := c.Get(ctx, rolloutKey, r); err != nil { + return false + } + return r.Status.Phase == rolloutv1alpha1.RolloutPhaseInitialized + }, timeout, interval).Should(BeTrue()) + }) + + It("should create rolloutRun with inline batch strategy and trigger", func() { + rolloutKey = types.NamespacedName{Namespace: namespace, Name: "test-rollout-inline-batch-trigger"} + rollout := newTestRolloutWithInlineBatch(rolloutKey.Name, namespace) + rollout.Annotations = map[string]string{ + rolloutapi.AnnoRolloutTrigger: "inline-batch-trigger", + } + Expect(c.Create(ctx, rollout)).Should(Succeed()) + + // Wait for rolloutRun to be created + Eventually(func() bool { + runList := &rolloutv1alpha1.RolloutRunList{} + if err := c.List(clusterinfo.WithCluster(ctx, clusterinfo.Fed), runList, client.InNamespace(namespace)); err != nil { + return false + } + for _, run := range runList.Items { + owner := metav1.GetControllerOf(&run) + if owner != nil && owner.Name == rolloutKey.Name && run.Name == "inline-batch-trigger" { + return run.Spec.Batch != nil + } + } + return false + }, timeout, interval).Should(BeTrue()) + }) + + It("should create rolloutRun with inline canary strategy and trigger", func() { + rolloutKey = types.NamespacedName{Namespace: namespace, Name: "test-rollout-inline-canary-trigger"} + rollout := newTestRolloutWithInlineCanary(rolloutKey.Name, namespace) + rollout.Annotations = map[string]string{ + rolloutapi.AnnoRolloutTrigger: "inline-canary-trigger", + } + Expect(c.Create(ctx, rollout)).Should(Succeed()) + + // Wait for rolloutRun to be created + Eventually(func() bool { + runList := &rolloutv1alpha1.RolloutRunList{} + if err := c.List(clusterinfo.WithCluster(ctx, clusterinfo.Fed), runList, client.InNamespace(namespace)); err != nil { + return false + } + for _, run := range runList.Items { + owner := metav1.GetControllerOf(&run) + if owner != nil && owner.Name == rolloutKey.Name && run.Name == "inline-canary-trigger" { + return run.Spec.Canary != nil + } + } + return false + }, timeout, interval).Should(BeTrue()) + }) + }) + + Context("Trigger Policy", func() { + var ( + namespace = "test-ns-manual-policy" + rolloutKey = types.NamespacedName{Namespace: namespace, Name: "test-rollout-manual-policy"} + ) + + It("should not auto-trigger when trigger policy is manual", func() { + Expect(createNamespace(namespace)).Should(Succeed()) + + rollout := newTestRolloutWithInlineBatch(rolloutKey.Name, namespace) + rollout.Spec.TriggerPolicy = rolloutv1alpha1.ManualTriggerPolicy + Expect(c.Create(ctx, rollout)).Should(Succeed()) + + // Wait a bit to ensure no rolloutRun is created + Consistently(func() int { + runList := &rolloutv1alpha1.RolloutRunList{} + _ = c.List(clusterinfo.WithCluster(ctx, clusterinfo.Fed), runList, client.InNamespace(namespace)) + return len(runList.Items) + }, time.Second*3, interval).Should(Equal(0)) + }) + + It("should auto-trigger when trigger policy is auto (default)", func() { + // Use different rolloutKey for this test + rolloutKey = types.NamespacedName{Namespace: namespace, Name: "test-rollout-auto-policy"} + + // Create rollout without trigger annotation + rollout := newTestRollout(rolloutKey.Name, namespace) + Expect(c.Create(ctx, rollout)).Should(Succeed()) + + // Wait and verify rolloutRun is not created without trigger annotation + // The controller needs workloads to be in waiting-rollout state + Consistently(func() int { + runList := &rolloutv1alpha1.RolloutRunList{} + _ = c.List(clusterinfo.WithCluster(ctx, clusterinfo.Fed), runList, client.InNamespace(namespace)) + return len(runList.Items) + }, time.Second*3, interval).Should(Equal(0)) + }) + }) + + Context("Status Updates", func() { + var ( + namespace = "test-ns-status" + rolloutKey = types.NamespacedName{Namespace: namespace, Name: "test-rollout-obs-gen"} + ) + + It("should update observed generation", func() { + Expect(createNamespace(namespace)).Should(Succeed()) + + rollout := newTestRollout(rolloutKey.Name, namespace) + Expect(c.Create(ctx, rollout)).Should(Succeed()) + + // Wait for observed generation to be set + Eventually(func() int64 { + r := &rolloutv1alpha1.Rollout{} + if err := c.Get(ctx, rolloutKey, r); err != nil { + return 0 + } + return r.Status.ObservedGeneration + }, timeout, interval).Should(Equal(rollout.Generation)) + }) + + It("should record conditions properly", func() { + rolloutKey = types.NamespacedName{Namespace: namespace, Name: "test-rollout-conditions"} + + rollout := newTestRollout(rolloutKey.Name, namespace) + Expect(c.Create(ctx, rollout)).Should(Succeed()) + + // Wait for conditions to be recorded + Eventually(func() bool { + r := &rolloutv1alpha1.Rollout{} + if err := c.Get(ctx, rolloutKey, r); err != nil { + return false + } + return len(r.Status.Conditions) > 0 + }, timeout, interval).Should(BeTrue()) + }) + }) +}) + +// Helper functions + +func newTestRollout(name, namespace string) *rolloutv1alpha1.Rollout { + return &rolloutv1alpha1.Rollout{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Namespace: namespace, + Labels: map[string]string{}, + }, + Spec: rolloutv1alpha1.RolloutSpec{ + WorkloadRef: rolloutv1alpha1.WorkloadRef{ + APIVersion: "apps/v1", + Kind: "StatefulSet", + }, + }, + } +} + +func newTestRolloutWithInlineBatch(name, namespace string) *rolloutv1alpha1.Rollout { + rollout := newTestRollout(name, namespace) + rollout.Spec.BatchStrategy = &rolloutv1alpha1.RolloutRunBatchStrategy{ + Batches: []rolloutv1alpha1.RolloutRunStep{ + { + Breakpoint: true, + Targets: []rolloutv1alpha1.RolloutRunStepTarget{ + { + CrossClusterObjectNameReference: rolloutv1alpha1.CrossClusterObjectNameReference{ + Cluster: "", + Name: "test-workload", + }, + Replicas: intstr.FromString("25%"), + }, + }, + }, + { + Targets: []rolloutv1alpha1.RolloutRunStepTarget{ + { + CrossClusterObjectNameReference: rolloutv1alpha1.CrossClusterObjectNameReference{ + Cluster: "", + Name: "test-workload", + }, + Replicas: intstr.FromString("100%"), + }, + }, + }, + }, + } + return rollout +} + +func newTestRolloutWithInlineCanary(name, namespace string) *rolloutv1alpha1.Rollout { + rollout := newTestRollout(name, namespace) + rollout.Spec.BatchStrategy = &rolloutv1alpha1.RolloutRunBatchStrategy{ + Batches: []rolloutv1alpha1.RolloutRunStep{ + { + Targets: []rolloutv1alpha1.RolloutRunStepTarget{ + { + CrossClusterObjectNameReference: rolloutv1alpha1.CrossClusterObjectNameReference{ + Name: "test-workload", + }, + Replicas: intstr.FromString("100%"), + }, + }, + }, + }, + } + rollout.Spec.CanaryStrategy = &rolloutv1alpha1.RolloutRunCanaryStrategy{ + Targets: []rolloutv1alpha1.RolloutRunStepTarget{ + { + CrossClusterObjectNameReference: rolloutv1alpha1.CrossClusterObjectNameReference{ + Name: "test-workload", + }, + Replicas: intstr.FromString("10%"), + }, + }, + } + return rollout +} + +func newTestRolloutStrategy(name, namespace string) *rolloutv1alpha1.RolloutStrategy { + return &rolloutv1alpha1.RolloutStrategy{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Namespace: namespace, + }, + Batch: &rolloutv1alpha1.BatchStrategy{ + Batches: []rolloutv1alpha1.RolloutStep{ + { + Breakpoint: true, + Replicas: intstr.FromString("25%"), + }, + { + Replicas: intstr.FromString("100%"), + }, + }, + }, + } +} + +func containsString(slice []string, s string) bool { + for _, item := range slice { + if item == s { + return true + } + } + return false +} + +func createNamespace(namespace string) error { + ctx = context.Background() + + // Create test namespace + ns := &corev1.Namespace{ + ObjectMeta: metav1.ObjectMeta{ + Name: namespace, + }, + } + return c.Create(ctx, ns) +} diff --git a/pkg/controllers/rollout/suite_test.go b/pkg/controllers/rollout/suite_test.go new file mode 100644 index 0000000..867dae4 --- /dev/null +++ b/pkg/controllers/rollout/suite_test.go @@ -0,0 +1,78 @@ +package rollout + +import ( + "context" + "os" + "path/filepath" + "testing" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + + "k8s.io/client-go/kubernetes/scheme" + "k8s.io/klog/v2" + "k8s.io/klog/v2/klogr" + rolloutv1alpha1 "kusionstack.io/kube-api/rollout/v1alpha1" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/envtest" + logf "sigs.k8s.io/controller-runtime/pkg/log" + "sigs.k8s.io/controller-runtime/pkg/log/zap" + "sigs.k8s.io/controller-runtime/pkg/manager" + + "kusionstack.io/rollout/pkg/controllers/registry" +) + +var ( + env *envtest.Environment + mgr manager.Manager + + ctx context.Context + cancel context.CancelFunc + c client.Client +) + +var _ = BeforeSuite(func() { + By("bootstrapping test environment") + + ctx, cancel = context.WithCancel(context.TODO()) + logf.SetLogger(zap.New(zap.WriteTo(os.Stdout), zap.UseDevMode(true))) + + testScheme := scheme.Scheme + err := rolloutv1alpha1.AddToScheme(testScheme) + Expect(err).NotTo(HaveOccurred()) + + env = &envtest.Environment{ + CRDDirectoryPaths: []string{filepath.Join("..", "..", "..", "config", "crd", "bases")}, + } + + config, err := env.Start() + Expect(err).NotTo(HaveOccurred()) + Expect(config).NotTo(BeNil()) + + klog.InitFlags(nil) + defer klog.Flush() + ctrl.SetLogger(klogr.New()) + mgr, err = manager.New(config, manager.Options{ + MetricsBindAddress: "0", + Scheme: testScheme, + Logger: ctrl.Log, + }) + Expect(err).NotTo(HaveOccurred()) + + c = mgr.GetClient() + + // Use empty workload registry for testing + // Controller will handle workload lookup failures gracefully + registry.InitWorkloadRegistry(mgr) + Expect(NewReconciler(mgr, registry.Workloads).SetupWithManager(mgr)).NotTo(HaveOccurred()) + + go func() { + Expect(mgr.Start(ctx)).NotTo(HaveOccurred()) + }() +}) + +func TestRolloutReconciler(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "Testing Rollout Suite") +} diff --git a/pkg/controllers/rollout/utils.go b/pkg/controllers/rollout/utils.go index cc03646..687ccde 100644 --- a/pkg/controllers/rollout/utils.go +++ b/pkg/controllers/rollout/utils.go @@ -69,8 +69,16 @@ func filterWorkloadsByMatch(workloads []*workload.Info, match *rolloutv1alpha1.R } func constructRolloutRun(obj *rolloutv1alpha1.Rollout, strategy *rolloutv1alpha1.RolloutStrategy, workloadWrappers []*workload.Info, rolloutId string) *rolloutv1alpha1.RolloutRun { + var run *rolloutv1alpha1.RolloutRun + var hasInline bool + // Try inline strategy first + if run, hasInline = constructRolloutRunFromInlineStrategy(obj, workloadWrappers, rolloutId); hasInline { + return run + } + + // Fall back to strategy reference owner := metav1.NewControllerRef(obj, rolloutv1alpha1.SchemeGroupVersion.WithKind("Rollout")) - run := &rolloutv1alpha1.RolloutRun{ + run = &rolloutv1alpha1.RolloutRun{ ObjectMeta: metav1.ObjectMeta{ Namespace: obj.Namespace, Name: rolloutId, diff --git a/pkg/controllers/rollout/utils_test.go b/pkg/controllers/rollout/utils_test.go index 65f4e03..fe3321c 100644 --- a/pkg/controllers/rollout/utils_test.go +++ b/pkg/controllers/rollout/utils_test.go @@ -178,3 +178,279 @@ func Test_constructRolloutRunBatches(t *testing.T) { }) } } + +func Test_constructRolloutRun(t *testing.T) { + tests := []struct { + name string + obj *rolloutv1alpha1.Rollout + strategy *rolloutv1alpha1.RolloutStrategy + workloadWrappers []*workload.Info + rolloutId string + wantInline bool // true if should use inline strategy + }{ + { + name: "inline batch strategy takes precedence over StrategyRef", + obj: &rolloutv1alpha1.Rollout{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "test", + Name: "test-rollout", + }, + Spec: rolloutv1alpha1.RolloutSpec{ + WorkloadRef: rolloutv1alpha1.WorkloadRef{ + APIVersion: "apps/v1", + Kind: "Deployment", + }, + BatchStrategy: &rolloutv1alpha1.RolloutRunBatchStrategy{ + Batches: []rolloutv1alpha1.RolloutRunStep{ + { + Targets: []rolloutv1alpha1.RolloutRunStepTarget{ + { + CrossClusterObjectNameReference: rolloutv1alpha1.CrossClusterObjectNameReference{ + Cluster: "cluster-a", + Name: "test-1", + }, + Replicas: intstr.FromString("20%"), + }, + }, + }, + }, + }, + }, + }, + strategy: &rolloutv1alpha1.RolloutStrategy{ + Batch: &rolloutv1alpha1.BatchStrategy{ + Batches: []rolloutv1alpha1.RolloutStep{ + { + Replicas: intstr.FromString("50%"), + Match: &rolloutv1alpha1.ResourceMatch{ + Names: []rolloutv1alpha1.CrossClusterObjectNameReference{ + {Cluster: "cluster-a", Name: "test-1"}, + }, + }, + }, + }, + }, + }, + workloadWrappers: []*workload.Info{ + newTestInfo("cluster-a", "test", "test-1"), + }, + rolloutId: "test-rollout-1", + wantInline: true, + }, + { + name: "inline canary strategy takes precedence over StrategyRef", + obj: &rolloutv1alpha1.Rollout{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "test", + Name: "test-rollout", + }, + Spec: rolloutv1alpha1.RolloutSpec{ + WorkloadRef: rolloutv1alpha1.WorkloadRef{ + APIVersion: "apps/v1", + Kind: "Deployment", + }, + CanaryStrategy: &rolloutv1alpha1.RolloutRunCanaryStrategy{ + Targets: []rolloutv1alpha1.RolloutRunStepTarget{ + { + CrossClusterObjectNameReference: rolloutv1alpha1.CrossClusterObjectNameReference{ + Cluster: "cluster-a", + Name: "test-1", + }, + Replicas: intstr.FromString("10%"), + }, + }, + }, + }, + }, + strategy: &rolloutv1alpha1.RolloutStrategy{ + Canary: &rolloutv1alpha1.CanaryStrategy{ + Replicas: intstr.FromString("20%"), + Match: &rolloutv1alpha1.ResourceMatch{ + Names: []rolloutv1alpha1.CrossClusterObjectNameReference{ + {Cluster: "cluster-a", Name: "test-1"}, + }, + }, + }, + Batch: &rolloutv1alpha1.BatchStrategy{ + Batches: []rolloutv1alpha1.RolloutStep{ + { + Replicas: intstr.FromString("100%"), + Match: &rolloutv1alpha1.ResourceMatch{ + Names: []rolloutv1alpha1.CrossClusterObjectNameReference{ + {Cluster: "cluster-a", Name: "test-1"}, + }, + }, + }, + }, + }, + }, + workloadWrappers: []*workload.Info{ + newTestInfo("cluster-a", "test", "test-1"), + }, + rolloutId: "test-rollout-1", + wantInline: true, + }, + { + name: "fallback to StrategyRef when no inline strategy", + obj: &rolloutv1alpha1.Rollout{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "test", + Name: "test-rollout", + }, + Spec: rolloutv1alpha1.RolloutSpec{ + WorkloadRef: rolloutv1alpha1.WorkloadRef{ + APIVersion: "apps/v1", + Kind: "Deployment", + }, + }, + }, + strategy: &rolloutv1alpha1.RolloutStrategy{ + Batch: &rolloutv1alpha1.BatchStrategy{ + Batches: []rolloutv1alpha1.RolloutStep{ + { + Replicas: intstr.FromString("50%"), + Match: &rolloutv1alpha1.ResourceMatch{ + Names: []rolloutv1alpha1.CrossClusterObjectNameReference{ + {Cluster: "cluster-a", Name: "test-1"}, + }, + }, + }, + }, + }, + }, + workloadWrappers: []*workload.Info{ + newTestInfo("cluster-a", "test", "test-1"), + }, + rolloutId: "test-rollout-1", + wantInline: false, + }, + { + name: "inline batch with canary together", + obj: &rolloutv1alpha1.Rollout{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "test", + Name: "test-rollout", + }, + Spec: rolloutv1alpha1.RolloutSpec{ + WorkloadRef: rolloutv1alpha1.WorkloadRef{ + APIVersion: "apps/v1", + Kind: "Deployment", + }, + BatchStrategy: &rolloutv1alpha1.RolloutRunBatchStrategy{ + Batches: []rolloutv1alpha1.RolloutRunStep{ + { + Targets: []rolloutv1alpha1.RolloutRunStepTarget{ + { + CrossClusterObjectNameReference: rolloutv1alpha1.CrossClusterObjectNameReference{ + Cluster: "cluster-a", + Name: "test-1", + }, + Replicas: intstr.FromString("25%"), + }, + }, + }, + }, + }, + CanaryStrategy: &rolloutv1alpha1.RolloutRunCanaryStrategy{ + Targets: []rolloutv1alpha1.RolloutRunStepTarget{ + { + CrossClusterObjectNameReference: rolloutv1alpha1.CrossClusterObjectNameReference{ + Cluster: "cluster-a", + Name: "test-1", + }, + Replicas: intstr.FromString("5%"), + }, + }, + }, + }, + }, + strategy: &rolloutv1alpha1.RolloutStrategy{ + Batch: &rolloutv1alpha1.BatchStrategy{ + Batches: []rolloutv1alpha1.RolloutStep{ + { + Replicas: intstr.FromString("50%"), + Match: &rolloutv1alpha1.ResourceMatch{ + Names: []rolloutv1alpha1.CrossClusterObjectNameReference{ + {Cluster: "cluster-a", Name: "test-1"}, + }, + }, + }, + }, + }, + }, + workloadWrappers: []*workload.Info{ + newTestInfo("cluster-a", "test", "test-1"), + }, + rolloutId: "test-rollout-1", + wantInline: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + run := constructRolloutRun(tt.obj, tt.strategy, tt.workloadWrappers, tt.rolloutId) + + if run == nil { + t.Errorf("constructRolloutRun() returned nil") + return + } + + // Verify basic fields + if run.Name != tt.rolloutId { + t.Errorf("run.Name = %v, want %v", run.Name, tt.rolloutId) + } + if run.Namespace != tt.obj.Namespace { + t.Errorf("run.Namespace = %v, want %v", run.Namespace, tt.obj.Namespace) + } + + if tt.wantInline { + // Verify that inline strategy was used (BatchSpec should be set based on inline config) + if tt.obj.Spec.BatchStrategy != nil { + if run.Spec.Batch == nil { + t.Errorf("run.Spec.Batch is nil, expected inline batch strategy to be used") + return + } + // Verify batch content matches inline config + if len(run.Spec.Batch.Batches) != len(tt.obj.Spec.BatchStrategy.Batches) { + t.Errorf("run.Spec.Batch.Batches length = %d, want %d", + len(run.Spec.Batch.Batches), len(tt.obj.Spec.BatchStrategy.Batches)) + } + } + + if tt.obj.Spec.CanaryStrategy != nil { + if run.Spec.Canary == nil { + t.Errorf("run.Spec.Canary is nil, expected inline canary strategy to be used") + return + } + // Verify canary content matches inline config + if len(run.Spec.Canary.Targets) != len(tt.obj.Spec.CanaryStrategy.Targets) { + t.Errorf("run.Spec.Canary.Targets length = %d, want %d", + len(run.Spec.Canary.Targets), len(tt.obj.Spec.CanaryStrategy.Targets)) + } + } + } else { + // Verify that StrategyRef was used + if run.Spec.Batch == nil { + t.Errorf("run.Spec.Batch is nil, expected StrategyRef batch to be used") + return + } + // Verify batch content matches strategy config + if len(run.Spec.Batch.Batches) != len(tt.strategy.Batch.Batches) { + t.Errorf("run.Spec.Batch.Batches length = %d, want %d", + len(run.Spec.Batch.Batches), len(tt.strategy.Batch.Batches)) + } + } + + // Verify owner reference exists + if len(run.OwnerReferences) != 1 { + t.Errorf("len(run.OwnerReferences) = %d, want 1", len(run.OwnerReferences)) + } else { + owner := run.OwnerReferences[0] + if owner.Kind != "Rollout" || owner.Name != tt.obj.Name { + t.Errorf("ownerReference = {Kind:%s, Name:%s}, want {Kind:Rollout, Name:%s}", + owner.Kind, owner.Name, tt.obj.Name) + } + } + }) + } +} diff --git a/pkg/controllers/rolloutrun/CLAUDE.md b/pkg/controllers/rolloutrun/CLAUDE.md new file mode 100644 index 0000000..6b5c934 --- /dev/null +++ b/pkg/controllers/rolloutrun/CLAUDE.md @@ -0,0 +1,338 @@ +# RolloutRun Controller 目录逻辑说明 + +## 概述 + +RolloutRun Controller 负责执行单次渐进式发布过程(RolloutRun),是 Rollout 的一次具体运行实例。它通过 Executor 来编排 Canary(金丝雀)和 Batch(分批)两种发布策略的执行流程。 + +## 核心职责 + +1. **执行发布流程** - 管理 RolloutRun 生命周期状态转换 +2. **协调执行器** - 调用 Executor 执行具体发布逻辑 +3. **等待工作负载就绪** - 监控工作负载状态,确保发布安全 +4. **管理流量路由** - 协调 TrafficManager 处理流量切换 +5. **支持 Webhook 钩子** - 在关键节点调用外部 Webhook + +## 目录结构 + +``` +rolloutrun/ +├── rolloutrun_controller.go # 主控制器逻辑 +├── initializer.go # 控制器初始化 +└── executor/ # 执行器模块 + ├── default.go # 主执行器 + ├── canary.go # 金丝雀发布执行器 + ├── batch.go # 分批发布执行器 + ├── context.go # 执行上下文 + ├── step_lifecycle.go # 步骤生命周期 + ├── command.go # 命令处理 + └── webhook/ # Webhook 模块 + ├── manager.go # Webhook 管理器 + ├── worker.go # Webhook 工作线程 + └── do_hook.go # Webhook 执行器 +``` + +## 核心数据结构 + +### RolloutRunReconciler + +```go +type RolloutRunReconciler struct { + *mixin.ReconcilerMixin + workloadRegistry registry.WorkloadRegistry + rvExpectation expectations.ResourceVersionExpectationInterface + executor *executor.Executor +} +``` + +### Executor + +```go +type Executor struct { + logger logr.Logger + canary *canaryExecutor // 金丝雀执行器 + batch *batchExecutor // 分批执行器 +} +``` + +## Reconcile 流程 + +### SetupWithManager + +```go +func (r *RolloutRunReconciler) SetupWithManager(mgr ctrl.Manager) error +``` + +监听的资源: +- `RolloutRun` - 使用 `ResourceVersionChangedPredicate` 和 `RolloutClassMatchesPredicate` + +### Reconcile 步骤 + +```go +func (r *RolloutRunReconciler) Reconcile(ctx context.Context, req ctrl.Request) +``` + +1. **获取 RolloutRun 对象** +2. **检查期望满足** - 资源版本期望 +3. **管理 Finalizer** +4. **跳过已完成** - `IsCompleted()` 则直接返回 +5. **查找工作负载** (跨集群) - 普通负载 + 金丝雀负载 +6. **同步 RolloutRun** - 调用 Executor.Do() +7. **清理 Annotation** +8. **更新状态** + +## 生命周期状态机 + +``` +┌──────────────┐ +│ Initial │ +└──────────────┘ + ↓ +┌──────────────┐ +│ PreRollout │ ← PreRolloutHook +└──────────────┘ + ↓ +┌──────────────┐ +│ Progressing │ ← 执行 Canary + Batch +└──────────────┘ + ↓ +┌──────────────┐ +│ PostRollout │ ← PostRolloutHook +└──────────────┘ + ↓ +┌──────────────┐ +│ Succeeded │ ← 终态 +└──────────────┘ + +┌──────────────┐ +│ Pausing │ ──→ Paused ← 暂停/继续命令 +└──────────────┘ + +┌──────────────┐ +│ Canceling │ ──→ Canceled ← 终态 +└──────────────┘ +``` + +## Executor 执行流程 + +### 生命周期处理 + +```go +func (e *Executor) lifecycle(ctx *ExecutorContext) (done bool, result ctrl.Result, err error) +``` + +1. **命令优先检查** - 如果存在手动命令,先执行命令 +2. **删除检测** - 触发 Canceling 状态 +3. **状态转换** + +### Processing 处理 + +```go +func (e *Executor) doProcessing(ctx *ExecutorContext) (bool, ctrl.Result, error) +``` + +按顺序执行: +1. ** Canary 发布** (如果配置) +2. **Batch 分批发布** + +## Canary 发布状态机 + +``` +┌──────────────┐ +│ None │ +└──────────────┘ + ↓ +┌──────────────┐ +│ Pending │ +└──────────────┘ + ↓ +┌──────────────┐ +│PreCanaryHook │ ← 调用 PreCanaryStepHook Webhook +└──────────────┘ + ↓ +┌──────────────┐ +│ Running │ ──→ 流量分叉 ──→ 创建金丝雀资源 ──→ 添加金丝雀路由 +└──────────────┘ │ │ │ + ↓ ↓ ↓ + 等待就绪 等待就绪 等待就绪 + ↓ +┌──────────────┐ +│PostCanaryHook│ ← 调用 PostCanaryStepHook Webhook (完成后暂停) +└──────────────┘ + ↓ +┌──────────────┐ +│ResourceRecyc │ ← 删除金丝雀路由 ──→ 删除金丝雀资源 ──→ 重置路由 ──→ 删除分叉后端 +└──────────────┘ + ↓ +┌──────────────┐ +│ Succeeded │ +└──────────────┘ +``` + +### Canary 执行步骤 + +| 步骤 | 操作 | 说明 | +|------|------|------| +| `doInit()` | 初始化 | 添加金丝雀标记,初始化流量管理 | +| `doPreStepHook()` | 前置钩子 | 调用外部 Webhook | +| `doCanary()` | 金丝雀执行 | 1. Fork 流量后端
2. 初始化路由
3. 创建金丝雀资源
4. 添加金丝雀路由 | +| `doPostStepHook()` | 后置钩子 | 调用外部 Webhook (完成后自动暂停) | +| `release()` | 资源回收 | 删除金丝雀路由、资源、流量后端 | + +## Batch 发布状态机 + +``` +┌──────────────┐ +│ None │ +└──────────────┘ + ↓ +┌──────────────┐ +│ Pending │ +└──────────────┘ + ↓ +┌──────────────┐ +│PreBatchHook │ ← 调用 PreBatchStepHook Webhook +└──────────────┘ + ↓ +┌──────────────┐ +│ Running │ ──→ 更新 Partition ──→ 等待就绪 +└──────────────┘ + ↓ +┌──────────────┐ +│PostBatchHook │ ← 调用 PostBatchStepHook Webhook +└──────────────┘ + ↓ +┌──────────────┐ +│ResourceRecyc │ ← 清理进度标记 (最后一批) +└──────────────┘ + ↓ +┌──────────────┐ +│ Succeeded │ +└──────────────┘ +``` + +### Batch 执行步骤 + +| 步骤 | 操作 | 说明 | +|------|------|------| +| `doPausing()` | 暂停检查 | 初始化进度信息,检查 breakpoint | +| `doPreStepHook()` | 前置钩子 | 调用外部 Webhook | +| `doBatchUpgrading()` | 分批升级 | 更新 Partition,等待副本就绪 (支持滑动窗口) | +| `doPostStepHook()` | 后置钩子 | 调用外部 Webhook | +| `doRecycle()` | 资源回收 | 清理进度标记 (仅最后一批) | + +## 流量管理 + +Canary 发布涉及的流量操作: + +| 操作 | 说明 | +|------|------| +| `ForkBackends` | 分叉流量后端 | +| `InitializeRoute` | 初始化路由 | +| `AddCanaryRoute` | 添加金丝雀路由 | +| `DeleteCanaryRoute` | 删除金丝雀路由 | +| `ResetRoute` | 重置路由 | +| `DeleteForkedBackends` | 删除分叉的后端 | + +## 手动命令 + +| 命令 | 说明 | +|------|------| +| `pause` | 暂停发布 | +| `resume`/`continue` | 从暂停状态继续 | +| `retry` | 从错误状态重试 | +| `skip` | 跳过当前批次 (错误时) | +| `cancel` | 取消发布 | +| `forceSkipCurrentBatch` | 强制跳过当前批次 | + +## Webhook 系统 + +### 支持的钩子类型 + +| HookType | 触发时机 | +|----------|----------| +| `PreCanaryStepHook` | 金丝雀发布前 | +| `PostCanaryStepHook` | 金丝雀发布后 (完成后暂停) | +| `PreBatchStepHook` | 每个批次开始前 | +| `PostBatchStepHook` | 每个批次完成后 | + +### Webhook 协议 + +请求: `RolloutWebhookReview` +返回状态: `OK`/`Error`/`Processing` + +## Step 状态引擎 + +```go +type stepStateEngine struct { + lifecycle []stepLifecycle +} +``` + +每个步骤定义 `do()` 和 `cancel()` 函数: +- `do()` 返回 `(done bool, retry time.Duration, error)` +- `cancel()` 支持优雅取消 + +## Control 模块 + +### BatchReleaseControl + +| 方法 | 说明 | +|------|------| +| `Initialize()` | 预检查,添加进度标记 | +| `UpdatePartition()` | 更新工作负载 partition | +| `Finalize()` | 删除进度标记 | + +### CanaryReleaseControl + +| 方法 | 说明 | +|------|------| +| `Initialize()` | 预检查,添加进度标记 | +| `Finalize()` | 删除金丝雀资源,清理标记 | +| `CreateOrUpdate()` | 创建或更新金丝雀资源 | + +## 关键设计决策 + +1. **状态机模式** - 使用状态机管理复杂的状态转换 +2. **执行器分离** - Canary 和 Batch 独立执行器,支持组合 +3. **Webhook 扩展** - 提供标准化的 Webhook 集成点 +4. **滑动窗口** - Batch 支持渐进式副本调整 +5. **流量解耦** - 通过 TrafficManager 抽象流量操作 + +## Annotation 用途 + +| Annotation | 说明 | +|------------|------| +| `rollout.kusionstack.io/manual-command` | 手动命令传递 | + +## Finalizer 用途 + +``` +rollout.kusionstack.io/cleanup # RolloutRun 保护 +rollout.kusionstack.io/canary Protection # 金丝雀资源保护 +``` + +## ExecutorContext + +```go +type ExecutorContext struct { + context.Context + Client client.Client + Recorder record.EventRecorder + Accessor workload.Accessor + OwnerKind string + OwnerName string + RolloutRun *rolloutv1alpha1.RolloutRun + NewStatus *rolloutv1alpha1.RolloutRunStatus + Workloads *workload.Set + TrafficManager *trafficcontrol.Manager +} +``` + +执行上下文封装了执行所需的所有资源。 + +## 参考 + +- [渐进式交付 Rollout 设计文档](https://yuque.antfin.com/antcloud-paas/dp4wap/ae5myagvwh96cugn) +- Rollout Controller - 负责触发和管理 RolloutRun +- Traffic Control - 流量路由管理模块 +- Workload Registry - 工作负载适配层 \ No newline at end of file diff --git a/pkg/features/ontimestrategy/ontimestrategy.go b/pkg/features/ontimestrategy/ontimestrategy.go index 7babe3a..f607662 100644 --- a/pkg/features/ontimestrategy/ontimestrategy.go +++ b/pkg/features/ontimestrategy/ontimestrategy.go @@ -28,7 +28,16 @@ const ( ) type OneTimeStrategy struct { + // Batch is the original field for StrategyRef scenario. + // Used when referencing a RolloutStrategy CRD with match/replicas. + // Mutually exclusive with InlineBatch. Batch rolloutv1alpha1.BatchStrategy `json:"batch,omitempty"` + + // InlineBatch is for inline batch strategy scenario. + // Used when RolloutSpec uses BatchStrategy inline configuration. + // Mutually exclusive with Batch. + // Directly reuses RolloutRunBatchStrategy type. + InlineBatch *rolloutv1alpha1.RolloutRunBatchStrategy `json:"inlineBatch,omitempty"` } func (s *OneTimeStrategy) JSONData() []byte { @@ -36,8 +45,22 @@ func (s *OneTimeStrategy) JSONData() []byte { return data } +// ConvertFrom creates a OneTimeStrategy from RolloutStrategy (for StrategyRef scenario) func ConvertFrom(in *rolloutv1alpha1.RolloutStrategy) *OneTimeStrategy { + if in == nil || in.Batch == nil { + return &OneTimeStrategy{} + } return &OneTimeStrategy{ Batch: *in.Batch, } } + +// ConvertFromInline creates a OneTimeStrategy for inline batch strategy scenario +func ConvertFromInline(batchStrategy *rolloutv1alpha1.RolloutRunBatchStrategy) *OneTimeStrategy { + if batchStrategy == nil { + return &OneTimeStrategy{} + } + return &OneTimeStrategy{ + InlineBatch: batchStrategy, + } +} From b916cab48e9873ecef82e1524e383c7a8fa63f1e Mon Sep 17 00:00:00 2001 From: youngLiuHY Date: Wed, 18 Mar 2026 17:14:13 +0800 Subject: [PATCH 03/10] fix: suite test add AfterSuite --- pkg/controllers/rollout/suite_test.go | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/pkg/controllers/rollout/suite_test.go b/pkg/controllers/rollout/suite_test.go index 867dae4..53608f0 100644 --- a/pkg/controllers/rollout/suite_test.go +++ b/pkg/controllers/rollout/suite_test.go @@ -5,6 +5,7 @@ import ( "os" "path/filepath" "testing" + "time" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" @@ -43,7 +44,8 @@ var _ = BeforeSuite(func() { Expect(err).NotTo(HaveOccurred()) env = &envtest.Environment{ - CRDDirectoryPaths: []string{filepath.Join("..", "..", "..", "config", "crd", "bases")}, + CRDDirectoryPaths: []string{filepath.Join("..", "..", "..", "config", "crd", "bases")}, + ControlPlaneStopTimeout: 60, // 60 seconds timeout for apiserver and etcd to stop } config, err := env.Start() @@ -72,6 +74,15 @@ var _ = BeforeSuite(func() { }() }) +var _ = AfterSuite(func() { + By("tearing down the test environment") + + cancel() + // Give manager time to stop gracefully before stopping envtest + time.Sleep(3 * time.Second) + _ = env.Stop() +}) + func TestRolloutReconciler(t *testing.T) { RegisterFailHandler(Fail) RunSpecs(t, "Testing Rollout Suite") From 2ad82acd06caa35da414e0290ab6822a7c1bf3e4 Mon Sep 17 00:00:00 2001 From: youngLiuHY Date: Wed, 18 Mar 2026 17:39:42 +0800 Subject: [PATCH 04/10] fix: test --- apis/rollout/v1alpha1/validation/rollout.go | 8 ++++++++ .../rollout/rollout_controller_test.go | 3 --- pkg/controllers/rollout/utils_test.go | 15 +++++++++++++++ 3 files changed, 23 insertions(+), 3 deletions(-) diff --git a/apis/rollout/v1alpha1/validation/rollout.go b/apis/rollout/v1alpha1/validation/rollout.go index 8c3b232..09efb19 100644 --- a/apis/rollout/v1alpha1/validation/rollout.go +++ b/apis/rollout/v1alpha1/validation/rollout.go @@ -56,6 +56,14 @@ func ValidateRolloutSpec(spec *rolloutv1alpha1.RolloutSpec, fldPath *field.Path, )) } + if hasCanary && !hasBatch { + allErrs = append(allErrs, field.Invalid( + fldPath, + spec.StrategyRef, + "batchStrategy is required when canaryStrategy is set", + )) + } + // Must specify at least one strategy if !hasStrategyRef && !hasBatch { allErrs = append(allErrs, field.Required( diff --git a/pkg/controllers/rollout/rollout_controller_test.go b/pkg/controllers/rollout/rollout_controller_test.go index ea65e85..924505f 100644 --- a/pkg/controllers/rollout/rollout_controller_test.go +++ b/pkg/controllers/rollout/rollout_controller_test.go @@ -15,7 +15,6 @@ package rollout import ( - "context" "time" . "github.com/onsi/ginkgo" @@ -427,8 +426,6 @@ func containsString(slice []string, s string) bool { } func createNamespace(namespace string) error { - ctx = context.Background() - // Create test namespace ns := &corev1.Namespace{ ObjectMeta: metav1.ObjectMeta{ diff --git a/pkg/controllers/rollout/utils_test.go b/pkg/controllers/rollout/utils_test.go index fe3321c..51615ad 100644 --- a/pkg/controllers/rollout/utils_test.go +++ b/pkg/controllers/rollout/utils_test.go @@ -260,6 +260,21 @@ func Test_constructRolloutRun(t *testing.T) { }, }, }, + BatchStrategy: &rolloutv1alpha1.RolloutRunBatchStrategy{ + Batches: []rolloutv1alpha1.RolloutRunStep{ + { + Targets: []rolloutv1alpha1.RolloutRunStepTarget{ + { + CrossClusterObjectNameReference: rolloutv1alpha1.CrossClusterObjectNameReference{ + Cluster: "cluster-a", + Name: "test-1", + }, + Replicas: intstr.FromString("100%"), + }, + }, + }, + }, + }, }, }, strategy: &rolloutv1alpha1.RolloutStrategy{ From 0e8b6de972c18e796ef37649a00987351d73ecfc Mon Sep 17 00:00:00 2001 From: youngLiuHY Date: Mon, 23 Mar 2026 17:52:12 +0800 Subject: [PATCH 05/10] fix: rollout test --- .../rollout/rollout_controller_test.go | 1226 ++++++++++++----- pkg/controllers/rollout/suite_test.go | 90 +- 2 files changed, 913 insertions(+), 403 deletions(-) diff --git a/pkg/controllers/rollout/rollout_controller_test.go b/pkg/controllers/rollout/rollout_controller_test.go index 924505f..7c13762 100644 --- a/pkg/controllers/rollout/rollout_controller_test.go +++ b/pkg/controllers/rollout/rollout_controller_test.go @@ -15,348 +15,542 @@ package rollout import ( + "context" + "encoding/json" + "flag" + "os" + "path/filepath" "time" - . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" - + "github.com/stretchr/testify/suite" + appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/util/intstr" + "k8s.io/client-go/kubernetes/scheme" + "k8s.io/client-go/rest" + "k8s.io/klog/v2" + "k8s.io/klog/v2/klogr" + "k8s.io/utils/ptr" rolloutapi "kusionstack.io/kube-api/rollout" rolloutv1alpha1 "kusionstack.io/kube-api/rollout/v1alpha1" "kusionstack.io/kube-api/rollout/v1alpha1/condition" + "kusionstack.io/kube-utils/multicluster" "kusionstack.io/kube-utils/multicluster/clusterinfo" + "kusionstack.io/kube-utils/multicluster/clusterprovider" "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/envtest" + logf "sigs.k8s.io/controller-runtime/pkg/log" + "sigs.k8s.io/controller-runtime/pkg/manager" + + "kusionstack.io/rollout/pkg/controllers/registry" + "kusionstack.io/rollout/pkg/features" + "kusionstack.io/rollout/pkg/features/ontimestrategy" ) -var _ = Describe("Rollout Controller Integration Tests", func() { - const ( - timeout = time.Second * 30 - interval = time.Millisecond * 250 +type rolloutTestSuite struct { + suite.Suite + + fedClient client.Client + cluster1Client client.Client + cluster2Client client.Client + + rollout *rolloutv1alpha1.Rollout + + // Environment cleanup + testClusterEnv *envtest.Environment + ctx context.Context + cancel context.CancelFunc +} + +func (s *rolloutTestSuite) setupCluster(env *envtest.Environment) (*rest.Config, client.Client) { + config, err := env.Start() + s.Require().NoError(err) + s.Require().NotNil(config) + + c, err := client.New(config, client.Options{Scheme: env.Scheme}) + s.Require().NoError(err) + s.Require().NotNil(c) + + return config, c +} + +func (s *rolloutTestSuite) SetupSuite() { + local := flag.NewFlagSet(os.Args[0], flag.ExitOnError) + klog.InitFlags(local) + local.Set("v", "3") + + // Enable OneTimeStrategy feature gate for tests + if err := features.DefaultMutableFeatureGate.Set("OneTimeStrategy=true"); err != nil { + panic(err) + } + + logf.SetLogger(klogr.New()) + + // Create cancellable context for cleanup + s.ctx, s.cancel = context.WithCancel(context.Background()) + + // fed + testscheme := scheme.Scheme + err := rolloutv1alpha1.AddToScheme(testscheme) + s.Require().NoError(err) + + s.testClusterEnv = &envtest.Environment{ + Scheme: testscheme, + CRDInstallOptions: envtest.CRDInstallOptions{ + Paths: []string{filepath.Join("..", "..", "..", "config", "crd", "bases")}, + }, + } + + var ( + fedConfig *rest.Config + cluster1Config *rest.Config + cluster2Config *rest.Config ) - Context("Rollout initialize", func() { - var ( - namespace = "test-ns-rollout-init" - rolloutKey = types.NamespacedName{ - Namespace: namespace, - Name: "test-rollout-init", - } - ) - - It("should create rollout with finalizer", func() { - Expect(createNamespace(namespace)).Should(Succeed()) - - // Create a basic rollout - rollout := newTestRollout(rolloutKey.Name, namespace) - Expect(c.Create(ctx, rollout)).Should(Succeed()) - - // Wait for finalizer to be added - Eventually(func() bool { - r := &rolloutv1alpha1.Rollout{} - if err := c.Get(ctx, rolloutKey, r); err != nil { - return false - } - return containsString(r.Finalizers, rolloutapi.FinalizerRolloutProtection) - }, timeout, interval).Should(BeTrue()) - }) - - It("initialize rollout with correct phase", func() { - // Wait for rollout to be initialized - Eventually(func() bool { - r := &rolloutv1alpha1.Rollout{} - if err := c.Get(ctx, rolloutKey, r); err != nil { - return false - } - return r.Status.Phase == rolloutv1alpha1.RolloutPhaseInitialized - }, timeout, interval).Should(BeTrue()) - }) - }) + fedConfig, s.fedClient = s.setupCluster(s.testClusterEnv) + cluster1Config, s.cluster1Client = s.setupCluster(s.testClusterEnv) + cluster2Config, s.cluster2Client = s.setupCluster(s.testClusterEnv) + + // manager + os.Setenv(clusterinfo.EnvClusterAllowList, "cluster1,cluster2") + + clusterMgr, newCacheFunc, newClientFunc, err := multicluster.NewManager(&multicluster.ManagerConfig{ + ClusterProvider: clusterprovider.NewSimpleClusterProvider(map[string]*rest.Config{ + "cluster1": cluster1Config, + "cluster2": cluster2Config, + "fed": fedConfig, + }), + FedConfig: fedConfig, + ClusterScheme: testscheme, + ResyncPeriod: 10 * time.Minute, + }, multicluster.Options{}) + + s.Require().NoError(err) + + go func() { + // start multi cluster client manager + err := clusterMgr.Run(s.ctx) + if err != nil { + panic(err) + } + }() - Context("Rollout with StrategyRef", func() { - var ( - namespace = "test-ns-rollout-strategy" - rolloutKey = types.NamespacedName{Namespace: namespace, Name: "test-rollout"} - strategyKey = types.NamespacedName{Namespace: namespace, Name: "test-strategy"} - ) - - It("should resolve strategy reference successfully", func() { - Expect(createNamespace(namespace)).Should(Succeed()) - - // Create rollout strategy - strategy := newTestRolloutStrategy(strategyKey.Name, namespace) - Expect(c.Create(clusterinfo.WithCluster(ctx, clusterinfo.Fed), strategy)).Should(Succeed()) - - rollout := newTestRollout(rolloutKey.Name, namespace) - rollout.Spec.StrategyRef = strategyKey.Name - Expect(c.Create(ctx, rollout)).Should(Succeed()) - - // Wait for Available condition to become True - Eventually(func() bool { - r := &rolloutv1alpha1.Rollout{} - if err := c.Get(ctx, rolloutKey, r); err != nil { - return false - } - return condition.IsAvailable(r.Status.Conditions) - }, timeout, interval).Should(BeTrue()) - }) - - It("should fail when strategy reference does not exist", func() { - rolloutKey = types.NamespacedName{ - Namespace: namespace, - Name: "test-rollout-no-strategy", - } - rollout := newTestRollout(rolloutKey.Name, namespace) - rollout.Spec.StrategyRef = "non-existent-strategy" - Expect(c.Create(ctx, rollout)).Should(Succeed()) - - // Wait for Available condition to become False - Eventually(func() bool { - r := &rolloutv1alpha1.Rollout{} - if err := c.Get(ctx, rolloutKey, r); err != nil { - return false - } - return !condition.IsAvailable(r.Status.Conditions) - }, timeout, interval).Should(BeTrue()) - }) - - It("should create rolloutRun using strategyRef", func() { - rolloutKey = types.NamespacedName{ - Namespace: namespace, - Name: "test-rollout-with-run", - } + // wait for cache synced + s.Require().True(clusterMgr.WaitForSynced(s.ctx)) - rollout := newTestRollout(rolloutKey.Name, namespace) - rollout.Spec.StrategyRef = strategyKey.Name - rollout.Annotations = map[string]string{ - rolloutapi.AnnoRolloutTrigger: "trigger-from-strategy-ref", - } - Expect(c.Create(ctx, rollout)).Should(Succeed()) - - // Wait for rolloutRun to be created - Eventually(func() bool { - runList := &rolloutv1alpha1.RolloutRunList{} - if err := c.List(clusterinfo.WithCluster(ctx, clusterinfo.Fed), runList, client.InNamespace(namespace)); err != nil { - return false - } - for _, run := range runList.Items { - owner := metav1.GetControllerOf(&run) - if owner != nil && owner.Name == rolloutKey.Name && run.Name == "trigger-from-strategy-ref" { - return true - } - } - return false - }, timeout, interval).Should(BeTrue()) - }) - }) + s.ctx = clusterinfo.WithCluster(s.ctx, clusterinfo.Fed) - Context("Rollout with Inline Strategy", func() { - var ( - namespace = "test-ns-inline" - rolloutKey = types.NamespacedName{Namespace: namespace, Name: "test-rollout"} - ) - - It("should create rollout with inline batch strategy", func() { - Expect(createNamespace(namespace)).Should(Succeed()) - - rollout := newTestRolloutWithInlineBatch(rolloutKey.Name, namespace) - Expect(c.Create(ctx, rollout)).Should(Succeed()) - - // Verify rollout is created and has finalizer - Eventually(func() bool { - r := &rolloutv1alpha1.Rollout{} - if err := c.Get(ctx, rolloutKey, r); err != nil { - return false - } - return containsString(r.Finalizers, rolloutapi.FinalizerRolloutProtection) - }, timeout, interval).Should(BeTrue()) - }) - - It("should create rollout with inline canary strategy", func() { - rolloutKey = types.NamespacedName{Namespace: namespace, Name: "test-rollout-canary"} - rollout := newTestRolloutWithInlineCanary(rolloutKey.Name, namespace) - Expect(c.Create(ctx, rollout)).Should(Succeed()) - - // Verify rollout is created - Eventually(func() bool { - r := &rolloutv1alpha1.Rollout{} - if err := c.Get(ctx, rolloutKey, r); err != nil { - return false - } - return r.Status.Phase == rolloutv1alpha1.RolloutPhaseInitialized - }, timeout, interval).Should(BeTrue()) - }) - - It("should create rolloutRun with inline batch strategy and trigger", func() { - rolloutKey = types.NamespacedName{Namespace: namespace, Name: "test-rollout-inline-batch-trigger"} - rollout := newTestRolloutWithInlineBatch(rolloutKey.Name, namespace) - rollout.Annotations = map[string]string{ - rolloutapi.AnnoRolloutTrigger: "inline-batch-trigger", - } - Expect(c.Create(ctx, rollout)).Should(Succeed()) - - // Wait for rolloutRun to be created - Eventually(func() bool { - runList := &rolloutv1alpha1.RolloutRunList{} - if err := c.List(clusterinfo.WithCluster(ctx, clusterinfo.Fed), runList, client.InNamespace(namespace)); err != nil { - return false - } - for _, run := range runList.Items { - owner := metav1.GetControllerOf(&run) - if owner != nil && owner.Name == rolloutKey.Name && run.Name == "inline-batch-trigger" { - return run.Spec.Batch != nil - } - } - return false - }, timeout, interval).Should(BeTrue()) - }) - - It("should create rolloutRun with inline canary strategy and trigger", func() { - rolloutKey = types.NamespacedName{Namespace: namespace, Name: "test-rollout-inline-canary-trigger"} - rollout := newTestRolloutWithInlineCanary(rolloutKey.Name, namespace) - rollout.Annotations = map[string]string{ - rolloutapi.AnnoRolloutTrigger: "inline-canary-trigger", - } - Expect(c.Create(ctx, rollout)).Should(Succeed()) - - // Wait for rolloutRun to be created - Eventually(func() bool { - runList := &rolloutv1alpha1.RolloutRunList{} - if err := c.List(clusterinfo.WithCluster(ctx, clusterinfo.Fed), runList, client.InNamespace(namespace)); err != nil { - return false - } - for _, run := range runList.Items { - owner := metav1.GetControllerOf(&run) - if owner != nil && owner.Name == rolloutKey.Name && run.Name == "inline-canary-trigger" { - return run.Spec.Canary != nil - } - } - return false - }, timeout, interval).Should(BeTrue()) - }) + mgr, err := manager.New(fedConfig, manager.Options{ + Scheme: testscheme, + NewClient: newClientFunc, + NewCache: newCacheFunc, + MetricsBindAddress: "0", + HealthProbeBindAddress: "0", }) - Context("Trigger Policy", func() { - var ( - namespace = "test-ns-manual-policy" - rolloutKey = types.NamespacedName{Namespace: namespace, Name: "test-rollout-manual-policy"} - ) - - It("should not auto-trigger when trigger policy is manual", func() { - Expect(createNamespace(namespace)).Should(Succeed()) - - rollout := newTestRolloutWithInlineBatch(rolloutKey.Name, namespace) - rollout.Spec.TriggerPolicy = rolloutv1alpha1.ManualTriggerPolicy - Expect(c.Create(ctx, rollout)).Should(Succeed()) - - // Wait a bit to ensure no rolloutRun is created - Consistently(func() int { - runList := &rolloutv1alpha1.RolloutRunList{} - _ = c.List(clusterinfo.WithCluster(ctx, clusterinfo.Fed), runList, client.InNamespace(namespace)) - return len(runList.Items) - }, time.Second*3, interval).Should(Equal(0)) - }) - - It("should auto-trigger when trigger policy is auto (default)", func() { - // Use different rolloutKey for this test - rolloutKey = types.NamespacedName{Namespace: namespace, Name: "test-rollout-auto-policy"} - - // Create rollout without trigger annotation - rollout := newTestRollout(rolloutKey.Name, namespace) - Expect(c.Create(ctx, rollout)).Should(Succeed()) - - // Wait and verify rolloutRun is not created without trigger annotation - // The controller needs workloads to be in waiting-rollout state - Consistently(func() int { - runList := &rolloutv1alpha1.RolloutRunList{} - _ = c.List(clusterinfo.WithCluster(ctx, clusterinfo.Fed), runList, client.InNamespace(namespace)) - return len(runList.Items) - }, time.Second*3, interval).Should(Equal(0)) - }) - }) + s.Require().NoError(err) - Context("Status Updates", func() { - var ( - namespace = "test-ns-status" - rolloutKey = types.NamespacedName{Namespace: namespace, Name: "test-rollout-obs-gen"} - ) - - It("should update observed generation", func() { - Expect(createNamespace(namespace)).Should(Succeed()) - - rollout := newTestRollout(rolloutKey.Name, namespace) - Expect(c.Create(ctx, rollout)).Should(Succeed()) - - // Wait for observed generation to be set - Eventually(func() int64 { - r := &rolloutv1alpha1.Rollout{} - if err := c.Get(ctx, rolloutKey, r); err != nil { - return 0 - } - return r.Status.ObservedGeneration - }, timeout, interval).Should(Equal(rollout.Generation)) - }) - - It("should record conditions properly", func() { - rolloutKey = types.NamespacedName{Namespace: namespace, Name: "test-rollout-conditions"} - - rollout := newTestRollout(rolloutKey.Name, namespace) - Expect(c.Create(ctx, rollout)).Should(Succeed()) - - // Wait for conditions to be recorded - Eventually(func() bool { - r := &rolloutv1alpha1.Rollout{} - if err := c.Get(ctx, rolloutKey, r); err != nil { - return false - } - return len(r.Status.Conditions) > 0 - }, timeout, interval).Should(BeTrue()) - }) - }) -}) + _, err = registry.InitWorkloadRegistry(mgr) + s.Require().NoError(err) -// Helper functions + _, err = InitFunc(mgr) + s.Require().NoError(err) -func newTestRollout(name, namespace string) *rolloutv1alpha1.Rollout { - return &rolloutv1alpha1.Rollout{ + go func() { + err := mgr.Start(s.ctx) + if err != nil { + panic(err) + } + }() +} + +func (s *rolloutTestSuite) TearDownSuite() { + // Cancel context to stop manager and cluster manager + if s.cancel != nil { + s.cancel() + } + // Stop envtest environment + if s.testClusterEnv != nil { + _ = s.testClusterEnv.Stop() + } +} + +func (s *rolloutTestSuite) SetupTest() { + namespace := "default" + s.rollout = newTestRollout("test-rollout", namespace) +} + +func (s *rolloutTestSuite) TearDownTest() { + err := s.fedClient.Delete(context.Background(), s.rollout) + s.Require().NoError(client.IgnoreNotFound(err)) +} + +func (s *rolloutTestSuite) rolloutShouldBeAvailable(obj *rolloutv1alpha1.Rollout) bool { + if obj.Generation != obj.Status.ObservedGeneration { + logf.Log.Info("generation not equal", "observedGeneration", obj.Status.ObservedGeneration, "generation", obj.Generation) + return false + } + if !condition.IsAvailable(obj.Status.Conditions) { + logf.Log.Info("Available condition should be true", "conditions", obj.Status.Conditions) + return false + } + return true +} + +func (s *rolloutTestSuite) rolloutShouldHaveFinalizer(obj *rolloutv1alpha1.Rollout) bool { + for _, f := range obj.Finalizers { + if f == rolloutapi.FinalizerRolloutProtection { + return true + } + } + return false +} + +type RolloutInitializationTestSuite struct { + rolloutTestSuite +} + +func (s *RolloutInitializationTestSuite) Test_CreateRollout() { + // create rollout + err := s.fedClient.Create(context.Background(), s.rollout) + s.Require().NoError(err) + + s.Require().Eventually(func() bool { + obj := &rolloutv1alpha1.Rollout{} + err := s.fedClient.Get(context.Background(), client.ObjectKeyFromObject(s.rollout), obj) + if err != nil { + return false + } + + // check finalizer + if !s.rolloutShouldHaveFinalizer(obj) { + logf.Log.Info("finalizer not found") + return false + } + + if obj.Generation != obj.Status.ObservedGeneration { + logf.Log.Info("generation not equal", "observedGeneration", obj.Status.ObservedGeneration, "generation", obj.Generation) + return false + } + + if obj.Status.Phase != rolloutv1alpha1.RolloutPhaseInitialized { + logf.Log.Info("phase should be Initialized", "phase", obj.Status.Phase) + return false + } + + return true + }, 30*time.Second, 2*time.Second) +} + +func (s *RolloutInitializationTestSuite) Test_CreateRolloutWithStrategyRef() { + // create rollout strategy + strategy := newTestRolloutStrategy("test-strategy", s.rollout.Namespace) + err := s.fedClient.Create(context.Background(), strategy) + s.Require().NoError(err) + + defer func() { + _ = s.fedClient.Delete(context.Background(), strategy) + }() + + // create rollout with strategy ref + s.rollout.Spec.StrategyRef = strategy.Name + s.rollout.Name = "test-rollout-with-strategy" + err = s.fedClient.Create(context.Background(), s.rollout) + s.Require().NoError(err) + + s.Require().Eventually(func() bool { + obj := &rolloutv1alpha1.Rollout{} + err := s.fedClient.Get(context.Background(), client.ObjectKeyFromObject(s.rollout), obj) + if err != nil { + return false + } + + return s.rolloutShouldBeAvailable(obj) + }, 30*time.Second, 2*time.Second) +} + +func (s *RolloutInitializationTestSuite) Test_CreateRolloutWithInlineBatchStrategy() { + // create rollout with inline batch strategy + s.rollout.Name = "test-rollout-inline-batch" + s.rollout.Spec.BatchStrategy = &rolloutv1alpha1.RolloutRunBatchStrategy{ + Batches: []rolloutv1alpha1.RolloutRunStep{ + { + Breakpoint: true, + Targets: []rolloutv1alpha1.RolloutRunStepTarget{ + { + CrossClusterObjectNameReference: rolloutv1alpha1.CrossClusterObjectNameReference{ + Cluster: "cluster1", + Name: "test-workload", + }, + Replicas: intstr.FromString("100%"), + }, + }, + }, + }, + } + err := s.fedClient.Create(context.Background(), s.rollout) + s.Require().NoError(err) + + s.Require().Eventually(func() bool { + obj := &rolloutv1alpha1.Rollout{} + err := s.fedClient.Get(context.Background(), client.ObjectKeyFromObject(s.rollout), obj) + if err != nil { + return false + } + + if !s.rolloutShouldHaveFinalizer(obj) { + return false + } + + return s.rolloutShouldBeAvailable(obj) + }, 30*time.Second, 2*time.Second) +} + +func (s *RolloutInitializationTestSuite) Test_CreateRolloutWithInlineCanaryStrategy() { + // create rollout with inline canary strategy + s.rollout.Name = "test-rollout-inline-canary" + s.rollout.Spec.BatchStrategy = &rolloutv1alpha1.RolloutRunBatchStrategy{ + Batches: []rolloutv1alpha1.RolloutRunStep{ + { + Breakpoint: true, + Targets: []rolloutv1alpha1.RolloutRunStepTarget{ + { + CrossClusterObjectNameReference: rolloutv1alpha1.CrossClusterObjectNameReference{ + Cluster: "cluster1", + Name: "test-workload", + }, + Replicas: intstr.FromString("100%"), + }, + }, + }, + }, + } + s.rollout.Spec.CanaryStrategy = &rolloutv1alpha1.RolloutRunCanaryStrategy{ + Targets: []rolloutv1alpha1.RolloutRunStepTarget{ + { + CrossClusterObjectNameReference: rolloutv1alpha1.CrossClusterObjectNameReference{ + Cluster: "cluster1", + Name: "test-workload", + }, + Replicas: intstr.FromString("10%"), + }, + }, + } + err := s.fedClient.Create(context.Background(), s.rollout) + s.Require().NoError(err) + + s.Require().Eventually(func() bool { + obj := &rolloutv1alpha1.Rollout{} + err := s.fedClient.Get(context.Background(), client.ObjectKeyFromObject(s.rollout), obj) + if err != nil { + return false + } + + if !s.rolloutShouldHaveFinalizer(obj) { + return false + } + + return s.rolloutShouldBeAvailable(obj) + }, 30*time.Second, 2*time.Second) +} + +type RolloutControllerTestSuite struct { + rolloutTestSuite +} + +func (s *RolloutControllerTestSuite) TearDownTest() { + // Override parent's TearDownTest to do nothing since each test manages its own cleanup +} + +func (s *RolloutControllerTestSuite) Test_StrategyRefNotFound() { + ctx := context.Background() + rollout := newTestRollout("test-rollout-no-strategy", "default") + rollout.Spec.StrategyRef = "non-existent-strategy" + + err := s.fedClient.Create(ctx, rollout) + s.Require().NoError(err) + + // Cleanup + defer func() { + _ = s.fedClient.Delete(ctx, rollout) + }() + + s.Require().Eventually(func() bool { + obj := &rolloutv1alpha1.Rollout{} + err := s.fedClient.Get(ctx, client.ObjectKeyFromObject(rollout), obj) + if err != nil { + return false + } + + // should not be available when strategy ref not found + if condition.IsAvailable(obj.Status.Conditions) { + logf.Log.Info("Available condition should be false when strategy ref not found") + return false + } + + return true + }, 20*time.Second, 2*time.Second) +} + +func (s *RolloutControllerTestSuite) Test_TriggerRolloutRunWithStrategyRef() { + ctx := context.Background() + namespace := "default" + stsName := "test-sts-strategyref" + + // 1. Create StatefulSet as workload + sts := newTestStatefulSet(stsName, namespace) + err := s.cluster1Client.Create(ctx, sts) + s.Require().NoError(err) + + // Cleanup + defer func() { + _ = s.cluster1Client.Delete(ctx, sts) + }() + + // 2. Create RolloutStrategy + strategy := &rolloutv1alpha1.RolloutStrategy{ ObjectMeta: metav1.ObjectMeta{ - Name: name, + Name: "test-strategy-for-run", Namespace: namespace, - Labels: map[string]string{}, }, - Spec: rolloutv1alpha1.RolloutSpec{ - WorkloadRef: rolloutv1alpha1.WorkloadRef{ - APIVersion: "apps/v1", - Kind: "StatefulSet", + Batch: &rolloutv1alpha1.BatchStrategy{ + Batches: []rolloutv1alpha1.RolloutStep{ + { + Breakpoint: true, + Replicas: intstr.FromString("25%"), + }, + { + Replicas: intstr.FromString("50%"), + }, + { + Replicas: intstr.FromString("100%"), + }, + }, + }, + } + err = s.fedClient.Create(ctx, strategy) + s.Require().NoError(err) + + // Cleanup + defer func() { + _ = s.fedClient.Delete(ctx, strategy) + }() + + // 3. Create Rollout with StrategyRef and trigger annotation + rollout := newTestRollout("test-rollout-strategyref-run", namespace) + rollout.Spec.StrategyRef = strategy.Name + rollout.Spec.WorkloadRef.Match = rolloutv1alpha1.ResourceMatch{ + Names: []rolloutv1alpha1.CrossClusterObjectNameReference{ + { + Cluster: "cluster1", + Name: stsName, }, }, } + rollout.Annotations = map[string]string{ + rolloutapi.AnnoRolloutTrigger: "trigger-strategyref-run", + } + err = s.fedClient.Create(ctx, rollout) + s.Require().NoError(err) + + // Cleanup + defer func() { + _ = s.fedClient.Delete(ctx, rollout) + }() + + // 4. Wait for Rollout to become Available first + s.Require().Eventually(func() bool { + obj := &rolloutv1alpha1.Rollout{} + err := s.fedClient.Get(ctx, client.ObjectKeyFromObject(rollout), obj) + if err != nil { + return false + } + return s.rolloutShouldBeAvailable(obj) + }, 30*time.Second, 2*time.Second) + + // 5. Wait for RolloutRun to be created and verify batch info + var run *rolloutv1alpha1.RolloutRun + s.Require().Eventually(func() bool { + runList := &rolloutv1alpha1.RolloutRunList{} + err := s.fedClient.List(ctx, runList, client.InNamespace(namespace)) + if err != nil { + return false + } + + for i := range runList.Items { + r := &runList.Items[i] + owner := metav1.GetControllerOf(r) + if owner != nil && owner.Name == rollout.Name && r.Name == "trigger-strategyref-run" { + run = r + return true + } + } + return false + }, 30*time.Second, 2*time.Second) + + defer func() { + _ = s.fedClient.Delete(ctx, run) + }() + + // 5. Verify RolloutRun spec + s.Require().NotNil(run.Spec.Batch, "Batch should not be nil") + s.Require().Len(run.Spec.Batch.Batches, 3, "Should have 3 batches") + s.Require().True(run.Spec.Batch.Batches[0].Breakpoint, "First batch should have breakpoint") + s.Require().False(run.Spec.Batch.Batches[1].Breakpoint, "Second batch should not have breakpoint") + s.Require().False(run.Spec.Batch.Batches[2].Breakpoint, "Third batch should not have breakpoint") + + // Verify targets are set correctly + s.Require().Len(run.Spec.Batch.Batches[0].Targets, 1, "First batch should have 1 target") + s.Require().Equal("cluster1", run.Spec.Batch.Batches[0].Targets[0].Cluster) + s.Require().Equal(stsName, run.Spec.Batch.Batches[0].Targets[0].Name) } -func newTestRolloutWithInlineBatch(name, namespace string) *rolloutv1alpha1.Rollout { - rollout := newTestRollout(name, namespace) +func (s *RolloutControllerTestSuite) Test_TriggerRolloutRunWithInlineBatchStrategy() { + ctx := context.Background() + namespace := "default" + stsName := "test-sts-inline-batch" + + // 1. Create StatefulSet as workload + sts := newTestStatefulSet(stsName, namespace) + err := s.cluster1Client.Create(ctx, sts) + s.Require().NoError(err) + + // Cleanup + defer func() { + _ = s.cluster1Client.Delete(ctx, sts) + }() + + // 2. Create Rollout with InlineBatchStrategy and trigger annotation + rollout := newTestRollout("test-rollout-inline-batch-run", namespace) + rollout.Spec.WorkloadRef.Match = rolloutv1alpha1.ResourceMatch{ + Names: []rolloutv1alpha1.CrossClusterObjectNameReference{ + { + Cluster: "cluster1", + Name: stsName, + }, + }, + } rollout.Spec.BatchStrategy = &rolloutv1alpha1.RolloutRunBatchStrategy{ Batches: []rolloutv1alpha1.RolloutRunStep{ { - Breakpoint: true, Targets: []rolloutv1alpha1.RolloutRunStepTarget{ { CrossClusterObjectNameReference: rolloutv1alpha1.CrossClusterObjectNameReference{ - Cluster: "", - Name: "test-workload", + Cluster: "cluster1", + Name: stsName, }, - Replicas: intstr.FromString("25%"), + Replicas: intstr.FromString("30%"), }, }, }, { + Breakpoint: true, Targets: []rolloutv1alpha1.RolloutRunStepTarget{ { CrossClusterObjectNameReference: rolloutv1alpha1.CrossClusterObjectNameReference{ - Cluster: "", - Name: "test-workload", + Cluster: "cluster1", + Name: stsName, }, Replicas: intstr.FromString("100%"), }, @@ -364,36 +558,401 @@ func newTestRolloutWithInlineBatch(name, namespace string) *rolloutv1alpha1.Roll }, }, } - return rollout + rollout.Annotations = map[string]string{ + rolloutapi.AnnoRolloutTrigger: "trigger-inline-batch-run", + } + err = s.fedClient.Create(ctx, rollout) + s.Require().NoError(err) + + // Cleanup + defer func() { + _ = s.fedClient.Delete(ctx, rollout) + }() + + // 3. Wait for Rollout to become Available first + s.Require().Eventually(func() bool { + obj := &rolloutv1alpha1.Rollout{} + err := s.fedClient.Get(ctx, client.ObjectKeyFromObject(rollout), obj) + if err != nil { + return false + } + return s.rolloutShouldBeAvailable(obj) + }, 30*time.Second, 2*time.Second) + + // 4. Wait for RolloutRun to be created and verify batch info + var run *rolloutv1alpha1.RolloutRun + s.Require().Eventually(func() bool { + runList := &rolloutv1alpha1.RolloutRunList{} + err := s.fedClient.List(ctx, runList, client.InNamespace(namespace)) + if err != nil { + return false + } + + for i := range runList.Items { + r := &runList.Items[i] + owner := metav1.GetControllerOf(r) + if owner != nil && owner.Name == rollout.Name && r.Name == "trigger-inline-batch-run" { + run = r + return true + } + } + return false + }, 30*time.Second, 2*time.Second) + + defer func() { + _ = s.fedClient.Delete(ctx, run) + }() + + // 5. Verify RolloutRun spec matches inline batch strategy + s.Require().NotNil(run.Spec.Batch, "Batch should not be nil") + s.Require().Len(run.Spec.Batch.Batches, 2, "Should have 2 batches") + + // Verify first batch + s.Require().Len(run.Spec.Batch.Batches[0].Targets, 1, "First batch should have 1 target") + s.Require().Equal("cluster1", run.Spec.Batch.Batches[0].Targets[0].Cluster) + s.Require().Equal(stsName, run.Spec.Batch.Batches[0].Targets[0].Name) + s.Require().Equal("30%", run.Spec.Batch.Batches[0].Targets[0].Replicas.String()) + + // Verify second batch + s.Require().True(run.Spec.Batch.Batches[1].Breakpoint, "Second batch should not have breakpoint") + s.Require().Len(run.Spec.Batch.Batches[1].Targets, 1, "Second batch should have 1 target") + s.Require().Equal("100%", run.Spec.Batch.Batches[1].Targets[0].Replicas.String()) } -func newTestRolloutWithInlineCanary(name, namespace string) *rolloutv1alpha1.Rollout { - rollout := newTestRollout(name, namespace) +func (s *RolloutControllerTestSuite) Test_ApplyOneTimeStrategyWithInlineBatch() { + ctx := context.Background() + namespace := "default" + stsName := "test-sts-onetime-inline" + + // 1. Create StatefulSet as workload + sts := newTestStatefulSet(stsName, namespace) + err := s.cluster1Client.Create(ctx, sts) + s.Require().NoError(err) + + // Cleanup + defer func() { + _ = s.cluster1Client.Delete(ctx, sts) + }() + + // 2. Create Rollout with InlineBatchStrategy and trigger annotation + rollout := newTestRollout("test-rollout-onetime-inline", namespace) + rollout.Spec.WorkloadRef.Match = rolloutv1alpha1.ResourceMatch{ + Names: []rolloutv1alpha1.CrossClusterObjectNameReference{ + { + Cluster: "cluster1", + Name: stsName, + }, + }, + } rollout.Spec.BatchStrategy = &rolloutv1alpha1.RolloutRunBatchStrategy{ Batches: []rolloutv1alpha1.RolloutRunStep{ { + Breakpoint: true, Targets: []rolloutv1alpha1.RolloutRunStepTarget{ { CrossClusterObjectNameReference: rolloutv1alpha1.CrossClusterObjectNameReference{ - Name: "test-workload", + Cluster: "cluster1", + Name: stsName, }, - Replicas: intstr.FromString("100%"), + Replicas: intstr.FromString("50%"), }, }, }, }, } - rollout.Spec.CanaryStrategy = &rolloutv1alpha1.RolloutRunCanaryStrategy{ - Targets: []rolloutv1alpha1.RolloutRunStepTarget{ + rollout.Annotations = map[string]string{ + rolloutapi.AnnoRolloutTrigger: "trigger-onetime-inline", + } + err = s.fedClient.Create(ctx, rollout) + s.Require().NoError(err) + + // Cleanup + defer func() { + _ = s.fedClient.Delete(ctx, rollout) + }() + + // 3. Wait for Rollout to become Available first + s.Require().Eventually(func() bool { + obj := &rolloutv1alpha1.Rollout{} + err := s.fedClient.Get(ctx, client.ObjectKeyFromObject(rollout), obj) + if err != nil { + return false + } + return s.rolloutShouldBeAvailable(obj) + }, 30*time.Second, 2*time.Second) + + // 4. Wait for RolloutRun to be created + var run *rolloutv1alpha1.RolloutRun + s.Require().Eventually(func() bool { + runList := &rolloutv1alpha1.RolloutRunList{} + err := s.fedClient.List(ctx, runList, client.InNamespace(namespace)) + if err != nil { + return false + } + + for i := range runList.Items { + r := &runList.Items[i] + owner := metav1.GetControllerOf(r) + if owner != nil && owner.Name == rollout.Name && r.Name == "trigger-onetime-inline" { + run = r + return true + } + } + return false + }, 30*time.Second, 2*time.Second) + + // 5. Verify initial batch + s.Require().NotNil(run.Spec.Batch, "Batch should not be nil") + s.Require().Len(run.Spec.Batch.Batches, 1, "Should have 1 batch initially") + s.Require().Equal("50%", run.Spec.Batch.Batches[0].Targets[0].Replicas.String()) + + // 6. Apply one-time strategy via annotation using InlineBatch + oneTimeStrategy := ontimestrategy.OneTimeStrategy{ + InlineBatch: &rolloutv1alpha1.RolloutRunBatchStrategy{ + Batches: []rolloutv1alpha1.RolloutRunStep{ + { + Targets: []rolloutv1alpha1.RolloutRunStepTarget{ + { + CrossClusterObjectNameReference: rolloutv1alpha1.CrossClusterObjectNameReference{ + Cluster: "cluster1", + Name: stsName, + }, + Replicas: intstr.FromString("20%"), + }, + }, + }, + { + Targets: []rolloutv1alpha1.RolloutRunStepTarget{ + { + CrossClusterObjectNameReference: rolloutv1alpha1.CrossClusterObjectNameReference{ + Cluster: "cluster1", + Name: stsName, + }, + Replicas: intstr.FromString("40%"), + }, + }, + }, + { + Targets: []rolloutv1alpha1.RolloutRunStepTarget{ + { + CrossClusterObjectNameReference: rolloutv1alpha1.CrossClusterObjectNameReference{ + Cluster: "cluster1", + Name: stsName, + }, + Replicas: intstr.FromString("60%"), + }, + }, + }, + }, + }, + } + oneTimeData, err := json.Marshal(oneTimeStrategy) + s.Require().NoError(err) + + // Update rollout with one-time strategy annotation + err = s.fedClient.Get(ctx, client.ObjectKeyFromObject(rollout), rollout) + s.Require().NoError(err) + if rollout.Annotations == nil { + rollout.Annotations = make(map[string]string) + } + rollout.Annotations[ontimestrategy.AnnoOneTimeStrategy] = string(oneTimeData) + err = s.fedClient.Update(ctx, rollout) + s.Require().NoError(err) + + // 7. Verify RolloutRun is updated with new batch strategy + s.Require().Eventually(func() bool { + err := s.fedClient.Get(ctx, client.ObjectKey{Name: run.Name, Namespace: namespace}, run) + if err != nil { + return false + } + return len(run.Spec.Batch.Batches) == 3 + }, 30*time.Second, 2*time.Second) + + defer func() { + _ = s.fedClient.Delete(ctx, run) + }() + + s.Require().Len(run.Spec.Batch.Batches, 3, "Should have 3 batches after one-time strategy applied") + s.Require().Equal("20%", run.Spec.Batch.Batches[0].Targets[0].Replicas.String()) + s.Require().Equal("40%", run.Spec.Batch.Batches[1].Targets[0].Replicas.String()) + s.Require().Equal("60%", run.Spec.Batch.Batches[2].Targets[0].Replicas.String()) + + // 8. Verify one-time strategy annotation is on RolloutRun + s.Require().Contains(run.Annotations, ontimestrategy.AnnoOneTimeStrategy, "RolloutRun should have one-time strategy annotation") +} + +func (s *RolloutControllerTestSuite) Test_ApplyOneTimeStrategyWithStrategyRef() { + ctx := context.Background() + namespace := "default" + stsName := "test-sts-onetime-strategyref" + + // 1. Create StatefulSet as workload + sts := newTestStatefulSet(stsName, namespace) + err := s.cluster1Client.Create(ctx, sts) + s.Require().NoError(err) + + // Cleanup + defer func() { + _ = s.cluster1Client.Delete(ctx, sts) + }() + + // 2. Create RolloutStrategy + strategy := &rolloutv1alpha1.RolloutStrategy{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-strategy-onetime", + Namespace: namespace, + }, + Batch: &rolloutv1alpha1.BatchStrategy{ + Batches: []rolloutv1alpha1.RolloutStep{ + { + Replicas: intstr.FromString("30%"), + }, + { + Breakpoint: true, + Replicas: intstr.FromString("60%"), + }, + { + Breakpoint: true, + Replicas: intstr.FromString("100%"), + }, + }, + }, + } + err = s.fedClient.Create(ctx, strategy) + s.Require().NoError(err) + + // Cleanup + defer func() { + _ = s.fedClient.Delete(ctx, strategy) + }() + + // 3. Create Rollout with StrategyRef and trigger annotation + rollout := newTestRollout("test-rollout-onetime-strategyref", namespace) + rollout.Spec.StrategyRef = strategy.Name + rollout.Spec.WorkloadRef.Match = rolloutv1alpha1.ResourceMatch{ + Names: []rolloutv1alpha1.CrossClusterObjectNameReference{ { - CrossClusterObjectNameReference: rolloutv1alpha1.CrossClusterObjectNameReference{ - Name: "test-workload", + Cluster: "cluster1", + Name: stsName, + }, + }, + } + rollout.Annotations = map[string]string{ + rolloutapi.AnnoRolloutTrigger: "trigger-onetime-strategyref", + } + err = s.fedClient.Create(ctx, rollout) + s.Require().NoError(err) + + // Cleanup + defer func() { + _ = s.fedClient.Delete(ctx, rollout) + }() + + // 4. Wait for Rollout to become Available first + s.Require().Eventually(func() bool { + obj := &rolloutv1alpha1.Rollout{} + err := s.fedClient.Get(ctx, client.ObjectKeyFromObject(rollout), obj) + if err != nil { + return false + } + return s.rolloutShouldBeAvailable(obj) + }, 30*time.Second, 2*time.Second) + + // 5. Wait for RolloutRun to be created + var run *rolloutv1alpha1.RolloutRun + s.Require().Eventually(func() bool { + runList := &rolloutv1alpha1.RolloutRunList{} + err := s.fedClient.List(ctx, runList, client.InNamespace(namespace)) + if err != nil { + return false + } + + for i := range runList.Items { + r := &runList.Items[i] + owner := metav1.GetControllerOf(r) + if owner != nil && owner.Name == rollout.Name && r.Name == "trigger-onetime-strategyref" { + run = r + return true + } + } + return false + }, 30*time.Second, 2*time.Second) + + // 6. Verify initial batch (from StrategyRef) + s.Require().NotNil(run.Spec.Batch, "Batch should not be nil") + s.Require().Len(run.Spec.Batch.Batches, 3, "Should have 3 batches from StrategyRef initially") + s.Require().True(run.Spec.Batch.Batches[1].Breakpoint, "Second batch should have breakpoint") + s.Require().True(run.Spec.Batch.Batches[2].Breakpoint, "Third batch should have breakpoint") + s.Require().Len(run.Spec.Batch.Batches[0].Targets, 1, "First batch should have 1 target") + s.Require().Equal("30%", run.Spec.Batch.Batches[0].Targets[0].Replicas.String()) + + // 7. Apply one-time strategy via annotation using InlineBatch + oneTimeStrategy := ontimestrategy.OneTimeStrategy{ + Batch: rolloutv1alpha1.BatchStrategy{ + Batches: []rolloutv1alpha1.RolloutStep{ + { + Replicas: intstr.FromString("30%"), + }, + { + Breakpoint: false, + Replicas: intstr.FromString("60%"), + }, + { + Breakpoint: false, + Replicas: intstr.FromString("100%"), }, - Replicas: intstr.FromString("10%"), }, }, } - return rollout + oneTimeData, err := json.Marshal(oneTimeStrategy) + s.Require().NoError(err) + + // Update rollout with one-time strategy annotation + err = s.fedClient.Get(ctx, client.ObjectKeyFromObject(rollout), rollout) + s.Require().NoError(err) + if rollout.Annotations == nil { + rollout.Annotations = make(map[string]string) + } + rollout.Annotations[ontimestrategy.AnnoOneTimeStrategy] = string(oneTimeData) + err = s.fedClient.Update(ctx, rollout) + s.Require().NoError(err) + + // 8. Verify RolloutRun is updated with new batch strategy + s.Require().Eventually(func() bool { + err := s.fedClient.Get(ctx, client.ObjectKey{Name: run.Name, Namespace: namespace}, run) + if err != nil { + return false + } + return len(run.Spec.Batch.Batches) == 3 + }, 30*time.Second, 2*time.Second) + + defer func() { + _ = s.fedClient.Delete(ctx, run) + }() + + s.Require().Len(run.Spec.Batch.Batches, 3, "Should have 3 batches after one-time strategy applied") + s.Require().False(run.Spec.Batch.Batches[1].Breakpoint, "Second batch should have no breakpoint") + s.Require().False(run.Spec.Batch.Batches[2].Breakpoint, "Third batch should have no breakpoint") + + // 9. Verify one-time strategy annotation is on RolloutRun + s.Require().Contains(run.Annotations, ontimestrategy.AnnoOneTimeStrategy, "RolloutRun should have one-time strategy annotation") +} + +// Helper functions + +func newTestRollout(name, namespace string) *rolloutv1alpha1.Rollout { + return &rolloutv1alpha1.Rollout{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Namespace: namespace, + }, + Spec: rolloutv1alpha1.RolloutSpec{ + WorkloadRef: rolloutv1alpha1.WorkloadRef{ + APIVersion: "apps/v1", + Kind: "StatefulSet", + }, + }, + } } func newTestRolloutStrategy(name, namespace string) *rolloutv1alpha1.RolloutStrategy { @@ -416,21 +975,42 @@ func newTestRolloutStrategy(name, namespace string) *rolloutv1alpha1.RolloutStra } } -func containsString(slice []string, s string) bool { - for _, item := range slice { - if item == s { - return true - } - } - return false -} - -func createNamespace(namespace string) error { - // Create test namespace - ns := &corev1.Namespace{ +func newTestStatefulSet(name, namespace string) *appsv1.StatefulSet { + return &appsv1.StatefulSet{ ObjectMeta: metav1.ObjectMeta{ - Name: namespace, + Name: name, + Namespace: namespace, + Labels: map[string]string{ + "app": name, + }, + }, + Spec: appsv1.StatefulSetSpec{ + Replicas: ptr.To[int32](3), + Selector: &metav1.LabelSelector{ + MatchLabels: map[string]string{ + "app": name, + }, + }, + Template: corev1.PodTemplateSpec{ + ObjectMeta: metav1.ObjectMeta{ + Labels: map[string]string{ + "app": name, + }, + }, + Spec: corev1.PodSpec{ + Containers: []corev1.Container{ + { + Name: "nginx", + Image: "nginx:1.14.2", + Ports: []corev1.ContainerPort{ + { + ContainerPort: 80, + }, + }, + }, + }, + }, + }, }, } - return c.Create(ctx, ns) } diff --git a/pkg/controllers/rollout/suite_test.go b/pkg/controllers/rollout/suite_test.go index 53608f0..bb1fdf3 100644 --- a/pkg/controllers/rollout/suite_test.go +++ b/pkg/controllers/rollout/suite_test.go @@ -1,89 +1,19 @@ package rollout import ( - "context" - "os" - "path/filepath" "testing" - "time" - . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" - - "k8s.io/client-go/kubernetes/scheme" - "k8s.io/klog/v2" - "k8s.io/klog/v2/klogr" - rolloutv1alpha1 "kusionstack.io/kube-api/rollout/v1alpha1" - ctrl "sigs.k8s.io/controller-runtime" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/envtest" - logf "sigs.k8s.io/controller-runtime/pkg/log" - "sigs.k8s.io/controller-runtime/pkg/log/zap" - "sigs.k8s.io/controller-runtime/pkg/manager" - - "kusionstack.io/rollout/pkg/controllers/registry" -) - -var ( - env *envtest.Environment - mgr manager.Manager - - ctx context.Context - cancel context.CancelFunc - c client.Client + "github.com/stretchr/testify/suite" ) -var _ = BeforeSuite(func() { - By("bootstrapping test environment") - - ctx, cancel = context.WithCancel(context.TODO()) - logf.SetLogger(zap.New(zap.WriteTo(os.Stdout), zap.UseDevMode(true))) - - testScheme := scheme.Scheme - err := rolloutv1alpha1.AddToScheme(testScheme) - Expect(err).NotTo(HaveOccurred()) - - env = &envtest.Environment{ - CRDDirectoryPaths: []string{filepath.Join("..", "..", "..", "config", "crd", "bases")}, - ControlPlaneStopTimeout: 60, // 60 seconds timeout for apiserver and etcd to stop - } - - config, err := env.Start() - Expect(err).NotTo(HaveOccurred()) - Expect(config).NotTo(BeNil()) - - klog.InitFlags(nil) - defer klog.Flush() - ctrl.SetLogger(klogr.New()) - mgr, err = manager.New(config, manager.Options{ - MetricsBindAddress: "0", - Scheme: testScheme, - Logger: ctrl.Log, - }) - Expect(err).NotTo(HaveOccurred()) - - c = mgr.GetClient() - - // Use empty workload registry for testing - // Controller will handle workload lookup failures gracefully - registry.InitWorkloadRegistry(mgr) - Expect(NewReconciler(mgr, registry.Workloads).SetupWithManager(mgr)).NotTo(HaveOccurred()) - - go func() { - Expect(mgr.Start(ctx)).NotTo(HaveOccurred()) - }() -}) - -var _ = AfterSuite(func() { - By("tearing down the test environment") - - cancel() - // Give manager time to stop gracefully before stopping envtest - time.Sleep(3 * time.Second) - _ = env.Stop() -}) +// In order for 'go test' to run this suite, we need to create +// a normal test function and pass our suite to suite.Run +func TestRolloutInitializationTestSuite(t *testing.T) { + suite.Run(t, new(RolloutInitializationTestSuite)) +} -func TestRolloutReconciler(t *testing.T) { - RegisterFailHandler(Fail) - RunSpecs(t, "Testing Rollout Suite") +// In order for 'go test' to run this suite, we need to create +// a normal test function and pass our suite to suite.Run +func TestRolloutControllerTestSuite(t *testing.T) { + suite.Run(t, new(RolloutControllerTestSuite)) } From e83d2f90678f317b64255b3f999d9b52e0b5d3c2 Mon Sep 17 00:00:00 2001 From: youngLiuHY Date: Mon, 13 Apr 2026 16:14:31 +0800 Subject: [PATCH 06/10] fix: return error when inline strategy workload not found --- pkg/controllers/rollout/inline_strategy.go | 48 ++++---- .../rollout/inline_strategy_test.go | 106 +++++++++++------- pkg/controllers/rollout/rollout_controller.go | 14 ++- pkg/controllers/rollout/utils.go | 12 +- pkg/controllers/rollout/utils_test.go | 6 +- 5 files changed, 119 insertions(+), 67 deletions(-) diff --git a/pkg/controllers/rollout/inline_strategy.go b/pkg/controllers/rollout/inline_strategy.go index 26fcab8..f4a60c0 100644 --- a/pkg/controllers/rollout/inline_strategy.go +++ b/pkg/controllers/rollout/inline_strategy.go @@ -15,6 +15,8 @@ package rollout import ( + "fmt" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" rolloutapi "kusionstack.io/kube-api/rollout" rolloutv1alpha1 "kusionstack.io/kube-api/rollout/v1alpha1" @@ -25,14 +27,14 @@ import ( ) // constructRolloutRunFromInlineStrategy constructs RolloutRun from inline strategy -// Returns the constructed RolloutRun and a boolean indicating if inline strategy was used +// Returns the constructed RolloutRun, a boolean indicating if inline strategy was used, and an error if validation fails func constructRolloutRunFromInlineStrategy( obj *rolloutv1alpha1.Rollout, workloadWrappers []*workload.Info, rolloutId string, -) (*rolloutv1alpha1.RolloutRun, bool) { +) (*rolloutv1alpha1.RolloutRun, bool, error) { if obj.Spec.BatchStrategy == nil { - return nil, false + return nil, false, nil } // Build workload map for validation @@ -59,11 +61,17 @@ func constructRolloutRunFromInlineStrategy( } if obj.Spec.CanaryStrategy != nil { - canary := validateAndCopyCanaryStrategy(obj.Spec.CanaryStrategy, workloadMap) + canary, err := validateAndCopyCanaryStrategy(obj.Spec.CanaryStrategy, workloadMap) + if err != nil { + return nil, true, err + } run.Spec.Canary = canary } - batch := validateAndCopyBatchStrategy(obj.Spec.BatchStrategy, workloadMap) + batch, err := validateAndCopyBatchStrategy(obj.Spec.BatchStrategy, workloadMap) + if err != nil { + return nil, true, err + } run.Spec.Batch = batch // Set OneTimeStrategy annotation for inline batch strategy @@ -80,26 +88,26 @@ func constructRolloutRunFromInlineStrategy( } } - return run, true + return run, true, nil } // validateAndCopyCanaryStrategy validates targets and creates a copy for RolloutRun // For inline strategy, targets are already pre-resolved by user +// Returns error if any target is not found in workloadMap func validateAndCopyCanaryStrategy( canary *rolloutv1alpha1.RolloutRunCanaryStrategy, workloadMap map[string]*workload.Info, -) *rolloutv1alpha1.RolloutRunCanaryStrategy { +) (*rolloutv1alpha1.RolloutRunCanaryStrategy, error) { if canary == nil { - return nil + return nil, nil } - // Validate targets exist + // Validate all targets exist validatedTargets := make([]rolloutv1alpha1.RolloutRunStepTarget, 0, len(canary.Targets)) for _, target := range canary.Targets { key := workloadKey(target.Cluster, target.Name) if _, exists := workloadMap[key]; !exists { - // Skip targets that don't exist in actual workloads - continue + return nil, fmt.Errorf("canary target cluster=%s name=%s not found in workloads", target.Cluster, target.Name) } // Direct copy - targets are already in correct format validatedTargets = append(validatedTargets, target) @@ -110,17 +118,18 @@ func validateAndCopyCanaryStrategy( Traffic: canary.Traffic, Properties: canary.Properties, TemplateMetadataPatch: canary.TemplateMetadataPatch, - } + }, nil } // validateAndCopyBatchStrategy validates and creates a copy for RolloutRun // For inline strategy, targets are already pre-resolved by user +// Returns error if any target is not found in workloadMap func validateAndCopyBatchStrategy( batch *rolloutv1alpha1.RolloutRunBatchStrategy, workloadMap map[string]*workload.Info, -) *rolloutv1alpha1.RolloutRunBatchStrategy { +) (*rolloutv1alpha1.RolloutRunBatchStrategy, error) { if batch == nil { - return nil + return nil, nil } if len(batch.Batches) == 0 { @@ -128,24 +137,23 @@ func validateAndCopyBatchStrategy( return &rolloutv1alpha1.RolloutRunBatchStrategy{ Toleration: batch.Toleration, Batches: []rolloutv1alpha1.RolloutRunStep{}, - } + }, nil } validatedBatches := make([]rolloutv1alpha1.RolloutRunStep, 0, len(batch.Batches)) - for _, step := range batch.Batches { + for batchIdx, step := range batch.Batches { if len(step.Targets) == 0 { // Skip steps without targets continue } - // Validate and filter targets that exist + // Validate all targets exist validatedTargets := make([]rolloutv1alpha1.RolloutRunStepTarget, 0, len(step.Targets)) for _, target := range step.Targets { key := workloadKey(target.Cluster, target.Name) if _, exists := workloadMap[key]; !exists { - // Skip targets that don't exist in actual workloads - continue + return nil, fmt.Errorf("batch[%d] target cluster=%s name=%s not found in workloads", batchIdx, target.Cluster, target.Name) } // Direct copy - targets are already in correct format validatedTargets = append(validatedTargets, target) @@ -165,7 +173,7 @@ func validateAndCopyBatchStrategy( return &rolloutv1alpha1.RolloutRunBatchStrategy{ Toleration: batch.Toleration, Batches: validatedBatches, - } + }, nil } // Helper functions diff --git a/pkg/controllers/rollout/inline_strategy_test.go b/pkg/controllers/rollout/inline_strategy_test.go index 0ca1aec..8d46673 100644 --- a/pkg/controllers/rollout/inline_strategy_test.go +++ b/pkg/controllers/rollout/inline_strategy_test.go @@ -16,6 +16,7 @@ package rollout import ( "reflect" + "strings" "testing" "github.com/davecgh/go-spew/spew" @@ -36,6 +37,8 @@ func Test_constructRolloutRunFromInlineStrategy(t *testing.T) { wantRun bool wantCanary bool wantBatch bool + wantErr bool + errContains string }{ { name: "no inline strategy - return nil, false", @@ -186,7 +189,7 @@ func Test_constructRolloutRunFromInlineStrategy(t *testing.T) { wantBatch: true, }, { - name: "filter non-existent workloads", + name: "non-existent workload should error", obj: &rolloutv1alpha1.Rollout{ ObjectMeta: metav1.ObjectMeta{ Namespace: "test", @@ -225,20 +228,34 @@ func Test_constructRolloutRunFromInlineStrategy(t *testing.T) { newTestInfo("cluster-a", "test", "test-1"), // cluster-b/test-1 is not in workloads }, - rolloutId: "test-rollout-1", - wantRun: true, - wantCanary: false, - wantBatch: true, + rolloutId: "test-rollout-1", + wantRun: true, + wantErr: true, + errContains: "batch[0] target cluster=cluster-b name=test-1 not found in workloads", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - run, gotInline := constructRolloutRunFromInlineStrategy(tt.obj, tt.workloadWrappers, tt.rolloutId) + run, gotInline, err := constructRolloutRunFromInlineStrategy(tt.obj, tt.workloadWrappers, tt.rolloutId) if gotInline != tt.wantRun { t.Errorf("constructRolloutRunFromInlineStrategy() gotInline = %v, want %v", gotInline, tt.wantRun) return } + if tt.wantErr { + if err == nil { + t.Errorf("constructRolloutRunFromInlineStrategy() expected error, got nil") + return + } + if tt.errContains != "" && !strings.Contains(err.Error(), tt.errContains) { + t.Errorf("constructRolloutRunFromInlineStrategy() error = %v, want containing %v", err, tt.errContains) + } + return + } + if err != nil { + t.Errorf("constructRolloutRunFromInlineStrategy() unexpected error: %v", err) + return + } if !tt.wantRun { if run != nil { @@ -292,6 +309,8 @@ func Test_validateAndCopyBatchStrategy(t *testing.T) { batch *rolloutv1alpha1.RolloutRunBatchStrategy workloadMap map[string]*workload.Info want *rolloutv1alpha1.RolloutRunBatchStrategy + wantErr bool + errContains string }{ { name: "nil batch", @@ -365,7 +384,7 @@ func Test_validateAndCopyBatchStrategy(t *testing.T) { }, }, { - name: "batch with targets - filter non-existent", + name: "batch with non-existent target - should error", batch: &rolloutv1alpha1.RolloutRunBatchStrategy{ Batches: []rolloutv1alpha1.RolloutRunStep{ { @@ -392,21 +411,8 @@ func Test_validateAndCopyBatchStrategy(t *testing.T) { "cluster-a/test-1": newTestInfo("cluster-a", "test", "test-1"), // cluster-b/test-1 is missing }, - want: &rolloutv1alpha1.RolloutRunBatchStrategy{ - Batches: []rolloutv1alpha1.RolloutRunStep{ - { - Targets: []rolloutv1alpha1.RolloutRunStepTarget{ - { - CrossClusterObjectNameReference: rolloutv1alpha1.CrossClusterObjectNameReference{ - Cluster: "cluster-a", - Name: "test-1", - }, - Replicas: intstr.FromString("20%"), - }, - }, - }, - }, - }, + wantErr: true, + errContains: "batch[0] target cluster=cluster-b name=test-1 not found in workloads", }, { name: "batch with toleration preserved", @@ -454,7 +460,21 @@ func Test_validateAndCopyBatchStrategy(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - got := validateAndCopyBatchStrategy(tt.batch, tt.workloadMap) + got, err := validateAndCopyBatchStrategy(tt.batch, tt.workloadMap) + if tt.wantErr { + if err == nil { + t.Errorf("validateAndCopyBatchStrategy() expected error, got nil") + return + } + if tt.errContains != "" && !strings.Contains(err.Error(), tt.errContains) { + t.Errorf("validateAndCopyBatchStrategy() error = %v, want containing %v", err, tt.errContains) + } + return + } + if err != nil { + t.Errorf("validateAndCopyBatchStrategy() unexpected error: %v", err) + return + } if !reflect.DeepEqual(got, tt.want) { t.Errorf("validateAndCopyBatchStrategy() = %v, want %v", spew.Sdump(got), spew.Sdump(tt.want)) } @@ -468,6 +488,8 @@ func Test_validateAndCopyCanaryStrategy(t *testing.T) { canary *rolloutv1alpha1.RolloutRunCanaryStrategy workloadMap map[string]*workload.Info want *rolloutv1alpha1.RolloutRunCanaryStrategy + wantErr bool + errContains string }{ { name: "nil canary", @@ -504,7 +526,7 @@ func Test_validateAndCopyCanaryStrategy(t *testing.T) { }, }, { - name: "canary with filtered targets", + name: "canary with non-existent target - should error", canary: &rolloutv1alpha1.RolloutRunCanaryStrategy{ Targets: []rolloutv1alpha1.RolloutRunStepTarget{ { @@ -527,20 +549,11 @@ func Test_validateAndCopyCanaryStrategy(t *testing.T) { "cluster-a/test-1": newTestInfo("cluster-a", "test", "test-1"), // cluster-b/test-1 is missing }, - want: &rolloutv1alpha1.RolloutRunCanaryStrategy{ - Targets: []rolloutv1alpha1.RolloutRunStepTarget{ - { - CrossClusterObjectNameReference: rolloutv1alpha1.CrossClusterObjectNameReference{ - Cluster: "cluster-a", - Name: "test-1", - }, - Replicas: intstr.FromString("10%"), - }, - }, - }, + wantErr: true, + errContains: "canary target cluster=cluster-b name=test-1 not found in workloads", }, { - name: "canary with all non-existent targets", + name: "canary with all non-existent targets - should error", canary: &rolloutv1alpha1.RolloutRunCanaryStrategy{ Targets: []rolloutv1alpha1.RolloutRunStepTarget{ { @@ -556,15 +569,28 @@ func Test_validateAndCopyCanaryStrategy(t *testing.T) { "cluster-a/test-1": newTestInfo("cluster-a", "test", "test-1"), // cluster-b/test-1 is missing }, - want: &rolloutv1alpha1.RolloutRunCanaryStrategy{ - Targets: []rolloutv1alpha1.RolloutRunStepTarget{}, - }, + wantErr: true, + errContains: "canary target cluster=cluster-b name=test-1 not found in workloads", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - got := validateAndCopyCanaryStrategy(tt.canary, tt.workloadMap) + got, err := validateAndCopyCanaryStrategy(tt.canary, tt.workloadMap) + if tt.wantErr { + if err == nil { + t.Errorf("validateAndCopyCanaryStrategy() expected error, got nil") + return + } + if tt.errContains != "" && !strings.Contains(err.Error(), tt.errContains) { + t.Errorf("validateAndCopyCanaryStrategy() error = %v, want containing %v", err, tt.errContains) + } + return + } + if err != nil { + t.Errorf("validateAndCopyCanaryStrategy() unexpected error: %v", err) + return + } if !reflect.DeepEqual(got, tt.want) { t.Errorf("validateAndCopyCanaryStrategy() = %v, want %v", spew.Sdump(got), spew.Sdump(tt.want)) } diff --git a/pkg/controllers/rollout/rollout_controller.go b/pkg/controllers/rollout/rollout_controller.go index 13a45c4..51c110e 100644 --- a/pkg/controllers/rollout/rollout_controller.go +++ b/pkg/controllers/rollout/rollout_controller.go @@ -439,7 +439,12 @@ func (r *RolloutReconciler) syncRun( } // 4. trigger a new rollout progress - curRun = constructRolloutRun(obj, ros, workloads, rolloutID) + var constructErr error + curRun, constructErr = constructRolloutRun(obj, ros, workloads, rolloutID) + if constructErr != nil { + r.recordCondition(obj, newStatus, rolloutv1alpha1.RolloutConditionTrigger, metav1.ConditionFalse, "FailedConstruct", fmt.Sprintf("failed to construct a new rolloutRun: %v", constructErr)) + return constructErr + } r.recordCondition(obj, newStatus, rolloutv1alpha1.RolloutConditionTrigger, metav1.ConditionTrue, "Create", fmt.Sprintf("construct a new rolloutRun %s", curRun.Name)) // NOTO: we have to set expectation before we create the rolloutRun to avoid @@ -681,7 +686,12 @@ func (r *RolloutReconciler) applyOneTimeStrategy(ctx context.Context, obj *rollo // Check if using InlineBatch (for inline batch strategy scenario) if strategy.InlineBatch != nil { workloadMap := buildWorkloadMap(workloads) - batch = validateAndCopyBatchStrategy(strategy.InlineBatch, workloadMap) + var validateErr error + batch, validateErr = validateAndCopyBatchStrategy(strategy.InlineBatch, workloadMap) + if validateErr != nil { + r.recordCondition(obj, newStatus, rolloutv1alpha1.RolloutConditionTrigger, metav1.ConditionFalse, "InvalidStrategy", fmt.Sprintf("failed to validate inline batch strategy: %v", validateErr)) + return nil + } } else { // Use original Batch field (for StrategyRef scenario) batch = &rolloutv1alpha1.RolloutRunBatchStrategy{ diff --git a/pkg/controllers/rollout/utils.go b/pkg/controllers/rollout/utils.go index 687ccde..ec25e6b 100644 --- a/pkg/controllers/rollout/utils.go +++ b/pkg/controllers/rollout/utils.go @@ -68,12 +68,16 @@ func filterWorkloadsByMatch(workloads []*workload.Info, match *rolloutv1alpha1.R return result } -func constructRolloutRun(obj *rolloutv1alpha1.Rollout, strategy *rolloutv1alpha1.RolloutStrategy, workloadWrappers []*workload.Info, rolloutId string) *rolloutv1alpha1.RolloutRun { +func constructRolloutRun(obj *rolloutv1alpha1.Rollout, strategy *rolloutv1alpha1.RolloutStrategy, workloadWrappers []*workload.Info, rolloutId string) (*rolloutv1alpha1.RolloutRun, error) { var run *rolloutv1alpha1.RolloutRun var hasInline bool // Try inline strategy first - if run, hasInline = constructRolloutRunFromInlineStrategy(obj, workloadWrappers, rolloutId); hasInline { - return run + run, hasInline, err := constructRolloutRunFromInlineStrategy(obj, workloadWrappers, rolloutId) + if hasInline { + if err != nil { + return nil, err + } + return run, nil } // Fall back to strategy reference @@ -114,7 +118,7 @@ func constructRolloutRun(obj *rolloutv1alpha1.Rollout, strategy *rolloutv1alpha1 run.Labels[rolloutapi.LabelRolloutClass] = class } } - return run + return run, nil } func constructRolloutRunCanary(strategy *rolloutv1alpha1.CanaryStrategy, workloadWrappers []*workload.Info) *rolloutv1alpha1.RolloutRunCanaryStrategy { diff --git a/pkg/controllers/rollout/utils_test.go b/pkg/controllers/rollout/utils_test.go index 51615ad..54ff0a9 100644 --- a/pkg/controllers/rollout/utils_test.go +++ b/pkg/controllers/rollout/utils_test.go @@ -403,7 +403,11 @@ func Test_constructRolloutRun(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - run := constructRolloutRun(tt.obj, tt.strategy, tt.workloadWrappers, tt.rolloutId) + run, err := constructRolloutRun(tt.obj, tt.strategy, tt.workloadWrappers, tt.rolloutId) + if err != nil { + t.Errorf("constructRolloutRun() unexpected error: %v", err) + return + } if run == nil { t.Errorf("constructRolloutRun() returned nil") From c25733bd3131d8dd7e1a0913d645f026cd93a77b Mon Sep 17 00:00:00 2001 From: youngLiuHY Date: Mon, 13 Apr 2026 16:57:36 +0800 Subject: [PATCH 07/10] fix: bump kube api version && support webhook --- go.mod | 2 +- go.sum | 4 ++-- pkg/controllers/rollout/inline_strategy.go | 2 +- pkg/controllers/rollout/rollout_controller.go | 2 +- pkg/controllers/rollout/rollout_controller_test.go | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index c4b22f3..d98a48c 100644 --- a/go.mod +++ b/go.mod @@ -23,7 +23,7 @@ require ( k8s.io/klog/v2 v2.130.1 k8s.io/kubernetes v1.22.2 k8s.io/utils v0.0.0-20241210054802-24370beab758 - kusionstack.io/kube-api v0.7.5-0.20260306081812-18b6128bc6fb + kusionstack.io/kube-api v0.7.5-0.20260413084915-e038d5ff4fea kusionstack.io/kube-utils v0.2.1-0.20251125083928-1134a582b341 kusionstack.io/resourceconsist v0.0.4 sigs.k8s.io/controller-runtime v0.21.0 diff --git a/go.sum b/go.sum index 210f4b5..bc4c1f3 100644 --- a/go.sum +++ b/go.sum @@ -1021,8 +1021,8 @@ k8s.io/sample-apiserver v0.22.2/go.mod h1:h+/DIV5EmuNq4vfPr5TSXy9mIBVXXlPAKQMPbj k8s.io/system-validators v1.5.0/go.mod h1:bPldcLgkIUK22ALflnsXk8pvkTEndYdNuaHH6gRrl0Q= k8s.io/utils v0.0.0-20240102154912-e7106e64919e h1:eQ/4ljkx21sObifjzXwlPKpdGLrCfRziVtos3ofG/sQ= k8s.io/utils v0.0.0-20240102154912-e7106e64919e/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= -kusionstack.io/kube-api v0.7.5-0.20260306081812-18b6128bc6fb h1:ODxnOte9umQL5yjsNjnGj+OmNqZRx/NtjaYgJteemW8= -kusionstack.io/kube-api v0.7.5-0.20260306081812-18b6128bc6fb/go.mod h1:e1jtrQH2LK5fD2nTyfIXG6nYrYbU8VXShRxTRwVPaLk= +kusionstack.io/kube-api v0.7.5-0.20260413084915-e038d5ff4fea h1:fQ6jQ5QDOPBthYBcz2ibu0F6QbCGMOzcWZLGO2mGZhY= +kusionstack.io/kube-api v0.7.5-0.20260413084915-e038d5ff4fea/go.mod h1:e1jtrQH2LK5fD2nTyfIXG6nYrYbU8VXShRxTRwVPaLk= kusionstack.io/kube-utils v0.2.1-0.20251125083928-1134a582b341 h1:dnMtHJvIpU3338WpqGiNN2qXWZFiXaoiuzR9jwhvWpg= kusionstack.io/kube-utils v0.2.1-0.20251125083928-1134a582b341/go.mod h1:Lz5SBYWg9+jw+kP0CAyf/b62D5DeUPf6+jE1d0WC4cI= kusionstack.io/resourceconsist v0.0.4 h1:wRqLJuNh8O4TT6p0uOklFpHUKiRdRxcAH71Sw/q9LhE= diff --git a/pkg/controllers/rollout/inline_strategy.go b/pkg/controllers/rollout/inline_strategy.go index f4a60c0..c519d08 100644 --- a/pkg/controllers/rollout/inline_strategy.go +++ b/pkg/controllers/rollout/inline_strategy.go @@ -56,7 +56,7 @@ func constructRolloutRunFromInlineStrategy( Kind: obj.Spec.WorkloadRef.Kind, }, TrafficTopologyRefs: obj.Spec.TrafficTopologyRefs, - Webhooks: []rolloutv1alpha1.RolloutWebhook{}, // Empty for inline strategy + Webhooks: obj.Spec.Webhooks, }, } diff --git a/pkg/controllers/rollout/rollout_controller.go b/pkg/controllers/rollout/rollout_controller.go index 51c110e..ad78123 100644 --- a/pkg/controllers/rollout/rollout_controller.go +++ b/pkg/controllers/rollout/rollout_controller.go @@ -722,7 +722,7 @@ func (r *RolloutReconciler) applyOneTimeStrategy(ctx context.Context, obj *rollo return nil }) if err != nil { - r.recordCondition(obj, newStatus, rolloutv1alpha1.RolloutConditionTrigger, metav1.ConditionFalse, "FailedUpdate", fmt.Sprintf("failed to apply one time stratey to RolloutRun: %v", err)) + r.recordCondition(obj, newStatus, rolloutv1alpha1.RolloutConditionTrigger, metav1.ConditionFalse, "FailedUpdate", fmt.Sprintf("failed to apply one time strategy to RolloutRun: %v", err)) // allow retry return err } diff --git a/pkg/controllers/rollout/rollout_controller_test.go b/pkg/controllers/rollout/rollout_controller_test.go index 7c13762..d6dc2d3 100644 --- a/pkg/controllers/rollout/rollout_controller_test.go +++ b/pkg/controllers/rollout/rollout_controller_test.go @@ -614,7 +614,7 @@ func (s *RolloutControllerTestSuite) Test_TriggerRolloutRunWithInlineBatchStrate s.Require().Equal("30%", run.Spec.Batch.Batches[0].Targets[0].Replicas.String()) // Verify second batch - s.Require().True(run.Spec.Batch.Batches[1].Breakpoint, "Second batch should not have breakpoint") + s.Require().True(run.Spec.Batch.Batches[1].Breakpoint, "Second batch should have breakpoint") s.Require().Len(run.Spec.Batch.Batches[1].Targets, 1, "Second batch should have 1 target") s.Require().Equal("100%", run.Spec.Batch.Batches[1].Targets[0].Replicas.String()) } From 6a3447b259fd7e98f0e37e279bb60586820fdcb8 Mon Sep 17 00:00:00 2001 From: youngLiuHY Date: Wed, 6 May 2026 14:31:38 +0800 Subject: [PATCH 08/10] feat: adapt to V2 strategy API - remove inline strategy, support BatchV2/CanaryV2 on RolloutStrategy MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adapt rollout codebase to kube-api PR #49 which removes CanaryStrategy, BatchStrategy and Webhooks from RolloutSpec and adds CanaryV2/BatchV2 to RolloutStrategy. Key changes: - Remove inline strategy validation from RolloutSpec, require StrategyRef - Add V1/V2 mutual exclusion validation for RolloutStrategy - Add V2 construction path: constructRolloutRunCanaryV2, constructRolloutRunBatchesV2, resolveRolloutTargets - Update OneTimeStrategy: InlineBatch → BatchV2, ConvertFromInline → ConvertFromV2 - Remove inline_strategy.go, merge helpers into utils.go - Update CRD YAML and config samples for new API shape - Simplify constructRolloutRun error return (always succeeds now) Co-Authored-By: Claude Opus 4.6 --- apis/rollout/v1alpha1/validation/rollout.go | 41 +- .../v1alpha1/validation/rollout_test.go | 307 +- .../v1alpha1/validation/rolloutstrategy.go | 85 +- .../validation/rolloutstrategy_test.go | 156 + .../rollout.kusionstack.io_rollouts.yaml | 4453 +---- ...lout.kusionstack.io_rolloutstrategies.yaml | 13369 +++++++++++----- config/kind/workload/bases/rollout.yaml | 54 +- config/rbac/role.yaml | 26 + config/samples/rollout_v1alpha1_rollout.yaml | 9 +- .../rollout_v1alpha1_rolloutstrategy.yaml | 8 +- go.mod | 2 +- go.sum | 4 +- pkg/controllers/rollout/inline_strategy.go | 192 - .../rollout/inline_strategy_test.go | 645 - pkg/controllers/rollout/rollout_controller.go | 28 +- .../rollout/rollout_controller_test.go | 253 +- pkg/controllers/rollout/utils.go | 104 +- pkg/controllers/rollout/utils_test.go | 451 +- pkg/features/ontimestrategy/ontimestrategy.go | 35 +- 19 files changed, 9790 insertions(+), 10432 deletions(-) delete mode 100644 pkg/controllers/rollout/inline_strategy.go delete mode 100644 pkg/controllers/rollout/inline_strategy_test.go diff --git a/apis/rollout/v1alpha1/validation/rollout.go b/apis/rollout/v1alpha1/validation/rollout.go index 09efb19..cb8737c 100644 --- a/apis/rollout/v1alpha1/validation/rollout.go +++ b/apis/rollout/v1alpha1/validation/rollout.go @@ -42,44 +42,9 @@ func ValidateRolloutSpec(spec *rolloutv1alpha1.RolloutSpec, fldPath *field.Path, allErrs = append(allErrs, field.NotSupported(fldPath.Child("triggerPolicy"), spec.TriggerPolicy, []string{string(rolloutv1alpha1.AutoTriggerPolicy), string(rolloutv1alpha1.ManualTriggerPolicy)})) } - // Validate strategy mutual exclusion: StrategyRef vs inline strategies (CanaryStrategy and BatchStrategy) - hasStrategyRef := len(spec.StrategyRef) > 0 - hasCanary := spec.CanaryStrategy != nil - hasBatch := spec.BatchStrategy != nil - - // StrategyRef is mutually exclusive with inline strategies - if hasStrategyRef && hasBatch { - allErrs = append(allErrs, field.Invalid( - fldPath, - spec.StrategyRef, - "strategyRef is mutually exclusive with batchStrategy", - )) - } - - if hasCanary && !hasBatch { - allErrs = append(allErrs, field.Invalid( - fldPath, - spec.StrategyRef, - "batchStrategy is required when canaryStrategy is set", - )) - } - - // Must specify at least one strategy - if !hasStrategyRef && !hasBatch { - allErrs = append(allErrs, field.Required( - fldPath.Child("strategyRef"), - "must specify either strategyRef, or batchStrategy", - )) - } - - // Validate CanaryStrategy if present - if hasCanary { - allErrs = append(allErrs, ValidateRolloutRunCanaryStrategy(spec.CanaryStrategy, fldPath.Child("canaryStrategy"))...) - } - - // Validate BatchStrategy if present - if hasBatch { - allErrs = append(allErrs, ValidateRolloutRunBatchStrategy(spec.BatchStrategy, fldPath.Child("batchStrategy"))...) + // StrategyRef is required + if len(spec.StrategyRef) == 0 { + allErrs = append(allErrs, field.Required(fldPath.Child("strategyRef"), "strategyRef is required")) } allErrs = append(allErrs, ValidateWorkloadRef(&spec.WorkloadRef, fldPath.Child("workloadRef"), isSupportedGVK)...) diff --git a/apis/rollout/v1alpha1/validation/rollout_test.go b/apis/rollout/v1alpha1/validation/rollout_test.go index 9cee580..1c4a78a 100644 --- a/apis/rollout/v1alpha1/validation/rollout_test.go +++ b/apis/rollout/v1alpha1/validation/rollout_test.go @@ -21,7 +21,6 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime/schema" - "k8s.io/apimachinery/pkg/util/intstr" rolloutv1alpha1 "kusionstack.io/kube-api/rollout/v1alpha1" ) @@ -86,7 +85,7 @@ func TestValidateRollout(t *testing.T) { wantErr: true, }, { - name: "invalid strategy ref", + name: "empty strategy ref", obj: func() *rolloutv1alpha1.Rollout { ro := validRollout.DeepCopy() ro.Spec.StrategyRef = "" @@ -122,307 +121,3 @@ func TestValidateRollout(t *testing.T) { }) } } - -// Tests for inline batch strategy validation -func TestValidateRollout_InlineBatchStrategy(t *testing.T) { - tests := []struct { - name string - obj *rolloutv1alpha1.Rollout - isSupportedGVK SupportedGVKFunc - wantErr bool - errMsg string - }{ - { - name: "valid inline batch strategy", - obj: &rolloutv1alpha1.Rollout{ - ObjectMeta: validMetadata, - Spec: rolloutv1alpha1.RolloutSpec{ - TriggerPolicy: "Auto", - WorkloadRef: validWorkloadRef, - BatchStrategy: &rolloutv1alpha1.RolloutRunBatchStrategy{ - Batches: []rolloutv1alpha1.RolloutRunStep{ - { - Targets: []rolloutv1alpha1.RolloutRunStepTarget{ - { - CrossClusterObjectNameReference: rolloutv1alpha1.CrossClusterObjectNameReference{ - Cluster: "cluster-a", - Name: "test", - }, - Replicas: intstr.FromString("20%"), - }, - }, - }, - }, - }, - }, - }, - isSupportedGVK: supportAllGVK, - wantErr: false, - }, - { - name: "batch strategy with multiple batches", - obj: &rolloutv1alpha1.Rollout{ - ObjectMeta: validMetadata, - Spec: rolloutv1alpha1.RolloutSpec{ - TriggerPolicy: "Auto", - WorkloadRef: validWorkloadRef, - BatchStrategy: &rolloutv1alpha1.RolloutRunBatchStrategy{ - Batches: []rolloutv1alpha1.RolloutRunStep{ - { - Breakpoint: true, - Targets: []rolloutv1alpha1.RolloutRunStepTarget{ - { - CrossClusterObjectNameReference: rolloutv1alpha1.CrossClusterObjectNameReference{ - Cluster: "cluster-a", - Name: "test", - }, - Replicas: intstr.FromString("20%"), - }, - }, - }, - { - Targets: []rolloutv1alpha1.RolloutRunStepTarget{ - { - CrossClusterObjectNameReference: rolloutv1alpha1.CrossClusterObjectNameReference{ - Cluster: "cluster-a", - Name: "test", - }, - Replicas: intstr.FromString("100%"), - }, - }, - }, - }, - }, - }, - }, - isSupportedGVK: supportAllGVK, - wantErr: false, - }, - { - name: "batch strategy with multiple targets in one batch", - obj: &rolloutv1alpha1.Rollout{ - ObjectMeta: validMetadata, - Spec: rolloutv1alpha1.RolloutSpec{ - TriggerPolicy: "Auto", - WorkloadRef: validWorkloadRef, - BatchStrategy: &rolloutv1alpha1.RolloutRunBatchStrategy{ - Batches: []rolloutv1alpha1.RolloutRunStep{ - { - Targets: []rolloutv1alpha1.RolloutRunStepTarget{ - { - CrossClusterObjectNameReference: rolloutv1alpha1.CrossClusterObjectNameReference{ - Cluster: "cluster-a", - Name: "test-1", - }, - Replicas: intstr.FromString("20%"), - }, - { - CrossClusterObjectNameReference: rolloutv1alpha1.CrossClusterObjectNameReference{ - Cluster: "cluster-b", - Name: "test-2", - }, - Replicas: intstr.FromString("30%"), - }, - }, - }, - }, - }, - }, - }, - isSupportedGVK: supportAllGVK, - wantErr: false, - }, - { - name: "empty batch strategy - no batches", - obj: &rolloutv1alpha1.Rollout{ - ObjectMeta: validMetadata, - Spec: rolloutv1alpha1.RolloutSpec{ - TriggerPolicy: "Auto", - WorkloadRef: validWorkloadRef, - BatchStrategy: &rolloutv1alpha1.RolloutRunBatchStrategy{ - Batches: []rolloutv1alpha1.RolloutRunStep{}, - }, - }, - }, - isSupportedGVK: supportAllGVK, - wantErr: true, - errMsg: "must specify at least one batch", - }, - { - name: "batch with empty targets", - obj: &rolloutv1alpha1.Rollout{ - ObjectMeta: validMetadata, - Spec: rolloutv1alpha1.RolloutSpec{ - TriggerPolicy: "Auto", - WorkloadRef: validWorkloadRef, - BatchStrategy: &rolloutv1alpha1.RolloutRunBatchStrategy{ - Batches: []rolloutv1alpha1.RolloutRunStep{ - { - Targets: []rolloutv1alpha1.RolloutRunStepTarget{}, - }, - }, - }, - }, - }, - isSupportedGVK: supportAllGVK, - wantErr: true, - errMsg: "must specify at least one target", - }, - { - name: "target missing name", - obj: &rolloutv1alpha1.Rollout{ - ObjectMeta: validMetadata, - Spec: rolloutv1alpha1.RolloutSpec{ - TriggerPolicy: "Auto", - WorkloadRef: validWorkloadRef, - BatchStrategy: &rolloutv1alpha1.RolloutRunBatchStrategy{ - Batches: []rolloutv1alpha1.RolloutRunStep{ - { - Targets: []rolloutv1alpha1.RolloutRunStepTarget{ - { - CrossClusterObjectNameReference: rolloutv1alpha1.CrossClusterObjectNameReference{ - Cluster: "cluster-a", - }, - Replicas: intstr.FromString("20%"), - }, - }, - }, - }, - }, - }, - }, - isSupportedGVK: supportAllGVK, - wantErr: true, - errMsg: "name is required", - }, - { - name: "target with invalid replicas", - obj: &rolloutv1alpha1.Rollout{ - ObjectMeta: validMetadata, - Spec: rolloutv1alpha1.RolloutSpec{ - TriggerPolicy: "Auto", - WorkloadRef: validWorkloadRef, - BatchStrategy: &rolloutv1alpha1.RolloutRunBatchStrategy{ - Batches: []rolloutv1alpha1.RolloutRunStep{ - { - Targets: []rolloutv1alpha1.RolloutRunStepTarget{ - { - CrossClusterObjectNameReference: rolloutv1alpha1.CrossClusterObjectNameReference{ - Cluster: "cluster-a", - Name: "test", - }, - Replicas: intstr.FromString("-1"), - }, - }, - }, - }, - }, - }, - }, - isSupportedGVK: supportAllGVK, - wantErr: true, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - got := ValidateRollout(tt.obj, tt.isSupportedGVK) - hasErr := got.ToAggregate() != nil - if tt.wantErr != hasErr { - t.Errorf("ValidateRollout() error = %v, wantErr %v", got.ToAggregate(), tt.wantErr) - return - } - if tt.wantErr && tt.errMsg != "" { - errStr := got.ToAggregate().Error() - if !containsString(errStr, tt.errMsg) { - t.Errorf("ValidateRollout() error message = %q, should contain %q", errStr, tt.errMsg) - } - } - }) - } -} - -// Tests for StrategyRef and inline strategy mutual exclusion -func TestValidateRollout_StrategyMutualExclusion(t *testing.T) { - tests := []struct { - name string - obj *rolloutv1alpha1.Rollout - isSupportedGVK SupportedGVKFunc - wantErr bool - errMsg string - }{ - { - name: "StrategyRef is mutually exclusive with BatchStrategy", - obj: &rolloutv1alpha1.Rollout{ - ObjectMeta: validMetadata, - Spec: rolloutv1alpha1.RolloutSpec{ - TriggerPolicy: "Auto", - StrategyRef: "strategy-a", - WorkloadRef: validWorkloadRef, - BatchStrategy: &rolloutv1alpha1.RolloutRunBatchStrategy{ - Batches: []rolloutv1alpha1.RolloutRunStep{ - { - Targets: []rolloutv1alpha1.RolloutRunStepTarget{ - { - CrossClusterObjectNameReference: rolloutv1alpha1.CrossClusterObjectNameReference{ - Cluster: "cluster-a", - Name: "test", - }, - Replicas: intstr.FromString("20%"), - }, - }, - }, - }, - }, - }, - }, - isSupportedGVK: supportAllGVK, - wantErr: true, - errMsg: "strategyRef is mutually exclusive with batchStrategy", - }, - { - name: "neither StrategyRef nor BatchStrategy specified", - obj: &rolloutv1alpha1.Rollout{ - ObjectMeta: validMetadata, - Spec: rolloutv1alpha1.RolloutSpec{ - TriggerPolicy: "Auto", - WorkloadRef: validWorkloadRef, - }, - }, - isSupportedGVK: supportAllGVK, - wantErr: true, - errMsg: "must specify either strategyRef, or batchStrategy", - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - got := ValidateRollout(tt.obj, tt.isSupportedGVK) - hasErr := got.ToAggregate() != nil - if tt.wantErr != hasErr { - t.Errorf("ValidateRollout() error = %v, wantErr %v", got.ToAggregate(), tt.wantErr) - return - } - if tt.wantErr && tt.errMsg != "" { - errStr := got.ToAggregate().Error() - if !containsString(errStr, tt.errMsg) { - t.Errorf("ValidateRollout() error message = %q, should contain %q", errStr, tt.errMsg) - } - } - }) - } -} - -// Helper function -func containsString(s, substr string) bool { - return len(s) >= len(substr) && (s == substr || len(s) > 0 && containsStringSub(s, substr)) -} - -func containsStringSub(s, substr string) bool { - for i := 0; i <= len(s)-len(substr); i++ { - if s[i:i+len(substr)] == substr { - return true - } - } - return false -} diff --git a/apis/rollout/v1alpha1/validation/rolloutstrategy.go b/apis/rollout/v1alpha1/validation/rolloutstrategy.go index d56ac2b..882c93c 100644 --- a/apis/rollout/v1alpha1/validation/rolloutstrategy.go +++ b/apis/rollout/v1alpha1/validation/rolloutstrategy.go @@ -28,12 +28,28 @@ import ( func ValidateRolloutStrategy(obj *rolloutv1alpha1.RolloutStrategy) field.ErrorList { allErrs := apimachineryvalidation.ValidateObjectMeta(&obj.ObjectMeta, true, apimachineryvalidation.NameIsDNSSubdomain, field.NewPath("metadata")) - if obj.Canary != nil && obj.Batch == nil { - allErrs = append(allErrs, field.Forbidden(field.NewPath("canary"), "cannot set canary independently")) + // V1 and V2 are mutually exclusive + if obj.Canary != nil && obj.CanaryV2 != nil { + allErrs = append(allErrs, field.Forbidden(field.NewPath("canaryV2"), "canary and canaryV2 are mutually exclusive")) + } + if obj.Batch != nil && obj.BatchV2 != nil { + allErrs = append(allErrs, field.Forbidden(field.NewPath("batchV2"), "batch and batchV2 are mutually exclusive")) } + // V1 validation + if obj.Canary != nil && obj.Batch == nil && obj.BatchV2 == nil { + allErrs = append(allErrs, field.Forbidden(field.NewPath("canary"), "cannot set canary independently")) + } allErrs = append(allErrs, ValidateBatchStrategy(obj.Batch, field.NewPath("batch"))...) allErrs = append(allErrs, ValidateCanaryStrategy(obj.Canary, field.NewPath("canary"))...) + + // V2 validation + if obj.CanaryV2 != nil && obj.BatchV2 == nil && obj.Batch == nil { + allErrs = append(allErrs, field.Forbidden(field.NewPath("canaryV2"), "cannot set canaryV2 independently")) + } + allErrs = append(allErrs, ValidateCanaryStrategyV2(obj.CanaryV2, field.NewPath("canaryV2"))...) + allErrs = append(allErrs, ValidateBatchStrategyV2(obj.BatchV2, field.NewPath("batchV2"))...) + allErrs = append(allErrs, ValidateWebhooks(obj.Webhooks, field.NewPath("webhooks"))...) return allErrs @@ -132,6 +148,71 @@ func ValidateRolloutWebhook(webhook *rolloutv1alpha1.RolloutWebhook, fldPath *fi return allErrs } +func ValidateBatchStrategyV2(strategy *rolloutv1alpha1.BatchStrategyV2, fldPath *field.Path) field.ErrorList { + if strategy == nil { + return nil + } + + allErrs := field.ErrorList{} + + if len(strategy.Batches) == 0 { + return append(allErrs, field.Required(fldPath.Child("batches"), "must have at least one batch")) + } + + for i := range strategy.Batches { + batch := strategy.Batches[i] + allErrs = append(allErrs, ValidateRolloutBatchStep(&batch, fldPath.Child("batches").Index(i))...) + } + + return allErrs +} + +func ValidateRolloutBatchStep(step *rolloutv1alpha1.RolloutBatchStep, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + + if len(step.Targets) == 0 { + allErrs = append(allErrs, field.Required(fldPath.Child("targets"), "must specify at least one target")) + } else { + for i := range step.Targets { + allErrs = append(allErrs, ValidateRolloutTargets(&step.Targets[i], fldPath.Child("targets").Index(i))...) + } + } + + allErrs = append(allErrs, validateTrafficStrategy(step.Traffic, fldPath.Child("traffic"))...) + + return allErrs +} + +func ValidateRolloutTargets(targets *rolloutv1alpha1.RolloutTargets, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + + allErrs = append(allErrs, appsvalidation.ValidatePositiveIntOrPercent(targets.Replicas, fldPath.Child("replicas"))...) + allErrs = append(allErrs, ValidateResourceMatch(targets.Match, fldPath.Child("matchTargets"))...) + + return allErrs +} + +func ValidateCanaryStrategyV2(strategy *rolloutv1alpha1.CanaryStrategyV2, fldPath *field.Path) field.ErrorList { + if strategy == nil { + return nil + } + + allErrs := field.ErrorList{} + + if len(strategy.Targets) == 0 { + allErrs = append(allErrs, field.Required(fldPath.Child("targets"), "must specify at least one target")) + } else { + for i := range strategy.Targets { + allErrs = append(allErrs, ValidateRolloutTargets(&strategy.Targets[i], fldPath.Child("targets").Index(i))...) + } + } + + allErrs = append(allErrs, validateTemplateMetadataPatch(strategy.TemplateMetadataPatch, fldPath.Child("patch"))...) + allErrs = append(allErrs, validateTrafficStrategy(strategy.Traffic, fldPath.Child("traffic"))...) + + return allErrs +} + func validateTrafficStrategy(traffic *rolloutv1alpha1.TrafficStrategy, fldPath *field.Path) field.ErrorList { if traffic == nil { return nil diff --git a/apis/rollout/v1alpha1/validation/rolloutstrategy_test.go b/apis/rollout/v1alpha1/validation/rolloutstrategy_test.go index 38b0e63..75fe7ed 100644 --- a/apis/rollout/v1alpha1/validation/rolloutstrategy_test.go +++ b/apis/rollout/v1alpha1/validation/rolloutstrategy_test.go @@ -170,3 +170,159 @@ func TestValidateRolloutStrategy(t *testing.T) { }) } } + +func TestValidateRolloutStrategy_V2(t *testing.T) { + validV2Strategy := &rolloutv1alpha1.RolloutStrategy{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-v2", + Namespace: "default", + }, + CanaryV2: &rolloutv1alpha1.CanaryStrategyV2{ + Targets: []rolloutv1alpha1.RolloutTargets{ + { + Replicas: intstr.FromString("10%"), + }, + }, + }, + BatchV2: &rolloutv1alpha1.BatchStrategyV2{ + Batches: []rolloutv1alpha1.RolloutBatchStep{ + { + Targets: []rolloutv1alpha1.RolloutTargets{ + { + Replicas: intstr.FromString("30%"), + }, + { + Replicas: intstr.FromString("50%"), + }, + }, + }, + { + Breakpoint: true, + Targets: []rolloutv1alpha1.RolloutTargets{ + { + Replicas: intstr.FromString("100%"), + }, + }, + }, + }, + }, + } + + tests := []struct { + name string + obj *rolloutv1alpha1.RolloutStrategy + wantErr bool + errLen int + }{ + { + name: "valid v2 strategy", + obj: validV2Strategy, + wantErr: false, + }, + { + name: "canaryV2 without batchV2 or batch", + obj: func() *rolloutv1alpha1.RolloutStrategy { + obj := validV2Strategy.DeepCopy() + obj.BatchV2 = nil + return obj + }(), + wantErr: true, + errLen: 1, + }, + { + name: "batchV2 and batch mutually exclusive", + obj: func() *rolloutv1alpha1.RolloutStrategy { + obj := validV2Strategy.DeepCopy() + obj.Batch = &rolloutv1alpha1.BatchStrategy{ + Batches: []rolloutv1alpha1.RolloutStep{ + {Replicas: intstr.FromString("100%")}, + }, + } + return obj + }(), + wantErr: true, + errLen: 1, + }, + { + name: "canaryV2 and canary mutually exclusive", + obj: func() *rolloutv1alpha1.RolloutStrategy { + obj := validV2Strategy.DeepCopy() + obj.BatchV2 = nil + obj.Canary = &rolloutv1alpha1.CanaryStrategy{Replicas: intstr.FromInt(1)} + obj.Batch = &rolloutv1alpha1.BatchStrategy{ + Batches: []rolloutv1alpha1.RolloutStep{ + {Replicas: intstr.FromString("100%")}, + }, + } + return obj + }(), + wantErr: true, + errLen: 1, + }, + { + name: "batchV2 with empty batches", + obj: func() *rolloutv1alpha1.RolloutStrategy { + obj := validV2Strategy.DeepCopy() + obj.CanaryV2 = nil + obj.BatchV2.Batches = nil + return obj + }(), + wantErr: true, + errLen: 1, + }, + { + name: "batchV2 step with empty targets", + obj: func() *rolloutv1alpha1.RolloutStrategy { + obj := validV2Strategy.DeepCopy() + obj.CanaryV2 = nil + obj.BatchV2.Batches = []rolloutv1alpha1.RolloutBatchStep{ + {Targets: nil}, + } + return obj + }(), + wantErr: true, + errLen: 1, + }, + { + name: "canaryV2 with empty targets", + obj: func() *rolloutv1alpha1.RolloutStrategy { + obj := validV2Strategy.DeepCopy() + obj.CanaryV2.Targets = nil + return obj + }(), + wantErr: true, + errLen: 1, + }, + { + name: "rolloutTargets with invalid replicas", + obj: func() *rolloutv1alpha1.RolloutStrategy { + obj := validV2Strategy.DeepCopy() + obj.BatchV2.Batches[0].Targets[0].Replicas = intstr.FromString("-1") + return obj + }(), + wantErr: true, + }, + { + name: "batchV2 only (without canaryV2) is valid", + obj: func() *rolloutv1alpha1.RolloutStrategy { + obj := validV2Strategy.DeepCopy() + obj.CanaryV2 = nil + return obj + }(), + wantErr: false, + }, + } + + for i := range tests { + tt := tests[i] + t.Run(tt.name, func(t *testing.T) { + got := ValidateRolloutStrategy(tt.obj) + if tt.wantErr != (got.ToAggregate() != nil) { + t.Errorf("ValidateRolloutStrategy() = %v, wantErr %v", got, tt.wantErr) + } + if tt.wantErr && tt.errLen > 0 && len(got) != tt.errLen { + t.Errorf("ValidateRolloutStrategy() = %v, want errors count %v", got, tt.errLen) + } + }) + } +} diff --git a/config/crd/bases/rollout.kusionstack.io_rollouts.yaml b/config/crd/bases/rollout.kusionstack.io_rollouts.yaml index 53eff15..a1d77e3 100644 --- a/config/crd/bases/rollout.kusionstack.io_rollouts.yaml +++ b/config/crd/bases/rollout.kusionstack.io_rollouts.yaml @@ -1,3 +1,4 @@ +--- apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: @@ -54,4453 +55,6 @@ spec: spec: description: RolloutSpec defines the desired state of Rollout properties: - batchStrategy: - description: |- - BatchStrategy defines the inline batch strategy. - This allows specifying batch deployment details directly in Rollout - without requiring a separate RolloutStrategy resource. - Mutually exclusive with StrategyRef. - properties: - batches: - description: Batches define the order of phases to execute release in batch release - items: - properties: - breakpoint: - description: If set to true, the rollout will be paused before the step starts. - type: boolean - properties: - additionalProperties: - type: string - description: Properties contains additional information for step - type: object - targets: - description: desired target replicas - items: - properties: - cluster: - description: Cluster indicates the name of cluster - type: string - name: - description: Name is the resource name - type: string - replicaSlidingWindow: - anyOf: - - type: integer - - type: string - description: |- - ReplicaSlidingWindow used to control the number of pods that are allowed to be upgraded in - a sliding window for progressive rollout smoothly. - x-kubernetes-int-or-string: true - replicas: - anyOf: - - type: integer - - type: string - description: Replicas is the replicas of the rollout task, which represents the number of pods to be upgraded - x-kubernetes-int-or-string: true - required: - - name - - replicas - type: object - type: array - traffic: - description: traffic strategy - properties: - http: - properties: - filters: - description: |- - Filters define the filters that are applied to requests that match - this rule. - - - The effects of ordering of multiple behaviors are currently unspecified. - This can change in the future based on feedback during the alpha stage. - - - Conformance-levels at this level are defined based on the type of filter: - - - - ALL core filters MUST be supported by all implementations. - - Implementers are encouraged to support extended filters. - - Implementation-specific custom filters have no API guarantees across - implementations. - - - Specifying the same filter multiple times is not supported unless explicitly - indicated in the filter. - - - All filters are expected to be compatible with each other except for the - URLRewrite and RequestRedirect filters, which may not be combined. If an - implementation can not support other combinations of filters, they must clearly - document that limitation. In cases where incompatible or unsupported - filters are specified and cause the `Accepted` condition to be set to status - `False`, implementations may use the `IncompatibleFilters` reason to specify - this configuration error. - - - Support: Core - items: - description: |- - HTTPRouteFilter defines processing steps that must be completed during the - request or response lifecycle. HTTPRouteFilters are meant as an extension - point to express processing that may be done in Gateway implementations. Some - examples include request or response modification, implementing - authentication strategies, rate-limiting, and traffic shaping. API - guarantee/conformance is defined based on the type of the filter. - properties: - extensionRef: - description: |- - ExtensionRef is an optional, implementation-specific extension to the - "filter" behavior. For example, resource "myroutefilter" in group - "networking.example.net"). ExtensionRef MUST NOT be used for core and - extended filters. - - - This filter can be used multiple times within the same rule. - - - Support: Implementation-specific - properties: - group: - description: |- - Group is the group of the referent. For example, "gateway.networking.k8s.io". - When unspecified or empty string, core API group is inferred. - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - description: Kind is kind of the referent. For example "HTTPRoute" or "Service". - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - type: string - name: - description: Name is the name of the referent. - maxLength: 253 - minLength: 1 - type: string - required: - - group - - kind - - name - type: object - requestHeaderModifier: - description: |- - RequestHeaderModifier defines a schema for a filter that modifies request - headers. - - - Support: Core - properties: - add: - description: |- - Add adds the given header(s) (name, value) to the request - before the action. It appends to any existing values associated - with the header name. - - - Input: - GET /foo HTTP/1.1 - my-header: foo - - - Config: - add: - - name: "my-header" - value: "bar,baz" - - - Output: - GET /foo HTTP/1.1 - my-header: foo,bar,baz - items: - description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. - properties: - name: - description: |- - Name is the name of the HTTP Header to be matched. Name matching MUST be - case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). - - - If multiple entries specify equivalent header names, the first entry with - an equivalent name MUST be considered for a match. Subsequent entries - with an equivalent header name MUST be ignored. Due to the - case-insensitivity of header names, "foo" and "Foo" are considered - equivalent. - maxLength: 256 - minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ - type: string - value: - description: Value is the value of HTTP Header to be matched. - maxLength: 4096 - minLength: 1 - type: string - required: - - name - - value - type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - remove: - description: |- - Remove the given header(s) from the HTTP request before the action. The - value of Remove is a list of HTTP header names. Note that the header - names are case-insensitive (see - https://datatracker.ietf.org/doc/html/rfc2616#section-4.2). - - - Input: - GET /foo HTTP/1.1 - my-header1: foo - my-header2: bar - my-header3: baz - - - Config: - remove: ["my-header1", "my-header3"] - - - Output: - GET /foo HTTP/1.1 - my-header2: bar - items: - type: string - maxItems: 16 - type: array - x-kubernetes-list-type: set - set: - description: |- - Set overwrites the request with the given header (name, value) - before the action. - - - Input: - GET /foo HTTP/1.1 - my-header: foo - - - Config: - set: - - name: "my-header" - value: "bar" - - - Output: - GET /foo HTTP/1.1 - my-header: bar - items: - description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. - properties: - name: - description: |- - Name is the name of the HTTP Header to be matched. Name matching MUST be - case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). - - - If multiple entries specify equivalent header names, the first entry with - an equivalent name MUST be considered for a match. Subsequent entries - with an equivalent header name MUST be ignored. Due to the - case-insensitivity of header names, "foo" and "Foo" are considered - equivalent. - maxLength: 256 - minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ - type: string - value: - description: Value is the value of HTTP Header to be matched. - maxLength: 4096 - minLength: 1 - type: string - required: - - name - - value - type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - type: object - requestMirror: - description: |- - RequestMirror defines a schema for a filter that mirrors requests. - Requests are sent to the specified destination, but responses from - that destination are ignored. - - - This filter can be used multiple times within the same rule. Note that - not all implementations will be able to support mirroring to multiple - backends. - - - Support: Extended - - - - properties: - backendRef: - description: |- - BackendRef references a resource where mirrored requests are sent. - - - Mirrored requests must be sent only to a single destination endpoint - within this BackendRef, irrespective of how many endpoints are present - within this BackendRef. - - - If the referent cannot be found, this BackendRef is invalid and must be - dropped from the Gateway. The controller must ensure the "ResolvedRefs" - condition on the Route status is set to `status: False` and not configure - this backend in the underlying implementation. - - - If there is a cross-namespace reference to an *existing* object - that is not allowed by a ReferenceGrant, the controller must ensure the - "ResolvedRefs" condition on the Route is set to `status: False`, - with the "RefNotPermitted" reason and not configure this backend in the - underlying implementation. - - - In either error case, the Message of the `ResolvedRefs` Condition - should be used to provide more detail about the problem. - - - Support: Extended for Kubernetes Service - - - Support: Implementation-specific for any other resource - properties: - group: - default: "" - description: |- - Group is the group of the referent. For example, "gateway.networking.k8s.io". - When unspecified or empty string, core API group is inferred. - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - default: Service - description: |- - Kind is the Kubernetes resource kind of the referent. For example - "Service". - - - Defaults to "Service" when not specified. - - - ExternalName services can refer to CNAME DNS records that may live - outside of the cluster and as such are difficult to reason about in - terms of conformance. They also may not be safe to forward to (see - CVE-2021-25740 for more information). Implementations SHOULD NOT - support ExternalName Services. - - - Support: Core (Services with a type other than ExternalName) - - - Support: Implementation-specific (Services with type ExternalName) - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - type: string - name: - description: Name is the name of the referent. - maxLength: 253 - minLength: 1 - type: string - namespace: - description: |- - Namespace is the namespace of the backend. When unspecified, the local - namespace is inferred. - - - Note that when a namespace different than the local namespace is specified, - a ReferenceGrant object is required in the referent namespace to allow that - namespace's owner to accept the reference. See the ReferenceGrant - documentation for details. - - - Support: Core - maxLength: 63 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ - type: string - port: - description: |- - Port specifies the destination port number to use for this resource. - Port is required when the referent is a Kubernetes Service. In this - case, the port number is the service port number, not the target port. - For other resources, destination port might be derived from the referent - resource or this field. - format: int32 - maximum: 65535 - minimum: 1 - type: integer - required: - - name - type: object - fraction: - description: |- - Fraction represents the fraction of requests that should be - mirrored to BackendRef. - - - Only one of Fraction or Percent may be specified. If neither field - is specified, 100% of requests will be mirrored. - - - - properties: - denominator: - default: 100 - format: int32 - minimum: 1 - type: integer - numerator: - format: int32 - minimum: 0 - type: integer - required: - - numerator - type: object - percent: - description: |- - Percent represents the percentage of requests that should be - mirrored to BackendRef. Its minimum value is 0 (indicating 0% of - requests) and its maximum value is 100 (indicating 100% of requests). - - - Only one of Fraction or Percent may be specified. If neither field - is specified, 100% of requests will be mirrored. - - - - format: int32 - maximum: 100 - minimum: 0 - type: integer - required: - - backendRef - type: object - requestRedirect: - description: |- - RequestRedirect defines a schema for a filter that responds to the - request with an HTTP redirection. - - - Support: Core - properties: - hostname: - description: |- - Hostname is the hostname to be used in the value of the `Location` - header in the response. - When empty, the hostname in the `Host` header of the request is used. - - - Support: Core - maxLength: 253 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - path: - description: |- - Path defines parameters used to modify the path of the incoming request. - The modified path is then used to construct the `Location` header. When - empty, the request path is used as-is. - - - Support: Extended - properties: - replaceFullPath: - description: |- - ReplaceFullPath specifies the value with which to replace the full path - of a request during a rewrite or redirect. - maxLength: 1024 - type: string - replacePrefixMatch: - description: |- - ReplacePrefixMatch specifies the value with which to replace the prefix - match of a request during a rewrite or redirect. For example, a request - to "/foo/bar" with a prefix match of "/foo" and a ReplacePrefixMatch - of "/xyz" would be modified to "/xyz/bar". - - - Note that this matches the behavior of the PathPrefix match type. This - matches full path elements. A path element refers to the list of labels - in the path split by the `/` separator. When specified, a trailing `/` is - ignored. For example, the paths `/abc`, `/abc/`, and `/abc/def` would all - match the prefix `/abc`, but the path `/abcd` would not. - - - ReplacePrefixMatch is only compatible with a `PathPrefix` HTTPRouteMatch. - Using any other HTTPRouteMatch type on the same HTTPRouteRule will result in - the implementation setting the Accepted Condition for the Route to `status: False`. - - - Request Path | Prefix Match | Replace Prefix | Modified Path - -------------|--------------|----------------|---------- - /foo/bar | /foo | /xyz | /xyz/bar - /foo/bar | /foo | /xyz/ | /xyz/bar - /foo/bar | /foo/ | /xyz | /xyz/bar - /foo/bar | /foo/ | /xyz/ | /xyz/bar - /foo | /foo | /xyz | /xyz - /foo/ | /foo | /xyz | /xyz/ - /foo/bar | /foo | | /bar - /foo/ | /foo | | / - /foo | /foo | | / - /foo/ | /foo | / | / - /foo | /foo | / | / - maxLength: 1024 - type: string - type: - description: |- - Type defines the type of path modifier. Additional types may be - added in a future release of the API. - - - Note that values may be added to this enum, implementations - must ensure that unknown values will not cause a crash. - - - Unknown values here must result in the implementation setting the - Accepted Condition for the Route to `status: False`, with a - Reason of `UnsupportedValue`. - enum: - - ReplaceFullPath - - ReplacePrefixMatch - type: string - required: - - type - type: object - port: - description: |- - Port is the port to be used in the value of the `Location` - header in the response. - - - If no port is specified, the redirect port MUST be derived using the - following rules: - - - * If redirect scheme is not-empty, the redirect port MUST be the well-known - port associated with the redirect scheme. Specifically "http" to port 80 - and "https" to port 443. If the redirect scheme does not have a - well-known port, the listener port of the Gateway SHOULD be used. - * If redirect scheme is empty, the redirect port MUST be the Gateway - Listener port. - - - Implementations SHOULD NOT add the port number in the 'Location' - header in the following cases: - - - * A Location header that will use HTTP (whether that is determined via - the Listener protocol or the Scheme field) _and_ use port 80. - * A Location header that will use HTTPS (whether that is determined via - the Listener protocol or the Scheme field) _and_ use port 443. - - - Support: Extended - format: int32 - maximum: 65535 - minimum: 1 - type: integer - scheme: - description: |- - Scheme is the scheme to be used in the value of the `Location` header in - the response. When empty, the scheme of the request is used. - - - Scheme redirects can affect the port of the redirect, for more information, - refer to the documentation for the port field of this filter. - - - Note that values may be added to this enum, implementations - must ensure that unknown values will not cause a crash. - - - Unknown values here must result in the implementation setting the - Accepted Condition for the Route to `status: False`, with a - Reason of `UnsupportedValue`. - - - Support: Extended - enum: - - http - - https - type: string - statusCode: - default: 302 - description: |- - StatusCode is the HTTP status code to be used in response. - - - Note that values may be added to this enum, implementations - must ensure that unknown values will not cause a crash. - - - Unknown values here must result in the implementation setting the - Accepted Condition for the Route to `status: False`, with a - Reason of `UnsupportedValue`. - - - Support: Core - enum: - - 301 - - 302 - type: integer - type: object - responseHeaderModifier: - description: |- - ResponseHeaderModifier defines a schema for a filter that modifies response - headers. - - - Support: Extended - properties: - add: - description: |- - Add adds the given header(s) (name, value) to the request - before the action. It appends to any existing values associated - with the header name. - - - Input: - GET /foo HTTP/1.1 - my-header: foo - - - Config: - add: - - name: "my-header" - value: "bar,baz" - - - Output: - GET /foo HTTP/1.1 - my-header: foo,bar,baz - items: - description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. - properties: - name: - description: |- - Name is the name of the HTTP Header to be matched. Name matching MUST be - case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). - - - If multiple entries specify equivalent header names, the first entry with - an equivalent name MUST be considered for a match. Subsequent entries - with an equivalent header name MUST be ignored. Due to the - case-insensitivity of header names, "foo" and "Foo" are considered - equivalent. - maxLength: 256 - minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ - type: string - value: - description: Value is the value of HTTP Header to be matched. - maxLength: 4096 - minLength: 1 - type: string - required: - - name - - value - type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - remove: - description: |- - Remove the given header(s) from the HTTP request before the action. The - value of Remove is a list of HTTP header names. Note that the header - names are case-insensitive (see - https://datatracker.ietf.org/doc/html/rfc2616#section-4.2). - - - Input: - GET /foo HTTP/1.1 - my-header1: foo - my-header2: bar - my-header3: baz - - - Config: - remove: ["my-header1", "my-header3"] - - - Output: - GET /foo HTTP/1.1 - my-header2: bar - items: - type: string - maxItems: 16 - type: array - x-kubernetes-list-type: set - set: - description: |- - Set overwrites the request with the given header (name, value) - before the action. - - - Input: - GET /foo HTTP/1.1 - my-header: foo - - - Config: - set: - - name: "my-header" - value: "bar" - - - Output: - GET /foo HTTP/1.1 - my-header: bar - items: - description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. - properties: - name: - description: |- - Name is the name of the HTTP Header to be matched. Name matching MUST be - case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). - - - If multiple entries specify equivalent header names, the first entry with - an equivalent name MUST be considered for a match. Subsequent entries - with an equivalent header name MUST be ignored. Due to the - case-insensitivity of header names, "foo" and "Foo" are considered - equivalent. - maxLength: 256 - minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ - type: string - value: - description: Value is the value of HTTP Header to be matched. - maxLength: 4096 - minLength: 1 - type: string - required: - - name - - value - type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - type: object - type: - description: |- - Type identifies the type of filter to apply. As with other API fields, - types are classified into three conformance levels: - - - - Core: Filter types and their corresponding configuration defined by - "Support: Core" in this package, e.g. "RequestHeaderModifier". All - implementations must support core filters. - - - - Extended: Filter types and their corresponding configuration defined by - "Support: Extended" in this package, e.g. "RequestMirror". Implementers - are encouraged to support extended filters. - - - - Implementation-specific: Filters that are defined and supported by - specific vendors. - In the future, filters showing convergence in behavior across multiple - implementations will be considered for inclusion in extended or core - conformance levels. Filter-specific configuration for such filters - is specified using the ExtensionRef field. `Type` should be set to - "ExtensionRef" for custom filters. - - - Implementers are encouraged to define custom implementation types to - extend the core API with implementation-specific behavior. - - - If a reference to a custom filter type cannot be resolved, the filter - MUST NOT be skipped. Instead, requests that would have been processed by - that filter MUST receive a HTTP error response. - - - Note that values may be added to this enum, implementations - must ensure that unknown values will not cause a crash. - - - Unknown values here must result in the implementation setting the - Accepted Condition for the Route to `status: False`, with a - Reason of `UnsupportedValue`. - enum: - - RequestHeaderModifier - - ResponseHeaderModifier - - RequestMirror - - RequestRedirect - - URLRewrite - - ExtensionRef - type: string - urlRewrite: - description: |- - URLRewrite defines a schema for a filter that modifies a request during forwarding. - - - Support: Extended - properties: - hostname: - description: |- - Hostname is the value to be used to replace the Host header value during - forwarding. - - - Support: Extended - maxLength: 253 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - path: - description: |- - Path defines a path rewrite. - - - Support: Extended - properties: - replaceFullPath: - description: |- - ReplaceFullPath specifies the value with which to replace the full path - of a request during a rewrite or redirect. - maxLength: 1024 - type: string - replacePrefixMatch: - description: |- - ReplacePrefixMatch specifies the value with which to replace the prefix - match of a request during a rewrite or redirect. For example, a request - to "/foo/bar" with a prefix match of "/foo" and a ReplacePrefixMatch - of "/xyz" would be modified to "/xyz/bar". - - - Note that this matches the behavior of the PathPrefix match type. This - matches full path elements. A path element refers to the list of labels - in the path split by the `/` separator. When specified, a trailing `/` is - ignored. For example, the paths `/abc`, `/abc/`, and `/abc/def` would all - match the prefix `/abc`, but the path `/abcd` would not. - - - ReplacePrefixMatch is only compatible with a `PathPrefix` HTTPRouteMatch. - Using any other HTTPRouteMatch type on the same HTTPRouteRule will result in - the implementation setting the Accepted Condition for the Route to `status: False`. - - - Request Path | Prefix Match | Replace Prefix | Modified Path - -------------|--------------|----------------|---------- - /foo/bar | /foo | /xyz | /xyz/bar - /foo/bar | /foo | /xyz/ | /xyz/bar - /foo/bar | /foo/ | /xyz | /xyz/bar - /foo/bar | /foo/ | /xyz/ | /xyz/bar - /foo | /foo | /xyz | /xyz - /foo/ | /foo | /xyz | /xyz/ - /foo/bar | /foo | | /bar - /foo/ | /foo | | / - /foo | /foo | | / - /foo/ | /foo | / | / - /foo | /foo | / | / - maxLength: 1024 - type: string - type: - description: |- - Type defines the type of path modifier. Additional types may be - added in a future release of the API. - - - Note that values may be added to this enum, implementations - must ensure that unknown values will not cause a crash. - - - Unknown values here must result in the implementation setting the - Accepted Condition for the Route to `status: False`, with a - Reason of `UnsupportedValue`. - enum: - - ReplaceFullPath - - ReplacePrefixMatch - type: string - required: - - type - type: object - type: object - required: - - type - type: object - maxItems: 16 - type: array - matches: - description: |- - Matches define conditions used for matching the rule against incoming - HTTP requests. Each match is independent, i.e. this rule will be matched - if **any** one of the matches is satisfied. - - - For example, take the following matches configuration: - - - ``` - matches: - - path: - value: "/foo" - headers: - - name: "version" - value: "v2" - - path: - value: "/v2/foo" - ``` - - - For a request to match against this rule, a request must satisfy - EITHER of the two conditions: - - - - path prefixed with `/foo` AND contains the header `version: v2` - - path prefix of `/v2/foo` - - - See the documentation for HTTPRouteMatch on how to specify multiple - match conditions that should be ANDed together. - - - If no matches are specified, the default is a prefix - path match on "/", which has the effect of matching every - HTTP request. - - - Proxy or Load Balancer routing configuration generated from HTTPRoutes - MUST prioritize matches based on the following criteria, continuing on - ties. Across all rules specified on applicable Routes, precedence must be - given to the match having: - - - * "Exact" path match. - * "Prefix" path match with largest number of characters. - * Method match. - * Largest number of header matches. - * Largest number of query param matches. - - - Note: The precedence of RegularExpression path matches are implementation-specific. - - - If ties still exist across multiple Routes, matching precedence MUST be - determined in order of the following criteria, continuing on ties: - - - * The oldest Route based on creation timestamp. - * The Route appearing first in alphabetical order by - "{namespace}/{name}". - - - If ties still exist within an HTTPRoute, matching precedence MUST be granted - to the FIRST matching rule (in list order) with a match meeting the above - criteria. - - - When no rules matching a request have been successfully attached to the - parent a request is coming from, a HTTP 404 status code MUST be returned. - items: - properties: - headers: - description: |- - Headers specifies HTTP request header matchers. Multiple match values are - ANDed together, meaning, a request must match all the specified headers - to select the route. - items: - description: |- - HTTPHeaderMatch describes how to select a HTTP route by matching HTTP request - headers. - properties: - name: - description: |- - Name is the name of the HTTP Header to be matched. Name matching MUST be - case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). - - - If multiple entries specify equivalent header names, only the first - entry with an equivalent name MUST be considered for a match. Subsequent - entries with an equivalent header name MUST be ignored. Due to the - case-insensitivity of header names, "foo" and "Foo" are considered - equivalent. - - - When a header is repeated in an HTTP request, it is - implementation-specific behavior as to how this is represented. - Generally, proxies should follow the guidance from the RFC: - https://www.rfc-editor.org/rfc/rfc7230.html#section-3.2.2 regarding - processing a repeated header, with special handling for "Set-Cookie". - maxLength: 256 - minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ - type: string - type: - default: Exact - description: |- - Type specifies how to match against the value of the header. - - - Support: Core (Exact) - - - Support: Implementation-specific (RegularExpression) - - - Since RegularExpression HeaderMatchType has implementation-specific - conformance, implementations can support POSIX, PCRE or any other dialects - of regular expressions. Please read the implementation's documentation to - determine the supported dialect. - enum: - - Exact - - RegularExpression - type: string - value: - description: Value is the value of HTTP Header to be matched. - maxLength: 4096 - minLength: 1 - type: string - required: - - name - - value - type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - path: - description: Path specifies a HTTP request path matcher. - properties: - type: - default: PathPrefix - description: |- - Type specifies how to match against the path Value. - - - Support: Core (Exact, PathPrefix) - - - Support: Implementation-specific (RegularExpression) - enum: - - Exact - - PathPrefix - - RegularExpression - type: string - value: - default: / - description: Value of the HTTP path to match against. - maxLength: 1024 - type: string - type: object - queryParams: - description: |- - QueryParams specifies HTTP query parameter matchers. Multiple match - values are ANDed together, meaning, a request must match all the - specified query parameters to select the route. - - - Support: Extended - items: - description: |- - HTTPQueryParamMatch describes how to select a HTTP route by matching HTTP - query parameters. - properties: - name: - description: |- - Name is the name of the HTTP query param to be matched. This must be an - exact string match. (See - https://tools.ietf.org/html/rfc7230#section-2.7.3). - - - If multiple entries specify equivalent query param names, only the first - entry with an equivalent name MUST be considered for a match. Subsequent - entries with an equivalent query param name MUST be ignored. - - - If a query param is repeated in an HTTP request, the behavior is - purposely left undefined, since different data planes have different - capabilities. However, it is *recommended* that implementations should - match against the first value of the param if the data plane supports it, - as this behavior is expected in other load balancing contexts outside of - the Gateway API. - - - Users SHOULD NOT route traffic based on repeated query params to guard - themselves against potential differences in the implementations. - maxLength: 256 - minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ - type: string - type: - default: Exact - description: |- - Type specifies how to match against the value of the query parameter. - - - Support: Extended (Exact) - - - Support: Implementation-specific (RegularExpression) - - - Since RegularExpression QueryParamMatchType has Implementation-specific - conformance, implementations can support POSIX, PCRE or any other - dialects of regular expressions. Please read the implementation's - documentation to determine the supported dialect. - enum: - - Exact - - RegularExpression - type: string - value: - description: Value is the value of HTTP query param to be matched. - maxLength: 1024 - minLength: 1 - type: string - required: - - name - - value - type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - type: object - maxItems: 8 - type: array - stableTraffic: - description: StableTraffic indicate the base traffic rule - properties: - filters: - description: |- - Filters define the filters that are applied to requests that match - this rule. - - - The effects of ordering of multiple behaviors are currently unspecified. - This can change in the future based on feedback during the alpha stage. - - - Conformance-levels at this level are defined based on the type of filter: - - - - ALL core filters MUST be supported by all implementations. - - Implementers are encouraged to support extended filters. - - Implementation-specific custom filters have no API guarantees across - implementations. - - - Specifying the same filter multiple times is not supported unless explicitly - indicated in the filter. - - - All filters are expected to be compatible with each other except for the - URLRewrite and RequestRedirect filters, which may not be combined. If an - implementation can not support other combinations of filters, they must clearly - document that limitation. In cases where incompatible or unsupported - filters are specified and cause the `Accepted` condition to be set to status - `False`, implementations may use the `IncompatibleFilters` reason to specify - this configuration error. - - - Support: Core - items: - description: |- - HTTPRouteFilter defines processing steps that must be completed during the - request or response lifecycle. HTTPRouteFilters are meant as an extension - point to express processing that may be done in Gateway implementations. Some - examples include request or response modification, implementing - authentication strategies, rate-limiting, and traffic shaping. API - guarantee/conformance is defined based on the type of the filter. - properties: - extensionRef: - description: |- - ExtensionRef is an optional, implementation-specific extension to the - "filter" behavior. For example, resource "myroutefilter" in group - "networking.example.net"). ExtensionRef MUST NOT be used for core and - extended filters. - - - This filter can be used multiple times within the same rule. - - - Support: Implementation-specific - properties: - group: - description: |- - Group is the group of the referent. For example, "gateway.networking.k8s.io". - When unspecified or empty string, core API group is inferred. - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - description: Kind is kind of the referent. For example "HTTPRoute" or "Service". - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - type: string - name: - description: Name is the name of the referent. - maxLength: 253 - minLength: 1 - type: string - required: - - group - - kind - - name - type: object - requestHeaderModifier: - description: |- - RequestHeaderModifier defines a schema for a filter that modifies request - headers. - - - Support: Core - properties: - add: - description: |- - Add adds the given header(s) (name, value) to the request - before the action. It appends to any existing values associated - with the header name. - - - Input: - GET /foo HTTP/1.1 - my-header: foo - - - Config: - add: - - name: "my-header" - value: "bar,baz" - - - Output: - GET /foo HTTP/1.1 - my-header: foo,bar,baz - items: - description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. - properties: - name: - description: |- - Name is the name of the HTTP Header to be matched. Name matching MUST be - case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). - - - If multiple entries specify equivalent header names, the first entry with - an equivalent name MUST be considered for a match. Subsequent entries - with an equivalent header name MUST be ignored. Due to the - case-insensitivity of header names, "foo" and "Foo" are considered - equivalent. - maxLength: 256 - minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ - type: string - value: - description: Value is the value of HTTP Header to be matched. - maxLength: 4096 - minLength: 1 - type: string - required: - - name - - value - type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - remove: - description: |- - Remove the given header(s) from the HTTP request before the action. The - value of Remove is a list of HTTP header names. Note that the header - names are case-insensitive (see - https://datatracker.ietf.org/doc/html/rfc2616#section-4.2). - - - Input: - GET /foo HTTP/1.1 - my-header1: foo - my-header2: bar - my-header3: baz - - - Config: - remove: ["my-header1", "my-header3"] - - - Output: - GET /foo HTTP/1.1 - my-header2: bar - items: - type: string - maxItems: 16 - type: array - x-kubernetes-list-type: set - set: - description: |- - Set overwrites the request with the given header (name, value) - before the action. - - - Input: - GET /foo HTTP/1.1 - my-header: foo - - - Config: - set: - - name: "my-header" - value: "bar" - - - Output: - GET /foo HTTP/1.1 - my-header: bar - items: - description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. - properties: - name: - description: |- - Name is the name of the HTTP Header to be matched. Name matching MUST be - case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). - - - If multiple entries specify equivalent header names, the first entry with - an equivalent name MUST be considered for a match. Subsequent entries - with an equivalent header name MUST be ignored. Due to the - case-insensitivity of header names, "foo" and "Foo" are considered - equivalent. - maxLength: 256 - minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ - type: string - value: - description: Value is the value of HTTP Header to be matched. - maxLength: 4096 - minLength: 1 - type: string - required: - - name - - value - type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - type: object - requestMirror: - description: |- - RequestMirror defines a schema for a filter that mirrors requests. - Requests are sent to the specified destination, but responses from - that destination are ignored. - - - This filter can be used multiple times within the same rule. Note that - not all implementations will be able to support mirroring to multiple - backends. - - - Support: Extended - - - - properties: - backendRef: - description: |- - BackendRef references a resource where mirrored requests are sent. - - - Mirrored requests must be sent only to a single destination endpoint - within this BackendRef, irrespective of how many endpoints are present - within this BackendRef. - - - If the referent cannot be found, this BackendRef is invalid and must be - dropped from the Gateway. The controller must ensure the "ResolvedRefs" - condition on the Route status is set to `status: False` and not configure - this backend in the underlying implementation. - - - If there is a cross-namespace reference to an *existing* object - that is not allowed by a ReferenceGrant, the controller must ensure the - "ResolvedRefs" condition on the Route is set to `status: False`, - with the "RefNotPermitted" reason and not configure this backend in the - underlying implementation. - - - In either error case, the Message of the `ResolvedRefs` Condition - should be used to provide more detail about the problem. - - - Support: Extended for Kubernetes Service - - - Support: Implementation-specific for any other resource - properties: - group: - default: "" - description: |- - Group is the group of the referent. For example, "gateway.networking.k8s.io". - When unspecified or empty string, core API group is inferred. - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - default: Service - description: |- - Kind is the Kubernetes resource kind of the referent. For example - "Service". - - - Defaults to "Service" when not specified. - - - ExternalName services can refer to CNAME DNS records that may live - outside of the cluster and as such are difficult to reason about in - terms of conformance. They also may not be safe to forward to (see - CVE-2021-25740 for more information). Implementations SHOULD NOT - support ExternalName Services. - - - Support: Core (Services with a type other than ExternalName) - - - Support: Implementation-specific (Services with type ExternalName) - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - type: string - name: - description: Name is the name of the referent. - maxLength: 253 - minLength: 1 - type: string - namespace: - description: |- - Namespace is the namespace of the backend. When unspecified, the local - namespace is inferred. - - - Note that when a namespace different than the local namespace is specified, - a ReferenceGrant object is required in the referent namespace to allow that - namespace's owner to accept the reference. See the ReferenceGrant - documentation for details. - - - Support: Core - maxLength: 63 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ - type: string - port: - description: |- - Port specifies the destination port number to use for this resource. - Port is required when the referent is a Kubernetes Service. In this - case, the port number is the service port number, not the target port. - For other resources, destination port might be derived from the referent - resource or this field. - format: int32 - maximum: 65535 - minimum: 1 - type: integer - required: - - name - type: object - fraction: - description: |- - Fraction represents the fraction of requests that should be - mirrored to BackendRef. - - - Only one of Fraction or Percent may be specified. If neither field - is specified, 100% of requests will be mirrored. - - - - properties: - denominator: - default: 100 - format: int32 - minimum: 1 - type: integer - numerator: - format: int32 - minimum: 0 - type: integer - required: - - numerator - type: object - percent: - description: |- - Percent represents the percentage of requests that should be - mirrored to BackendRef. Its minimum value is 0 (indicating 0% of - requests) and its maximum value is 100 (indicating 100% of requests). - - - Only one of Fraction or Percent may be specified. If neither field - is specified, 100% of requests will be mirrored. - - - - format: int32 - maximum: 100 - minimum: 0 - type: integer - required: - - backendRef - type: object - requestRedirect: - description: |- - RequestRedirect defines a schema for a filter that responds to the - request with an HTTP redirection. - - - Support: Core - properties: - hostname: - description: |- - Hostname is the hostname to be used in the value of the `Location` - header in the response. - When empty, the hostname in the `Host` header of the request is used. - - - Support: Core - maxLength: 253 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - path: - description: |- - Path defines parameters used to modify the path of the incoming request. - The modified path is then used to construct the `Location` header. When - empty, the request path is used as-is. - - - Support: Extended - properties: - replaceFullPath: - description: |- - ReplaceFullPath specifies the value with which to replace the full path - of a request during a rewrite or redirect. - maxLength: 1024 - type: string - replacePrefixMatch: - description: |- - ReplacePrefixMatch specifies the value with which to replace the prefix - match of a request during a rewrite or redirect. For example, a request - to "/foo/bar" with a prefix match of "/foo" and a ReplacePrefixMatch - of "/xyz" would be modified to "/xyz/bar". - - - Note that this matches the behavior of the PathPrefix match type. This - matches full path elements. A path element refers to the list of labels - in the path split by the `/` separator. When specified, a trailing `/` is - ignored. For example, the paths `/abc`, `/abc/`, and `/abc/def` would all - match the prefix `/abc`, but the path `/abcd` would not. - - - ReplacePrefixMatch is only compatible with a `PathPrefix` HTTPRouteMatch. - Using any other HTTPRouteMatch type on the same HTTPRouteRule will result in - the implementation setting the Accepted Condition for the Route to `status: False`. - - - Request Path | Prefix Match | Replace Prefix | Modified Path - -------------|--------------|----------------|---------- - /foo/bar | /foo | /xyz | /xyz/bar - /foo/bar | /foo | /xyz/ | /xyz/bar - /foo/bar | /foo/ | /xyz | /xyz/bar - /foo/bar | /foo/ | /xyz/ | /xyz/bar - /foo | /foo | /xyz | /xyz - /foo/ | /foo | /xyz | /xyz/ - /foo/bar | /foo | | /bar - /foo/ | /foo | | / - /foo | /foo | | / - /foo/ | /foo | / | / - /foo | /foo | / | / - maxLength: 1024 - type: string - type: - description: |- - Type defines the type of path modifier. Additional types may be - added in a future release of the API. - - - Note that values may be added to this enum, implementations - must ensure that unknown values will not cause a crash. - - - Unknown values here must result in the implementation setting the - Accepted Condition for the Route to `status: False`, with a - Reason of `UnsupportedValue`. - enum: - - ReplaceFullPath - - ReplacePrefixMatch - type: string - required: - - type - type: object - port: - description: |- - Port is the port to be used in the value of the `Location` - header in the response. - - - If no port is specified, the redirect port MUST be derived using the - following rules: - - - * If redirect scheme is not-empty, the redirect port MUST be the well-known - port associated with the redirect scheme. Specifically "http" to port 80 - and "https" to port 443. If the redirect scheme does not have a - well-known port, the listener port of the Gateway SHOULD be used. - * If redirect scheme is empty, the redirect port MUST be the Gateway - Listener port. - - - Implementations SHOULD NOT add the port number in the 'Location' - header in the following cases: - - - * A Location header that will use HTTP (whether that is determined via - the Listener protocol or the Scheme field) _and_ use port 80. - * A Location header that will use HTTPS (whether that is determined via - the Listener protocol or the Scheme field) _and_ use port 443. - - - Support: Extended - format: int32 - maximum: 65535 - minimum: 1 - type: integer - scheme: - description: |- - Scheme is the scheme to be used in the value of the `Location` header in - the response. When empty, the scheme of the request is used. - - - Scheme redirects can affect the port of the redirect, for more information, - refer to the documentation for the port field of this filter. - - - Note that values may be added to this enum, implementations - must ensure that unknown values will not cause a crash. - - - Unknown values here must result in the implementation setting the - Accepted Condition for the Route to `status: False`, with a - Reason of `UnsupportedValue`. - - - Support: Extended - enum: - - http - - https - type: string - statusCode: - default: 302 - description: |- - StatusCode is the HTTP status code to be used in response. - - - Note that values may be added to this enum, implementations - must ensure that unknown values will not cause a crash. - - - Unknown values here must result in the implementation setting the - Accepted Condition for the Route to `status: False`, with a - Reason of `UnsupportedValue`. - - - Support: Core - enum: - - 301 - - 302 - type: integer - type: object - responseHeaderModifier: - description: |- - ResponseHeaderModifier defines a schema for a filter that modifies response - headers. - - - Support: Extended - properties: - add: - description: |- - Add adds the given header(s) (name, value) to the request - before the action. It appends to any existing values associated - with the header name. - - - Input: - GET /foo HTTP/1.1 - my-header: foo - - - Config: - add: - - name: "my-header" - value: "bar,baz" - - - Output: - GET /foo HTTP/1.1 - my-header: foo,bar,baz - items: - description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. - properties: - name: - description: |- - Name is the name of the HTTP Header to be matched. Name matching MUST be - case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). - - - If multiple entries specify equivalent header names, the first entry with - an equivalent name MUST be considered for a match. Subsequent entries - with an equivalent header name MUST be ignored. Due to the - case-insensitivity of header names, "foo" and "Foo" are considered - equivalent. - maxLength: 256 - minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ - type: string - value: - description: Value is the value of HTTP Header to be matched. - maxLength: 4096 - minLength: 1 - type: string - required: - - name - - value - type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - remove: - description: |- - Remove the given header(s) from the HTTP request before the action. The - value of Remove is a list of HTTP header names. Note that the header - names are case-insensitive (see - https://datatracker.ietf.org/doc/html/rfc2616#section-4.2). - - - Input: - GET /foo HTTP/1.1 - my-header1: foo - my-header2: bar - my-header3: baz - - - Config: - remove: ["my-header1", "my-header3"] - - - Output: - GET /foo HTTP/1.1 - my-header2: bar - items: - type: string - maxItems: 16 - type: array - x-kubernetes-list-type: set - set: - description: |- - Set overwrites the request with the given header (name, value) - before the action. - - - Input: - GET /foo HTTP/1.1 - my-header: foo - - - Config: - set: - - name: "my-header" - value: "bar" - - - Output: - GET /foo HTTP/1.1 - my-header: bar - items: - description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. - properties: - name: - description: |- - Name is the name of the HTTP Header to be matched. Name matching MUST be - case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). - - - If multiple entries specify equivalent header names, the first entry with - an equivalent name MUST be considered for a match. Subsequent entries - with an equivalent header name MUST be ignored. Due to the - case-insensitivity of header names, "foo" and "Foo" are considered - equivalent. - maxLength: 256 - minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ - type: string - value: - description: Value is the value of HTTP Header to be matched. - maxLength: 4096 - minLength: 1 - type: string - required: - - name - - value - type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - type: object - type: - description: |- - Type identifies the type of filter to apply. As with other API fields, - types are classified into three conformance levels: - - - - Core: Filter types and their corresponding configuration defined by - "Support: Core" in this package, e.g. "RequestHeaderModifier". All - implementations must support core filters. - - - - Extended: Filter types and their corresponding configuration defined by - "Support: Extended" in this package, e.g. "RequestMirror". Implementers - are encouraged to support extended filters. - - - - Implementation-specific: Filters that are defined and supported by - specific vendors. - In the future, filters showing convergence in behavior across multiple - implementations will be considered for inclusion in extended or core - conformance levels. Filter-specific configuration for such filters - is specified using the ExtensionRef field. `Type` should be set to - "ExtensionRef" for custom filters. - - - Implementers are encouraged to define custom implementation types to - extend the core API with implementation-specific behavior. - - - If a reference to a custom filter type cannot be resolved, the filter - MUST NOT be skipped. Instead, requests that would have been processed by - that filter MUST receive a HTTP error response. - - - Note that values may be added to this enum, implementations - must ensure that unknown values will not cause a crash. - - - Unknown values here must result in the implementation setting the - Accepted Condition for the Route to `status: False`, with a - Reason of `UnsupportedValue`. - enum: - - RequestHeaderModifier - - ResponseHeaderModifier - - RequestMirror - - RequestRedirect - - URLRewrite - - ExtensionRef - type: string - urlRewrite: - description: |- - URLRewrite defines a schema for a filter that modifies a request during forwarding. - - - Support: Extended - properties: - hostname: - description: |- - Hostname is the value to be used to replace the Host header value during - forwarding. - - - Support: Extended - maxLength: 253 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - path: - description: |- - Path defines a path rewrite. - - - Support: Extended - properties: - replaceFullPath: - description: |- - ReplaceFullPath specifies the value with which to replace the full path - of a request during a rewrite or redirect. - maxLength: 1024 - type: string - replacePrefixMatch: - description: |- - ReplacePrefixMatch specifies the value with which to replace the prefix - match of a request during a rewrite or redirect. For example, a request - to "/foo/bar" with a prefix match of "/foo" and a ReplacePrefixMatch - of "/xyz" would be modified to "/xyz/bar". - - - Note that this matches the behavior of the PathPrefix match type. This - matches full path elements. A path element refers to the list of labels - in the path split by the `/` separator. When specified, a trailing `/` is - ignored. For example, the paths `/abc`, `/abc/`, and `/abc/def` would all - match the prefix `/abc`, but the path `/abcd` would not. - - - ReplacePrefixMatch is only compatible with a `PathPrefix` HTTPRouteMatch. - Using any other HTTPRouteMatch type on the same HTTPRouteRule will result in - the implementation setting the Accepted Condition for the Route to `status: False`. - - - Request Path | Prefix Match | Replace Prefix | Modified Path - -------------|--------------|----------------|---------- - /foo/bar | /foo | /xyz | /xyz/bar - /foo/bar | /foo | /xyz/ | /xyz/bar - /foo/bar | /foo/ | /xyz | /xyz/bar - /foo/bar | /foo/ | /xyz/ | /xyz/bar - /foo | /foo | /xyz | /xyz - /foo/ | /foo | /xyz | /xyz/ - /foo/bar | /foo | | /bar - /foo/ | /foo | | / - /foo | /foo | | / - /foo/ | /foo | / | / - /foo | /foo | / | / - maxLength: 1024 - type: string - type: - description: |- - Type defines the type of path modifier. Additional types may be - added in a future release of the API. - - - Note that values may be added to this enum, implementations - must ensure that unknown values will not cause a crash. - - - Unknown values here must result in the implementation setting the - Accepted Condition for the Route to `status: False`, with a - Reason of `UnsupportedValue`. - enum: - - ReplaceFullPath - - ReplacePrefixMatch - type: string - required: - - type - type: object - type: object - required: - - type - type: object - maxItems: 16 - type: array - matches: - description: |- - Matches define conditions used for matching the rule against incoming - HTTP requests. Each match is independent, i.e. this rule will be matched - if **any** one of the matches is satisfied. - - - For example, take the following matches configuration: - - - ``` - matches: - - path: - value: "/foo" - headers: - - name: "version" - value: "v2" - - path: - value: "/v2/foo" - ``` - - - For a request to match against this rule, a request must satisfy - EITHER of the two conditions: - - - - path prefixed with `/foo` AND contains the header `version: v2` - - path prefix of `/v2/foo` - - - See the documentation for HTTPRouteMatch on how to specify multiple - match conditions that should be ANDed together. - - - If no matches are specified, the default is a prefix - path match on "/", which has the effect of matching every - HTTP request. - - - Proxy or Load Balancer routing configuration generated from HTTPRoutes - MUST prioritize matches based on the following criteria, continuing on - ties. Across all rules specified on applicable Routes, precedence must be - given to the match having: - - - * "Exact" path match. - * "Prefix" path match with largest number of characters. - * Method match. - * Largest number of header matches. - * Largest number of query param matches. - - - Note: The precedence of RegularExpression path matches are implementation-specific. - - - If ties still exist across multiple Routes, matching precedence MUST be - determined in order of the following criteria, continuing on ties: - - - * The oldest Route based on creation timestamp. - * The Route appearing first in alphabetical order by - "{namespace}/{name}". - - - If ties still exist within an HTTPRoute, matching precedence MUST be granted - to the FIRST matching rule (in list order) with a match meeting the above - criteria. - - - When no rules matching a request have been successfully attached to the - parent a request is coming from, a HTTP 404 status code MUST be returned. - items: - properties: - headers: - description: |- - Headers specifies HTTP request header matchers. Multiple match values are - ANDed together, meaning, a request must match all the specified headers - to select the route. - items: - description: |- - HTTPHeaderMatch describes how to select a HTTP route by matching HTTP request - headers. - properties: - name: - description: |- - Name is the name of the HTTP Header to be matched. Name matching MUST be - case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). - - - If multiple entries specify equivalent header names, only the first - entry with an equivalent name MUST be considered for a match. Subsequent - entries with an equivalent header name MUST be ignored. Due to the - case-insensitivity of header names, "foo" and "Foo" are considered - equivalent. - - - When a header is repeated in an HTTP request, it is - implementation-specific behavior as to how this is represented. - Generally, proxies should follow the guidance from the RFC: - https://www.rfc-editor.org/rfc/rfc7230.html#section-3.2.2 regarding - processing a repeated header, with special handling for "Set-Cookie". - maxLength: 256 - minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ - type: string - type: - default: Exact - description: |- - Type specifies how to match against the value of the header. - - - Support: Core (Exact) - - - Support: Implementation-specific (RegularExpression) - - - Since RegularExpression HeaderMatchType has implementation-specific - conformance, implementations can support POSIX, PCRE or any other dialects - of regular expressions. Please read the implementation's documentation to - determine the supported dialect. - enum: - - Exact - - RegularExpression - type: string - value: - description: Value is the value of HTTP Header to be matched. - maxLength: 4096 - minLength: 1 - type: string - required: - - name - - value - type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - path: - description: Path specifies a HTTP request path matcher. - properties: - type: - default: PathPrefix - description: |- - Type specifies how to match against the path Value. - - - Support: Core (Exact, PathPrefix) - - - Support: Implementation-specific (RegularExpression) - enum: - - Exact - - PathPrefix - - RegularExpression - type: string - value: - default: / - description: Value of the HTTP path to match against. - maxLength: 1024 - type: string - type: object - queryParams: - description: |- - QueryParams specifies HTTP query parameter matchers. Multiple match - values are ANDed together, meaning, a request must match all the - specified query parameters to select the route. - - - Support: Extended - items: - description: |- - HTTPQueryParamMatch describes how to select a HTTP route by matching HTTP - query parameters. - properties: - name: - description: |- - Name is the name of the HTTP query param to be matched. This must be an - exact string match. (See - https://tools.ietf.org/html/rfc7230#section-2.7.3). - - - If multiple entries specify equivalent query param names, only the first - entry with an equivalent name MUST be considered for a match. Subsequent - entries with an equivalent query param name MUST be ignored. - - - If a query param is repeated in an HTTP request, the behavior is - purposely left undefined, since different data planes have different - capabilities. However, it is *recommended* that implementations should - match against the first value of the param if the data plane supports it, - as this behavior is expected in other load balancing contexts outside of - the Gateway API. - - - Users SHOULD NOT route traffic based on repeated query params to guard - themselves against potential differences in the implementations. - maxLength: 256 - minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ - type: string - type: - default: Exact - description: |- - Type specifies how to match against the value of the query parameter. - - - Support: Extended (Exact) - - - Support: Implementation-specific (RegularExpression) - - - Since RegularExpression QueryParamMatchType has Implementation-specific - conformance, implementations can support POSIX, PCRE or any other - dialects of regular expressions. Please read the implementation's - documentation to determine the supported dialect. - enum: - - Exact - - RegularExpression - type: string - value: - description: Value is the value of HTTP query param to be matched. - maxLength: 1024 - minLength: 1 - type: string - required: - - name - - value - type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - type: object - maxItems: 8 - type: array - type: object - weight: - description: Weight indicate how many percentage of traffic the canary pods should receive - format: int32 - maximum: 100 - minimum: 0 - type: integer - type: object - type: object - required: - - targets - type: object - type: array - toleration: - description: Toleration is the toleration policy of the canary strategy - properties: - initialDelaySeconds: - description: Number of seconds after the toleration check has started before the task are initiated. - format: int32 - type: integer - taskFailureThreshold: - anyOf: - - type: integer - - type: string - description: |- - FailureThreshold indicates how many failed pods can be tolerated before marking the rollout task as success - If not set, the default value is 0, which means no failed pods can be tolerated - This is a task level threshold. - x-kubernetes-int-or-string: true - workloadTotalFailureThreshold: - anyOf: - - type: integer - - type: string - description: |- - WorkloadFailureThreshold indicates how many failed pods can be tolerated in all upgraded pods of one workload. - The default value is 0, which means no failed pods can be tolerated. - This is a workload level threshold. - x-kubernetes-int-or-string: true - type: object - type: object - canaryStrategy: - description: |- - CanaryStrategy defines the inline canary strategy. - This allows specifying canary deployment details directly in Rollout - without requiring a separate RolloutStrategy resource. - Mutually exclusive with StrategyRef. - properties: - podTemplateMetadataPatch: - description: PodTemplateMetadataPatch defines a patch for workload podTemplate metadata. - properties: - annotations: - additionalProperties: - type: string - description: Annotations are additional metadata that can be included. - type: object - labels: - additionalProperties: - type: string - description: Labels are additional metadata that can be included. - type: object - type: object - properties: - additionalProperties: - type: string - description: Properties contains additional information for step - type: object - targets: - description: desired target replicas - items: - properties: - cluster: - description: Cluster indicates the name of cluster - type: string - name: - description: Name is the resource name - type: string - replicaSlidingWindow: - anyOf: - - type: integer - - type: string - description: |- - ReplicaSlidingWindow used to control the number of pods that are allowed to be upgraded in - a sliding window for progressive rollout smoothly. - x-kubernetes-int-or-string: true - replicas: - anyOf: - - type: integer - - type: string - description: Replicas is the replicas of the rollout task, which represents the number of pods to be upgraded - x-kubernetes-int-or-string: true - required: - - name - - replicas - type: object - type: array - traffic: - description: traffic strategy - properties: - http: - properties: - filters: - description: |- - Filters define the filters that are applied to requests that match - this rule. - - - The effects of ordering of multiple behaviors are currently unspecified. - This can change in the future based on feedback during the alpha stage. - - - Conformance-levels at this level are defined based on the type of filter: - - - - ALL core filters MUST be supported by all implementations. - - Implementers are encouraged to support extended filters. - - Implementation-specific custom filters have no API guarantees across - implementations. - - - Specifying the same filter multiple times is not supported unless explicitly - indicated in the filter. - - - All filters are expected to be compatible with each other except for the - URLRewrite and RequestRedirect filters, which may not be combined. If an - implementation can not support other combinations of filters, they must clearly - document that limitation. In cases where incompatible or unsupported - filters are specified and cause the `Accepted` condition to be set to status - `False`, implementations may use the `IncompatibleFilters` reason to specify - this configuration error. - - - Support: Core - items: - description: |- - HTTPRouteFilter defines processing steps that must be completed during the - request or response lifecycle. HTTPRouteFilters are meant as an extension - point to express processing that may be done in Gateway implementations. Some - examples include request or response modification, implementing - authentication strategies, rate-limiting, and traffic shaping. API - guarantee/conformance is defined based on the type of the filter. - properties: - extensionRef: - description: |- - ExtensionRef is an optional, implementation-specific extension to the - "filter" behavior. For example, resource "myroutefilter" in group - "networking.example.net"). ExtensionRef MUST NOT be used for core and - extended filters. - - - This filter can be used multiple times within the same rule. - - - Support: Implementation-specific - properties: - group: - description: |- - Group is the group of the referent. For example, "gateway.networking.k8s.io". - When unspecified or empty string, core API group is inferred. - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - description: Kind is kind of the referent. For example "HTTPRoute" or "Service". - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - type: string - name: - description: Name is the name of the referent. - maxLength: 253 - minLength: 1 - type: string - required: - - group - - kind - - name - type: object - requestHeaderModifier: - description: |- - RequestHeaderModifier defines a schema for a filter that modifies request - headers. - - - Support: Core - properties: - add: - description: |- - Add adds the given header(s) (name, value) to the request - before the action. It appends to any existing values associated - with the header name. - - - Input: - GET /foo HTTP/1.1 - my-header: foo - - - Config: - add: - - name: "my-header" - value: "bar,baz" - - - Output: - GET /foo HTTP/1.1 - my-header: foo,bar,baz - items: - description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. - properties: - name: - description: |- - Name is the name of the HTTP Header to be matched. Name matching MUST be - case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). - - - If multiple entries specify equivalent header names, the first entry with - an equivalent name MUST be considered for a match. Subsequent entries - with an equivalent header name MUST be ignored. Due to the - case-insensitivity of header names, "foo" and "Foo" are considered - equivalent. - maxLength: 256 - minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ - type: string - value: - description: Value is the value of HTTP Header to be matched. - maxLength: 4096 - minLength: 1 - type: string - required: - - name - - value - type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - remove: - description: |- - Remove the given header(s) from the HTTP request before the action. The - value of Remove is a list of HTTP header names. Note that the header - names are case-insensitive (see - https://datatracker.ietf.org/doc/html/rfc2616#section-4.2). - - - Input: - GET /foo HTTP/1.1 - my-header1: foo - my-header2: bar - my-header3: baz - - - Config: - remove: ["my-header1", "my-header3"] - - - Output: - GET /foo HTTP/1.1 - my-header2: bar - items: - type: string - maxItems: 16 - type: array - x-kubernetes-list-type: set - set: - description: |- - Set overwrites the request with the given header (name, value) - before the action. - - - Input: - GET /foo HTTP/1.1 - my-header: foo - - - Config: - set: - - name: "my-header" - value: "bar" - - - Output: - GET /foo HTTP/1.1 - my-header: bar - items: - description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. - properties: - name: - description: |- - Name is the name of the HTTP Header to be matched. Name matching MUST be - case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). - - - If multiple entries specify equivalent header names, the first entry with - an equivalent name MUST be considered for a match. Subsequent entries - with an equivalent header name MUST be ignored. Due to the - case-insensitivity of header names, "foo" and "Foo" are considered - equivalent. - maxLength: 256 - minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ - type: string - value: - description: Value is the value of HTTP Header to be matched. - maxLength: 4096 - minLength: 1 - type: string - required: - - name - - value - type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - type: object - requestMirror: - description: |- - RequestMirror defines a schema for a filter that mirrors requests. - Requests are sent to the specified destination, but responses from - that destination are ignored. - - - This filter can be used multiple times within the same rule. Note that - not all implementations will be able to support mirroring to multiple - backends. - - - Support: Extended - - - - properties: - backendRef: - description: |- - BackendRef references a resource where mirrored requests are sent. - - - Mirrored requests must be sent only to a single destination endpoint - within this BackendRef, irrespective of how many endpoints are present - within this BackendRef. - - - If the referent cannot be found, this BackendRef is invalid and must be - dropped from the Gateway. The controller must ensure the "ResolvedRefs" - condition on the Route status is set to `status: False` and not configure - this backend in the underlying implementation. - - - If there is a cross-namespace reference to an *existing* object - that is not allowed by a ReferenceGrant, the controller must ensure the - "ResolvedRefs" condition on the Route is set to `status: False`, - with the "RefNotPermitted" reason and not configure this backend in the - underlying implementation. - - - In either error case, the Message of the `ResolvedRefs` Condition - should be used to provide more detail about the problem. - - - Support: Extended for Kubernetes Service - - - Support: Implementation-specific for any other resource - properties: - group: - default: "" - description: |- - Group is the group of the referent. For example, "gateway.networking.k8s.io". - When unspecified or empty string, core API group is inferred. - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - default: Service - description: |- - Kind is the Kubernetes resource kind of the referent. For example - "Service". - - - Defaults to "Service" when not specified. - - - ExternalName services can refer to CNAME DNS records that may live - outside of the cluster and as such are difficult to reason about in - terms of conformance. They also may not be safe to forward to (see - CVE-2021-25740 for more information). Implementations SHOULD NOT - support ExternalName Services. - - - Support: Core (Services with a type other than ExternalName) - - - Support: Implementation-specific (Services with type ExternalName) - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - type: string - name: - description: Name is the name of the referent. - maxLength: 253 - minLength: 1 - type: string - namespace: - description: |- - Namespace is the namespace of the backend. When unspecified, the local - namespace is inferred. - - - Note that when a namespace different than the local namespace is specified, - a ReferenceGrant object is required in the referent namespace to allow that - namespace's owner to accept the reference. See the ReferenceGrant - documentation for details. - - - Support: Core - maxLength: 63 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ - type: string - port: - description: |- - Port specifies the destination port number to use for this resource. - Port is required when the referent is a Kubernetes Service. In this - case, the port number is the service port number, not the target port. - For other resources, destination port might be derived from the referent - resource or this field. - format: int32 - maximum: 65535 - minimum: 1 - type: integer - required: - - name - type: object - fraction: - description: |- - Fraction represents the fraction of requests that should be - mirrored to BackendRef. - - - Only one of Fraction or Percent may be specified. If neither field - is specified, 100% of requests will be mirrored. - - - - properties: - denominator: - default: 100 - format: int32 - minimum: 1 - type: integer - numerator: - format: int32 - minimum: 0 - type: integer - required: - - numerator - type: object - percent: - description: |- - Percent represents the percentage of requests that should be - mirrored to BackendRef. Its minimum value is 0 (indicating 0% of - requests) and its maximum value is 100 (indicating 100% of requests). - - - Only one of Fraction or Percent may be specified. If neither field - is specified, 100% of requests will be mirrored. - - - - format: int32 - maximum: 100 - minimum: 0 - type: integer - required: - - backendRef - type: object - requestRedirect: - description: |- - RequestRedirect defines a schema for a filter that responds to the - request with an HTTP redirection. - - - Support: Core - properties: - hostname: - description: |- - Hostname is the hostname to be used in the value of the `Location` - header in the response. - When empty, the hostname in the `Host` header of the request is used. - - - Support: Core - maxLength: 253 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - path: - description: |- - Path defines parameters used to modify the path of the incoming request. - The modified path is then used to construct the `Location` header. When - empty, the request path is used as-is. - - - Support: Extended - properties: - replaceFullPath: - description: |- - ReplaceFullPath specifies the value with which to replace the full path - of a request during a rewrite or redirect. - maxLength: 1024 - type: string - replacePrefixMatch: - description: |- - ReplacePrefixMatch specifies the value with which to replace the prefix - match of a request during a rewrite or redirect. For example, a request - to "/foo/bar" with a prefix match of "/foo" and a ReplacePrefixMatch - of "/xyz" would be modified to "/xyz/bar". - - - Note that this matches the behavior of the PathPrefix match type. This - matches full path elements. A path element refers to the list of labels - in the path split by the `/` separator. When specified, a trailing `/` is - ignored. For example, the paths `/abc`, `/abc/`, and `/abc/def` would all - match the prefix `/abc`, but the path `/abcd` would not. - - - ReplacePrefixMatch is only compatible with a `PathPrefix` HTTPRouteMatch. - Using any other HTTPRouteMatch type on the same HTTPRouteRule will result in - the implementation setting the Accepted Condition for the Route to `status: False`. - - - Request Path | Prefix Match | Replace Prefix | Modified Path - -------------|--------------|----------------|---------- - /foo/bar | /foo | /xyz | /xyz/bar - /foo/bar | /foo | /xyz/ | /xyz/bar - /foo/bar | /foo/ | /xyz | /xyz/bar - /foo/bar | /foo/ | /xyz/ | /xyz/bar - /foo | /foo | /xyz | /xyz - /foo/ | /foo | /xyz | /xyz/ - /foo/bar | /foo | | /bar - /foo/ | /foo | | / - /foo | /foo | | / - /foo/ | /foo | / | / - /foo | /foo | / | / - maxLength: 1024 - type: string - type: - description: |- - Type defines the type of path modifier. Additional types may be - added in a future release of the API. - - - Note that values may be added to this enum, implementations - must ensure that unknown values will not cause a crash. - - - Unknown values here must result in the implementation setting the - Accepted Condition for the Route to `status: False`, with a - Reason of `UnsupportedValue`. - enum: - - ReplaceFullPath - - ReplacePrefixMatch - type: string - required: - - type - type: object - port: - description: |- - Port is the port to be used in the value of the `Location` - header in the response. - - - If no port is specified, the redirect port MUST be derived using the - following rules: - - - * If redirect scheme is not-empty, the redirect port MUST be the well-known - port associated with the redirect scheme. Specifically "http" to port 80 - and "https" to port 443. If the redirect scheme does not have a - well-known port, the listener port of the Gateway SHOULD be used. - * If redirect scheme is empty, the redirect port MUST be the Gateway - Listener port. - - - Implementations SHOULD NOT add the port number in the 'Location' - header in the following cases: - - - * A Location header that will use HTTP (whether that is determined via - the Listener protocol or the Scheme field) _and_ use port 80. - * A Location header that will use HTTPS (whether that is determined via - the Listener protocol or the Scheme field) _and_ use port 443. - - - Support: Extended - format: int32 - maximum: 65535 - minimum: 1 - type: integer - scheme: - description: |- - Scheme is the scheme to be used in the value of the `Location` header in - the response. When empty, the scheme of the request is used. - - - Scheme redirects can affect the port of the redirect, for more information, - refer to the documentation for the port field of this filter. - - - Note that values may be added to this enum, implementations - must ensure that unknown values will not cause a crash. - - - Unknown values here must result in the implementation setting the - Accepted Condition for the Route to `status: False`, with a - Reason of `UnsupportedValue`. - - - Support: Extended - enum: - - http - - https - type: string - statusCode: - default: 302 - description: |- - StatusCode is the HTTP status code to be used in response. - - - Note that values may be added to this enum, implementations - must ensure that unknown values will not cause a crash. - - - Unknown values here must result in the implementation setting the - Accepted Condition for the Route to `status: False`, with a - Reason of `UnsupportedValue`. - - - Support: Core - enum: - - 301 - - 302 - type: integer - type: object - responseHeaderModifier: - description: |- - ResponseHeaderModifier defines a schema for a filter that modifies response - headers. - - - Support: Extended - properties: - add: - description: |- - Add adds the given header(s) (name, value) to the request - before the action. It appends to any existing values associated - with the header name. - - - Input: - GET /foo HTTP/1.1 - my-header: foo - - - Config: - add: - - name: "my-header" - value: "bar,baz" - - - Output: - GET /foo HTTP/1.1 - my-header: foo,bar,baz - items: - description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. - properties: - name: - description: |- - Name is the name of the HTTP Header to be matched. Name matching MUST be - case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). - - - If multiple entries specify equivalent header names, the first entry with - an equivalent name MUST be considered for a match. Subsequent entries - with an equivalent header name MUST be ignored. Due to the - case-insensitivity of header names, "foo" and "Foo" are considered - equivalent. - maxLength: 256 - minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ - type: string - value: - description: Value is the value of HTTP Header to be matched. - maxLength: 4096 - minLength: 1 - type: string - required: - - name - - value - type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - remove: - description: |- - Remove the given header(s) from the HTTP request before the action. The - value of Remove is a list of HTTP header names. Note that the header - names are case-insensitive (see - https://datatracker.ietf.org/doc/html/rfc2616#section-4.2). - - - Input: - GET /foo HTTP/1.1 - my-header1: foo - my-header2: bar - my-header3: baz - - - Config: - remove: ["my-header1", "my-header3"] - - - Output: - GET /foo HTTP/1.1 - my-header2: bar - items: - type: string - maxItems: 16 - type: array - x-kubernetes-list-type: set - set: - description: |- - Set overwrites the request with the given header (name, value) - before the action. - - - Input: - GET /foo HTTP/1.1 - my-header: foo - - - Config: - set: - - name: "my-header" - value: "bar" - - - Output: - GET /foo HTTP/1.1 - my-header: bar - items: - description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. - properties: - name: - description: |- - Name is the name of the HTTP Header to be matched. Name matching MUST be - case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). - - - If multiple entries specify equivalent header names, the first entry with - an equivalent name MUST be considered for a match. Subsequent entries - with an equivalent header name MUST be ignored. Due to the - case-insensitivity of header names, "foo" and "Foo" are considered - equivalent. - maxLength: 256 - minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ - type: string - value: - description: Value is the value of HTTP Header to be matched. - maxLength: 4096 - minLength: 1 - type: string - required: - - name - - value - type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - type: object - type: - description: |- - Type identifies the type of filter to apply. As with other API fields, - types are classified into three conformance levels: - - - - Core: Filter types and their corresponding configuration defined by - "Support: Core" in this package, e.g. "RequestHeaderModifier". All - implementations must support core filters. - - - - Extended: Filter types and their corresponding configuration defined by - "Support: Extended" in this package, e.g. "RequestMirror". Implementers - are encouraged to support extended filters. - - - - Implementation-specific: Filters that are defined and supported by - specific vendors. - In the future, filters showing convergence in behavior across multiple - implementations will be considered for inclusion in extended or core - conformance levels. Filter-specific configuration for such filters - is specified using the ExtensionRef field. `Type` should be set to - "ExtensionRef" for custom filters. - - - Implementers are encouraged to define custom implementation types to - extend the core API with implementation-specific behavior. - - - If a reference to a custom filter type cannot be resolved, the filter - MUST NOT be skipped. Instead, requests that would have been processed by - that filter MUST receive a HTTP error response. - - - Note that values may be added to this enum, implementations - must ensure that unknown values will not cause a crash. - - - Unknown values here must result in the implementation setting the - Accepted Condition for the Route to `status: False`, with a - Reason of `UnsupportedValue`. - enum: - - RequestHeaderModifier - - ResponseHeaderModifier - - RequestMirror - - RequestRedirect - - URLRewrite - - ExtensionRef - type: string - urlRewrite: - description: |- - URLRewrite defines a schema for a filter that modifies a request during forwarding. - - - Support: Extended - properties: - hostname: - description: |- - Hostname is the value to be used to replace the Host header value during - forwarding. - - - Support: Extended - maxLength: 253 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - path: - description: |- - Path defines a path rewrite. - - - Support: Extended - properties: - replaceFullPath: - description: |- - ReplaceFullPath specifies the value with which to replace the full path - of a request during a rewrite or redirect. - maxLength: 1024 - type: string - replacePrefixMatch: - description: |- - ReplacePrefixMatch specifies the value with which to replace the prefix - match of a request during a rewrite or redirect. For example, a request - to "/foo/bar" with a prefix match of "/foo" and a ReplacePrefixMatch - of "/xyz" would be modified to "/xyz/bar". - - - Note that this matches the behavior of the PathPrefix match type. This - matches full path elements. A path element refers to the list of labels - in the path split by the `/` separator. When specified, a trailing `/` is - ignored. For example, the paths `/abc`, `/abc/`, and `/abc/def` would all - match the prefix `/abc`, but the path `/abcd` would not. - - - ReplacePrefixMatch is only compatible with a `PathPrefix` HTTPRouteMatch. - Using any other HTTPRouteMatch type on the same HTTPRouteRule will result in - the implementation setting the Accepted Condition for the Route to `status: False`. - - - Request Path | Prefix Match | Replace Prefix | Modified Path - -------------|--------------|----------------|---------- - /foo/bar | /foo | /xyz | /xyz/bar - /foo/bar | /foo | /xyz/ | /xyz/bar - /foo/bar | /foo/ | /xyz | /xyz/bar - /foo/bar | /foo/ | /xyz/ | /xyz/bar - /foo | /foo | /xyz | /xyz - /foo/ | /foo | /xyz | /xyz/ - /foo/bar | /foo | | /bar - /foo/ | /foo | | / - /foo | /foo | | / - /foo/ | /foo | / | / - /foo | /foo | / | / - maxLength: 1024 - type: string - type: - description: |- - Type defines the type of path modifier. Additional types may be - added in a future release of the API. - - - Note that values may be added to this enum, implementations - must ensure that unknown values will not cause a crash. - - - Unknown values here must result in the implementation setting the - Accepted Condition for the Route to `status: False`, with a - Reason of `UnsupportedValue`. - enum: - - ReplaceFullPath - - ReplacePrefixMatch - type: string - required: - - type - type: object - type: object - required: - - type - type: object - maxItems: 16 - type: array - matches: - description: |- - Matches define conditions used for matching the rule against incoming - HTTP requests. Each match is independent, i.e. this rule will be matched - if **any** one of the matches is satisfied. - - - For example, take the following matches configuration: - - - ``` - matches: - - path: - value: "/foo" - headers: - - name: "version" - value: "v2" - - path: - value: "/v2/foo" - ``` - - - For a request to match against this rule, a request must satisfy - EITHER of the two conditions: - - - - path prefixed with `/foo` AND contains the header `version: v2` - - path prefix of `/v2/foo` - - - See the documentation for HTTPRouteMatch on how to specify multiple - match conditions that should be ANDed together. - - - If no matches are specified, the default is a prefix - path match on "/", which has the effect of matching every - HTTP request. - - - Proxy or Load Balancer routing configuration generated from HTTPRoutes - MUST prioritize matches based on the following criteria, continuing on - ties. Across all rules specified on applicable Routes, precedence must be - given to the match having: - - - * "Exact" path match. - * "Prefix" path match with largest number of characters. - * Method match. - * Largest number of header matches. - * Largest number of query param matches. - - - Note: The precedence of RegularExpression path matches are implementation-specific. - - - If ties still exist across multiple Routes, matching precedence MUST be - determined in order of the following criteria, continuing on ties: - - - * The oldest Route based on creation timestamp. - * The Route appearing first in alphabetical order by - "{namespace}/{name}". - - - If ties still exist within an HTTPRoute, matching precedence MUST be granted - to the FIRST matching rule (in list order) with a match meeting the above - criteria. - - - When no rules matching a request have been successfully attached to the - parent a request is coming from, a HTTP 404 status code MUST be returned. - items: - properties: - headers: - description: |- - Headers specifies HTTP request header matchers. Multiple match values are - ANDed together, meaning, a request must match all the specified headers - to select the route. - items: - description: |- - HTTPHeaderMatch describes how to select a HTTP route by matching HTTP request - headers. - properties: - name: - description: |- - Name is the name of the HTTP Header to be matched. Name matching MUST be - case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). - - - If multiple entries specify equivalent header names, only the first - entry with an equivalent name MUST be considered for a match. Subsequent - entries with an equivalent header name MUST be ignored. Due to the - case-insensitivity of header names, "foo" and "Foo" are considered - equivalent. - - - When a header is repeated in an HTTP request, it is - implementation-specific behavior as to how this is represented. - Generally, proxies should follow the guidance from the RFC: - https://www.rfc-editor.org/rfc/rfc7230.html#section-3.2.2 regarding - processing a repeated header, with special handling for "Set-Cookie". - maxLength: 256 - minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ - type: string - type: - default: Exact - description: |- - Type specifies how to match against the value of the header. - - - Support: Core (Exact) - - - Support: Implementation-specific (RegularExpression) - - - Since RegularExpression HeaderMatchType has implementation-specific - conformance, implementations can support POSIX, PCRE or any other dialects - of regular expressions. Please read the implementation's documentation to - determine the supported dialect. - enum: - - Exact - - RegularExpression - type: string - value: - description: Value is the value of HTTP Header to be matched. - maxLength: 4096 - minLength: 1 - type: string - required: - - name - - value - type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - path: - description: Path specifies a HTTP request path matcher. - properties: - type: - default: PathPrefix - description: |- - Type specifies how to match against the path Value. - - - Support: Core (Exact, PathPrefix) - - - Support: Implementation-specific (RegularExpression) - enum: - - Exact - - PathPrefix - - RegularExpression - type: string - value: - default: / - description: Value of the HTTP path to match against. - maxLength: 1024 - type: string - type: object - queryParams: - description: |- - QueryParams specifies HTTP query parameter matchers. Multiple match - values are ANDed together, meaning, a request must match all the - specified query parameters to select the route. - - - Support: Extended - items: - description: |- - HTTPQueryParamMatch describes how to select a HTTP route by matching HTTP - query parameters. - properties: - name: - description: |- - Name is the name of the HTTP query param to be matched. This must be an - exact string match. (See - https://tools.ietf.org/html/rfc7230#section-2.7.3). - - - If multiple entries specify equivalent query param names, only the first - entry with an equivalent name MUST be considered for a match. Subsequent - entries with an equivalent query param name MUST be ignored. - - - If a query param is repeated in an HTTP request, the behavior is - purposely left undefined, since different data planes have different - capabilities. However, it is *recommended* that implementations should - match against the first value of the param if the data plane supports it, - as this behavior is expected in other load balancing contexts outside of - the Gateway API. - - - Users SHOULD NOT route traffic based on repeated query params to guard - themselves against potential differences in the implementations. - maxLength: 256 - minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ - type: string - type: - default: Exact - description: |- - Type specifies how to match against the value of the query parameter. - - - Support: Extended (Exact) - - - Support: Implementation-specific (RegularExpression) - - - Since RegularExpression QueryParamMatchType has Implementation-specific - conformance, implementations can support POSIX, PCRE or any other - dialects of regular expressions. Please read the implementation's - documentation to determine the supported dialect. - enum: - - Exact - - RegularExpression - type: string - value: - description: Value is the value of HTTP query param to be matched. - maxLength: 1024 - minLength: 1 - type: string - required: - - name - - value - type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - type: object - maxItems: 8 - type: array - stableTraffic: - description: StableTraffic indicate the base traffic rule - properties: - filters: - description: |- - Filters define the filters that are applied to requests that match - this rule. - - - The effects of ordering of multiple behaviors are currently unspecified. - This can change in the future based on feedback during the alpha stage. - - - Conformance-levels at this level are defined based on the type of filter: - - - - ALL core filters MUST be supported by all implementations. - - Implementers are encouraged to support extended filters. - - Implementation-specific custom filters have no API guarantees across - implementations. - - - Specifying the same filter multiple times is not supported unless explicitly - indicated in the filter. - - - All filters are expected to be compatible with each other except for the - URLRewrite and RequestRedirect filters, which may not be combined. If an - implementation can not support other combinations of filters, they must clearly - document that limitation. In cases where incompatible or unsupported - filters are specified and cause the `Accepted` condition to be set to status - `False`, implementations may use the `IncompatibleFilters` reason to specify - this configuration error. - - - Support: Core - items: - description: |- - HTTPRouteFilter defines processing steps that must be completed during the - request or response lifecycle. HTTPRouteFilters are meant as an extension - point to express processing that may be done in Gateway implementations. Some - examples include request or response modification, implementing - authentication strategies, rate-limiting, and traffic shaping. API - guarantee/conformance is defined based on the type of the filter. - properties: - extensionRef: - description: |- - ExtensionRef is an optional, implementation-specific extension to the - "filter" behavior. For example, resource "myroutefilter" in group - "networking.example.net"). ExtensionRef MUST NOT be used for core and - extended filters. - - - This filter can be used multiple times within the same rule. - - - Support: Implementation-specific - properties: - group: - description: |- - Group is the group of the referent. For example, "gateway.networking.k8s.io". - When unspecified or empty string, core API group is inferred. - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - description: Kind is kind of the referent. For example "HTTPRoute" or "Service". - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - type: string - name: - description: Name is the name of the referent. - maxLength: 253 - minLength: 1 - type: string - required: - - group - - kind - - name - type: object - requestHeaderModifier: - description: |- - RequestHeaderModifier defines a schema for a filter that modifies request - headers. - - - Support: Core - properties: - add: - description: |- - Add adds the given header(s) (name, value) to the request - before the action. It appends to any existing values associated - with the header name. - - - Input: - GET /foo HTTP/1.1 - my-header: foo - - - Config: - add: - - name: "my-header" - value: "bar,baz" - - - Output: - GET /foo HTTP/1.1 - my-header: foo,bar,baz - items: - description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. - properties: - name: - description: |- - Name is the name of the HTTP Header to be matched. Name matching MUST be - case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). - - - If multiple entries specify equivalent header names, the first entry with - an equivalent name MUST be considered for a match. Subsequent entries - with an equivalent header name MUST be ignored. Due to the - case-insensitivity of header names, "foo" and "Foo" are considered - equivalent. - maxLength: 256 - minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ - type: string - value: - description: Value is the value of HTTP Header to be matched. - maxLength: 4096 - minLength: 1 - type: string - required: - - name - - value - type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - remove: - description: |- - Remove the given header(s) from the HTTP request before the action. The - value of Remove is a list of HTTP header names. Note that the header - names are case-insensitive (see - https://datatracker.ietf.org/doc/html/rfc2616#section-4.2). - - - Input: - GET /foo HTTP/1.1 - my-header1: foo - my-header2: bar - my-header3: baz - - - Config: - remove: ["my-header1", "my-header3"] - - - Output: - GET /foo HTTP/1.1 - my-header2: bar - items: - type: string - maxItems: 16 - type: array - x-kubernetes-list-type: set - set: - description: |- - Set overwrites the request with the given header (name, value) - before the action. - - - Input: - GET /foo HTTP/1.1 - my-header: foo - - - Config: - set: - - name: "my-header" - value: "bar" - - - Output: - GET /foo HTTP/1.1 - my-header: bar - items: - description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. - properties: - name: - description: |- - Name is the name of the HTTP Header to be matched. Name matching MUST be - case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). - - - If multiple entries specify equivalent header names, the first entry with - an equivalent name MUST be considered for a match. Subsequent entries - with an equivalent header name MUST be ignored. Due to the - case-insensitivity of header names, "foo" and "Foo" are considered - equivalent. - maxLength: 256 - minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ - type: string - value: - description: Value is the value of HTTP Header to be matched. - maxLength: 4096 - minLength: 1 - type: string - required: - - name - - value - type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - type: object - requestMirror: - description: |- - RequestMirror defines a schema for a filter that mirrors requests. - Requests are sent to the specified destination, but responses from - that destination are ignored. - - - This filter can be used multiple times within the same rule. Note that - not all implementations will be able to support mirroring to multiple - backends. - - - Support: Extended - - - - properties: - backendRef: - description: |- - BackendRef references a resource where mirrored requests are sent. - - - Mirrored requests must be sent only to a single destination endpoint - within this BackendRef, irrespective of how many endpoints are present - within this BackendRef. - - - If the referent cannot be found, this BackendRef is invalid and must be - dropped from the Gateway. The controller must ensure the "ResolvedRefs" - condition on the Route status is set to `status: False` and not configure - this backend in the underlying implementation. - - - If there is a cross-namespace reference to an *existing* object - that is not allowed by a ReferenceGrant, the controller must ensure the - "ResolvedRefs" condition on the Route is set to `status: False`, - with the "RefNotPermitted" reason and not configure this backend in the - underlying implementation. - - - In either error case, the Message of the `ResolvedRefs` Condition - should be used to provide more detail about the problem. - - - Support: Extended for Kubernetes Service - - - Support: Implementation-specific for any other resource - properties: - group: - default: "" - description: |- - Group is the group of the referent. For example, "gateway.networking.k8s.io". - When unspecified or empty string, core API group is inferred. - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - default: Service - description: |- - Kind is the Kubernetes resource kind of the referent. For example - "Service". - - - Defaults to "Service" when not specified. - - - ExternalName services can refer to CNAME DNS records that may live - outside of the cluster and as such are difficult to reason about in - terms of conformance. They also may not be safe to forward to (see - CVE-2021-25740 for more information). Implementations SHOULD NOT - support ExternalName Services. - - - Support: Core (Services with a type other than ExternalName) - - - Support: Implementation-specific (Services with type ExternalName) - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - type: string - name: - description: Name is the name of the referent. - maxLength: 253 - minLength: 1 - type: string - namespace: - description: |- - Namespace is the namespace of the backend. When unspecified, the local - namespace is inferred. - - - Note that when a namespace different than the local namespace is specified, - a ReferenceGrant object is required in the referent namespace to allow that - namespace's owner to accept the reference. See the ReferenceGrant - documentation for details. - - - Support: Core - maxLength: 63 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ - type: string - port: - description: |- - Port specifies the destination port number to use for this resource. - Port is required when the referent is a Kubernetes Service. In this - case, the port number is the service port number, not the target port. - For other resources, destination port might be derived from the referent - resource or this field. - format: int32 - maximum: 65535 - minimum: 1 - type: integer - required: - - name - type: object - fraction: - description: |- - Fraction represents the fraction of requests that should be - mirrored to BackendRef. - - - Only one of Fraction or Percent may be specified. If neither field - is specified, 100% of requests will be mirrored. - - - - properties: - denominator: - default: 100 - format: int32 - minimum: 1 - type: integer - numerator: - format: int32 - minimum: 0 - type: integer - required: - - numerator - type: object - percent: - description: |- - Percent represents the percentage of requests that should be - mirrored to BackendRef. Its minimum value is 0 (indicating 0% of - requests) and its maximum value is 100 (indicating 100% of requests). - - - Only one of Fraction or Percent may be specified. If neither field - is specified, 100% of requests will be mirrored. - - - - format: int32 - maximum: 100 - minimum: 0 - type: integer - required: - - backendRef - type: object - requestRedirect: - description: |- - RequestRedirect defines a schema for a filter that responds to the - request with an HTTP redirection. - - - Support: Core - properties: - hostname: - description: |- - Hostname is the hostname to be used in the value of the `Location` - header in the response. - When empty, the hostname in the `Host` header of the request is used. - - - Support: Core - maxLength: 253 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - path: - description: |- - Path defines parameters used to modify the path of the incoming request. - The modified path is then used to construct the `Location` header. When - empty, the request path is used as-is. - - - Support: Extended - properties: - replaceFullPath: - description: |- - ReplaceFullPath specifies the value with which to replace the full path - of a request during a rewrite or redirect. - maxLength: 1024 - type: string - replacePrefixMatch: - description: |- - ReplacePrefixMatch specifies the value with which to replace the prefix - match of a request during a rewrite or redirect. For example, a request - to "/foo/bar" with a prefix match of "/foo" and a ReplacePrefixMatch - of "/xyz" would be modified to "/xyz/bar". - - - Note that this matches the behavior of the PathPrefix match type. This - matches full path elements. A path element refers to the list of labels - in the path split by the `/` separator. When specified, a trailing `/` is - ignored. For example, the paths `/abc`, `/abc/`, and `/abc/def` would all - match the prefix `/abc`, but the path `/abcd` would not. - - - ReplacePrefixMatch is only compatible with a `PathPrefix` HTTPRouteMatch. - Using any other HTTPRouteMatch type on the same HTTPRouteRule will result in - the implementation setting the Accepted Condition for the Route to `status: False`. - - - Request Path | Prefix Match | Replace Prefix | Modified Path - -------------|--------------|----------------|---------- - /foo/bar | /foo | /xyz | /xyz/bar - /foo/bar | /foo | /xyz/ | /xyz/bar - /foo/bar | /foo/ | /xyz | /xyz/bar - /foo/bar | /foo/ | /xyz/ | /xyz/bar - /foo | /foo | /xyz | /xyz - /foo/ | /foo | /xyz | /xyz/ - /foo/bar | /foo | | /bar - /foo/ | /foo | | / - /foo | /foo | | / - /foo/ | /foo | / | / - /foo | /foo | / | / - maxLength: 1024 - type: string - type: - description: |- - Type defines the type of path modifier. Additional types may be - added in a future release of the API. - - - Note that values may be added to this enum, implementations - must ensure that unknown values will not cause a crash. - - - Unknown values here must result in the implementation setting the - Accepted Condition for the Route to `status: False`, with a - Reason of `UnsupportedValue`. - enum: - - ReplaceFullPath - - ReplacePrefixMatch - type: string - required: - - type - type: object - port: - description: |- - Port is the port to be used in the value of the `Location` - header in the response. - - - If no port is specified, the redirect port MUST be derived using the - following rules: - - - * If redirect scheme is not-empty, the redirect port MUST be the well-known - port associated with the redirect scheme. Specifically "http" to port 80 - and "https" to port 443. If the redirect scheme does not have a - well-known port, the listener port of the Gateway SHOULD be used. - * If redirect scheme is empty, the redirect port MUST be the Gateway - Listener port. - - - Implementations SHOULD NOT add the port number in the 'Location' - header in the following cases: - - - * A Location header that will use HTTP (whether that is determined via - the Listener protocol or the Scheme field) _and_ use port 80. - * A Location header that will use HTTPS (whether that is determined via - the Listener protocol or the Scheme field) _and_ use port 443. - - - Support: Extended - format: int32 - maximum: 65535 - minimum: 1 - type: integer - scheme: - description: |- - Scheme is the scheme to be used in the value of the `Location` header in - the response. When empty, the scheme of the request is used. - - - Scheme redirects can affect the port of the redirect, for more information, - refer to the documentation for the port field of this filter. - - - Note that values may be added to this enum, implementations - must ensure that unknown values will not cause a crash. - - - Unknown values here must result in the implementation setting the - Accepted Condition for the Route to `status: False`, with a - Reason of `UnsupportedValue`. - - - Support: Extended - enum: - - http - - https - type: string - statusCode: - default: 302 - description: |- - StatusCode is the HTTP status code to be used in response. - - - Note that values may be added to this enum, implementations - must ensure that unknown values will not cause a crash. - - - Unknown values here must result in the implementation setting the - Accepted Condition for the Route to `status: False`, with a - Reason of `UnsupportedValue`. - - - Support: Core - enum: - - 301 - - 302 - type: integer - type: object - responseHeaderModifier: - description: |- - ResponseHeaderModifier defines a schema for a filter that modifies response - headers. - - - Support: Extended - properties: - add: - description: |- - Add adds the given header(s) (name, value) to the request - before the action. It appends to any existing values associated - with the header name. - - - Input: - GET /foo HTTP/1.1 - my-header: foo - - - Config: - add: - - name: "my-header" - value: "bar,baz" - - - Output: - GET /foo HTTP/1.1 - my-header: foo,bar,baz - items: - description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. - properties: - name: - description: |- - Name is the name of the HTTP Header to be matched. Name matching MUST be - case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). - - - If multiple entries specify equivalent header names, the first entry with - an equivalent name MUST be considered for a match. Subsequent entries - with an equivalent header name MUST be ignored. Due to the - case-insensitivity of header names, "foo" and "Foo" are considered - equivalent. - maxLength: 256 - minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ - type: string - value: - description: Value is the value of HTTP Header to be matched. - maxLength: 4096 - minLength: 1 - type: string - required: - - name - - value - type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - remove: - description: |- - Remove the given header(s) from the HTTP request before the action. The - value of Remove is a list of HTTP header names. Note that the header - names are case-insensitive (see - https://datatracker.ietf.org/doc/html/rfc2616#section-4.2). - - - Input: - GET /foo HTTP/1.1 - my-header1: foo - my-header2: bar - my-header3: baz - - - Config: - remove: ["my-header1", "my-header3"] - - - Output: - GET /foo HTTP/1.1 - my-header2: bar - items: - type: string - maxItems: 16 - type: array - x-kubernetes-list-type: set - set: - description: |- - Set overwrites the request with the given header (name, value) - before the action. - - - Input: - GET /foo HTTP/1.1 - my-header: foo - - - Config: - set: - - name: "my-header" - value: "bar" - - - Output: - GET /foo HTTP/1.1 - my-header: bar - items: - description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. - properties: - name: - description: |- - Name is the name of the HTTP Header to be matched. Name matching MUST be - case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). - - - If multiple entries specify equivalent header names, the first entry with - an equivalent name MUST be considered for a match. Subsequent entries - with an equivalent header name MUST be ignored. Due to the - case-insensitivity of header names, "foo" and "Foo" are considered - equivalent. - maxLength: 256 - minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ - type: string - value: - description: Value is the value of HTTP Header to be matched. - maxLength: 4096 - minLength: 1 - type: string - required: - - name - - value - type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - type: object - type: - description: |- - Type identifies the type of filter to apply. As with other API fields, - types are classified into three conformance levels: - - - - Core: Filter types and their corresponding configuration defined by - "Support: Core" in this package, e.g. "RequestHeaderModifier". All - implementations must support core filters. - - - - Extended: Filter types and their corresponding configuration defined by - "Support: Extended" in this package, e.g. "RequestMirror". Implementers - are encouraged to support extended filters. - - - - Implementation-specific: Filters that are defined and supported by - specific vendors. - In the future, filters showing convergence in behavior across multiple - implementations will be considered for inclusion in extended or core - conformance levels. Filter-specific configuration for such filters - is specified using the ExtensionRef field. `Type` should be set to - "ExtensionRef" for custom filters. - - - Implementers are encouraged to define custom implementation types to - extend the core API with implementation-specific behavior. - - - If a reference to a custom filter type cannot be resolved, the filter - MUST NOT be skipped. Instead, requests that would have been processed by - that filter MUST receive a HTTP error response. - - - Note that values may be added to this enum, implementations - must ensure that unknown values will not cause a crash. - - - Unknown values here must result in the implementation setting the - Accepted Condition for the Route to `status: False`, with a - Reason of `UnsupportedValue`. - enum: - - RequestHeaderModifier - - ResponseHeaderModifier - - RequestMirror - - RequestRedirect - - URLRewrite - - ExtensionRef - type: string - urlRewrite: - description: |- - URLRewrite defines a schema for a filter that modifies a request during forwarding. - - - Support: Extended - properties: - hostname: - description: |- - Hostname is the value to be used to replace the Host header value during - forwarding. - - - Support: Extended - maxLength: 253 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - path: - description: |- - Path defines a path rewrite. - - - Support: Extended - properties: - replaceFullPath: - description: |- - ReplaceFullPath specifies the value with which to replace the full path - of a request during a rewrite or redirect. - maxLength: 1024 - type: string - replacePrefixMatch: - description: |- - ReplacePrefixMatch specifies the value with which to replace the prefix - match of a request during a rewrite or redirect. For example, a request - to "/foo/bar" with a prefix match of "/foo" and a ReplacePrefixMatch - of "/xyz" would be modified to "/xyz/bar". - - - Note that this matches the behavior of the PathPrefix match type. This - matches full path elements. A path element refers to the list of labels - in the path split by the `/` separator. When specified, a trailing `/` is - ignored. For example, the paths `/abc`, `/abc/`, and `/abc/def` would all - match the prefix `/abc`, but the path `/abcd` would not. - - - ReplacePrefixMatch is only compatible with a `PathPrefix` HTTPRouteMatch. - Using any other HTTPRouteMatch type on the same HTTPRouteRule will result in - the implementation setting the Accepted Condition for the Route to `status: False`. - - - Request Path | Prefix Match | Replace Prefix | Modified Path - -------------|--------------|----------------|---------- - /foo/bar | /foo | /xyz | /xyz/bar - /foo/bar | /foo | /xyz/ | /xyz/bar - /foo/bar | /foo/ | /xyz | /xyz/bar - /foo/bar | /foo/ | /xyz/ | /xyz/bar - /foo | /foo | /xyz | /xyz - /foo/ | /foo | /xyz | /xyz/ - /foo/bar | /foo | | /bar - /foo/ | /foo | | / - /foo | /foo | | / - /foo/ | /foo | / | / - /foo | /foo | / | / - maxLength: 1024 - type: string - type: - description: |- - Type defines the type of path modifier. Additional types may be - added in a future release of the API. - - - Note that values may be added to this enum, implementations - must ensure that unknown values will not cause a crash. - - - Unknown values here must result in the implementation setting the - Accepted Condition for the Route to `status: False`, with a - Reason of `UnsupportedValue`. - enum: - - ReplaceFullPath - - ReplacePrefixMatch - type: string - required: - - type - type: object - type: object - required: - - type - type: object - maxItems: 16 - type: array - matches: - description: |- - Matches define conditions used for matching the rule against incoming - HTTP requests. Each match is independent, i.e. this rule will be matched - if **any** one of the matches is satisfied. - - - For example, take the following matches configuration: - - - ``` - matches: - - path: - value: "/foo" - headers: - - name: "version" - value: "v2" - - path: - value: "/v2/foo" - ``` - - - For a request to match against this rule, a request must satisfy - EITHER of the two conditions: - - - - path prefixed with `/foo` AND contains the header `version: v2` - - path prefix of `/v2/foo` - - - See the documentation for HTTPRouteMatch on how to specify multiple - match conditions that should be ANDed together. - - - If no matches are specified, the default is a prefix - path match on "/", which has the effect of matching every - HTTP request. - - - Proxy or Load Balancer routing configuration generated from HTTPRoutes - MUST prioritize matches based on the following criteria, continuing on - ties. Across all rules specified on applicable Routes, precedence must be - given to the match having: - - - * "Exact" path match. - * "Prefix" path match with largest number of characters. - * Method match. - * Largest number of header matches. - * Largest number of query param matches. - - - Note: The precedence of RegularExpression path matches are implementation-specific. - - - If ties still exist across multiple Routes, matching precedence MUST be - determined in order of the following criteria, continuing on ties: - - - * The oldest Route based on creation timestamp. - * The Route appearing first in alphabetical order by - "{namespace}/{name}". - - - If ties still exist within an HTTPRoute, matching precedence MUST be granted - to the FIRST matching rule (in list order) with a match meeting the above - criteria. - - - When no rules matching a request have been successfully attached to the - parent a request is coming from, a HTTP 404 status code MUST be returned. - items: - properties: - headers: - description: |- - Headers specifies HTTP request header matchers. Multiple match values are - ANDed together, meaning, a request must match all the specified headers - to select the route. - items: - description: |- - HTTPHeaderMatch describes how to select a HTTP route by matching HTTP request - headers. - properties: - name: - description: |- - Name is the name of the HTTP Header to be matched. Name matching MUST be - case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). - - - If multiple entries specify equivalent header names, only the first - entry with an equivalent name MUST be considered for a match. Subsequent - entries with an equivalent header name MUST be ignored. Due to the - case-insensitivity of header names, "foo" and "Foo" are considered - equivalent. - - - When a header is repeated in an HTTP request, it is - implementation-specific behavior as to how this is represented. - Generally, proxies should follow the guidance from the RFC: - https://www.rfc-editor.org/rfc/rfc7230.html#section-3.2.2 regarding - processing a repeated header, with special handling for "Set-Cookie". - maxLength: 256 - minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ - type: string - type: - default: Exact - description: |- - Type specifies how to match against the value of the header. - - - Support: Core (Exact) - - - Support: Implementation-specific (RegularExpression) - - - Since RegularExpression HeaderMatchType has implementation-specific - conformance, implementations can support POSIX, PCRE or any other dialects - of regular expressions. Please read the implementation's documentation to - determine the supported dialect. - enum: - - Exact - - RegularExpression - type: string - value: - description: Value is the value of HTTP Header to be matched. - maxLength: 4096 - minLength: 1 - type: string - required: - - name - - value - type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - path: - description: Path specifies a HTTP request path matcher. - properties: - type: - default: PathPrefix - description: |- - Type specifies how to match against the path Value. - - - Support: Core (Exact, PathPrefix) - - - Support: Implementation-specific (RegularExpression) - enum: - - Exact - - PathPrefix - - RegularExpression - type: string - value: - default: / - description: Value of the HTTP path to match against. - maxLength: 1024 - type: string - type: object - queryParams: - description: |- - QueryParams specifies HTTP query parameter matchers. Multiple match - values are ANDed together, meaning, a request must match all the - specified query parameters to select the route. - - - Support: Extended - items: - description: |- - HTTPQueryParamMatch describes how to select a HTTP route by matching HTTP - query parameters. - properties: - name: - description: |- - Name is the name of the HTTP query param to be matched. This must be an - exact string match. (See - https://tools.ietf.org/html/rfc7230#section-2.7.3). - - - If multiple entries specify equivalent query param names, only the first - entry with an equivalent name MUST be considered for a match. Subsequent - entries with an equivalent query param name MUST be ignored. - - - If a query param is repeated in an HTTP request, the behavior is - purposely left undefined, since different data planes have different - capabilities. However, it is *recommended* that implementations should - match against the first value of the param if the data plane supports it, - as this behavior is expected in other load balancing contexts outside of - the Gateway API. - - - Users SHOULD NOT route traffic based on repeated query params to guard - themselves against potential differences in the implementations. - maxLength: 256 - minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ - type: string - type: - default: Exact - description: |- - Type specifies how to match against the value of the query parameter. - - - Support: Extended (Exact) - - - Support: Implementation-specific (RegularExpression) - - - Since RegularExpression QueryParamMatchType has Implementation-specific - conformance, implementations can support POSIX, PCRE or any other - dialects of regular expressions. Please read the implementation's - documentation to determine the supported dialect. - enum: - - Exact - - RegularExpression - type: string - value: - description: Value is the value of HTTP query param to be matched. - maxLength: 1024 - minLength: 1 - type: string - required: - - name - - value - type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - type: object - maxItems: 8 - type: array - type: object - weight: - description: Weight indicate how many percentage of traffic the canary pods should receive - format: int32 - maximum: 100 - minimum: 0 - type: integer - type: object - type: object - required: - - targets - type: object disabled: description: |- Disabled means that rollout will not response for new event. @@ -4516,10 +70,7 @@ spec: format: int32 type: integer strategyRef: - description: |- - StrategyRef is the reference to the rollout strategy. - Mutually exclusive with CanaryStrategy and BatchStrategy. - If specified, CanaryStrategy and BatchStrategy must be empty. + description: StrategyRef is the reference to the rollout strategy. type: string trafficTopologyRefs: description: |- diff --git a/config/crd/bases/rollout.kusionstack.io_rolloutstrategies.yaml b/config/crd/bases/rollout.kusionstack.io_rolloutstrategies.yaml index 1d221c6..bd9851e 100644 --- a/config/crd/bases/rollout.kusionstack.io_rolloutstrategies.yaml +++ b/config/crd/bases/rollout.kusionstack.io_rolloutstrategies.yaml @@ -11,4658 +11,9211 @@ spec: listKind: RolloutStrategyList plural: rolloutstrategies shortNames: - - ros + - ros singular: rolloutstrategy scope: Namespaced versions: - - name: v1alpha1 - schema: - openAPIV3Schema: - description: RolloutStrategy is the Schema for the rolloutstrategies API - properties: - apiVersion: - description: |- - APIVersion defines the versioned schema of this representation of an object. - Servers should convert recognized schemas to the latest internal value, and - may reject unrecognized values. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources - type: string - batch: - description: Batch is the batch strategy for upgrade and operation - properties: - batches: - description: Batches define the order of phases to execute release in canary release - items: - description: Custom release step - properties: - breakpoint: - description: If set to true, the rollout will be paused before the step starts. - type: boolean - matchTargets: - description: Match defines condition used for matching resource cross clusterset - properties: - names: - description: Names is a list of workload name - items: - description: CrossClusterObjectNameReference contains cluster and name reference to a k8s object + - name: v1alpha1 + schema: + openAPIV3Schema: + description: RolloutStrategy is the Schema for the rolloutstrategies API + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + batch: + description: Batch is the batch strategy for upgrade and operation + properties: + batches: + description: Batches define the order of phases to execute release in canary release + items: + description: Custom release step + properties: + breakpoint: + description: If set to true, the rollout will be paused before the step starts. + type: boolean + matchTargets: + description: Match defines condition used for matching resource cross clusterset + properties: + names: + description: Names is a list of workload name + items: + description: CrossClusterObjectNameReference contains cluster and name reference to a k8s object + properties: + cluster: + description: Cluster indicates the name of cluster + type: string + name: + description: Name is the resource name + type: string + required: + - name + type: object + type: array + selector: + description: Selector is a label query over a set of resources, in this case resource properties: - cluster: - description: Cluster indicates the name of cluster - type: string - name: - description: Name is the resource name - type: string - required: - - name - type: object - type: array - selector: - description: Selector is a label query over a set of resources, in this case resource - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. - items: - description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. - properties: - key: - description: key is the label key that the selector applies to. - type: string - operator: - description: |- - operator represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists and DoesNotExist. - type: string - values: - description: |- - values is an array of string values. If the operator is In or NotIn, - the values array must be non-empty. If the operator is Exists or DoesNotExist, - the values array must be empty. This array is replaced during a strategic - merge patch. - items: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector applies to. type: string - type: array - required: - - key - - operator + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. type: object - type: array - matchLabels: - additionalProperties: - type: string - description: |- - matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels - map is equivalent to an element of matchExpressions, whose key field is "key", the - operator is "In", and the values array contains only "value". The requirements are ANDed. - type: object - type: object - x-kubernetes-map-type: atomic - type: object - properties: - additionalProperties: - type: string - description: Properties contains additional information for step - type: object - replicaSlidingWindow: - anyOf: - - type: integer - - type: string - description: |- - ReplicaSlidingWindow used to control the number of pods that are allowed to be upgraded in - a sliding window for progressive rollout smoothly. - x-kubernetes-int-or-string: true - replicas: - anyOf: - - type: integer - - type: string - description: Replicas is the replicas of the rollout task, which represents the number of pods to be upgraded - x-kubernetes-int-or-string: true - traffic: - description: traffic strategy + type: object + x-kubernetes-map-type: atomic + type: object properties: - http: - properties: - filters: - description: |- - Filters define the filters that are applied to requests that match - this rule. - - - The effects of ordering of multiple behaviors are currently unspecified. - This can change in the future based on feedback during the alpha stage. - - - Conformance-levels at this level are defined based on the type of filter: - - - - ALL core filters MUST be supported by all implementations. - - Implementers are encouraged to support extended filters. - - Implementation-specific custom filters have no API guarantees across - implementations. - - - Specifying the same filter multiple times is not supported unless explicitly - indicated in the filter. - - - All filters are expected to be compatible with each other except for the - URLRewrite and RequestRedirect filters, which may not be combined. If an - implementation can not support other combinations of filters, they must clearly - document that limitation. In cases where incompatible or unsupported - filters are specified and cause the `Accepted` condition to be set to status - `False`, implementations may use the `IncompatibleFilters` reason to specify - this configuration error. - - - Support: Core - items: + additionalProperties: + type: string + description: Properties contains additional information for step + type: object + replicaSlidingWindow: + anyOf: + - type: integer + - type: string + description: |- + ReplicaSlidingWindow used to control the number of pods that are allowed to be upgraded in + a sliding window for progressive rollout smoothly. + x-kubernetes-int-or-string: true + replicas: + anyOf: + - type: integer + - type: string + description: Replicas is the replicas of the rollout task, which represents the number of pods to be upgraded + x-kubernetes-int-or-string: true + traffic: + description: traffic strategy + properties: + http: + properties: + filters: description: |- - HTTPRouteFilter defines processing steps that must be completed during the - request or response lifecycle. HTTPRouteFilters are meant as an extension - point to express processing that may be done in Gateway implementations. Some - examples include request or response modification, implementing - authentication strategies, rate-limiting, and traffic shaping. API - guarantee/conformance is defined based on the type of the filter. - properties: - extensionRef: - description: |- - ExtensionRef is an optional, implementation-specific extension to the - "filter" behavior. For example, resource "myroutefilter" in group - "networking.example.net"). ExtensionRef MUST NOT be used for core and - extended filters. - - - This filter can be used multiple times within the same rule. - - - Support: Implementation-specific - properties: - group: - description: |- - Group is the group of the referent. For example, "gateway.networking.k8s.io". - When unspecified or empty string, core API group is inferred. - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - description: Kind is kind of the referent. For example "HTTPRoute" or "Service". - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - type: string - name: - description: Name is the name of the referent. - maxLength: 253 - minLength: 1 - type: string - required: - - group - - kind - - name - type: object - requestHeaderModifier: - description: |- - RequestHeaderModifier defines a schema for a filter that modifies request - headers. - - - Support: Core - properties: - add: - description: |- - Add adds the given header(s) (name, value) to the request - before the action. It appends to any existing values associated - with the header name. - - - Input: - GET /foo HTTP/1.1 - my-header: foo - - - Config: - add: - - name: "my-header" - value: "bar,baz" - - - Output: - GET /foo HTTP/1.1 - my-header: foo,bar,baz - items: - description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. + Filters define the filters that are applied to requests that match + this rule. + + + The effects of ordering of multiple behaviors are currently unspecified. + This can change in the future based on feedback during the alpha stage. + + + Conformance-levels at this level are defined based on the type of filter: + + + - ALL core filters MUST be supported by all implementations. + - Implementers are encouraged to support extended filters. + - Implementation-specific custom filters have no API guarantees across + implementations. + + + Specifying the same filter multiple times is not supported unless explicitly + indicated in the filter. + + + All filters are expected to be compatible with each other except for the + URLRewrite and RequestRedirect filters, which may not be combined. If an + implementation can not support other combinations of filters, they must clearly + document that limitation. In cases where incompatible or unsupported + filters are specified and cause the `Accepted` condition to be set to status + `False`, implementations may use the `IncompatibleFilters` reason to specify + this configuration error. + + + Support: Core + items: + description: |- + HTTPRouteFilter defines processing steps that must be completed during the + request or response lifecycle. HTTPRouteFilters are meant as an extension + point to express processing that may be done in Gateway implementations. Some + examples include request or response modification, implementing + authentication strategies, rate-limiting, and traffic shaping. API + guarantee/conformance is defined based on the type of the filter. + properties: + extensionRef: + description: |- + ExtensionRef is an optional, implementation-specific extension to the + "filter" behavior. For example, resource "myroutefilter" in group + "networking.example.net"). ExtensionRef MUST NOT be used for core and + extended filters. + + + This filter can be used multiple times within the same rule. + + + Support: Implementation-specific + properties: + group: + description: |- + Group is the group of the referent. For example, "gateway.networking.k8s.io". + When unspecified or empty string, core API group is inferred. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + description: Kind is kind of the referent. For example "HTTPRoute" or "Service". + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: Name is the name of the referent. + maxLength: 253 + minLength: 1 + type: string + required: + - group + - kind + - name + type: object + requestHeaderModifier: + description: |- + RequestHeaderModifier defines a schema for a filter that modifies request + headers. + + + Support: Core + properties: + add: + description: |- + Add adds the given header(s) (name, value) to the request + before the action. It appends to any existing values associated + with the header name. + + + Input: + GET /foo HTTP/1.1 + my-header: foo + + + Config: + add: + - name: "my-header" + value: "bar,baz" + + + Output: + GET /foo HTTP/1.1 + my-header: foo,bar,baz + items: + description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + + If multiple entries specify equivalent header names, the first entry with + an equivalent name MUST be considered for a match. Subsequent entries + with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + description: Value is the value of HTTP Header to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + remove: + description: |- + Remove the given header(s) from the HTTP request before the action. The + value of Remove is a list of HTTP header names. Note that the header + names are case-insensitive (see + https://datatracker.ietf.org/doc/html/rfc2616#section-4.2). + + + Input: + GET /foo HTTP/1.1 + my-header1: foo + my-header2: bar + my-header3: baz + + + Config: + remove: ["my-header1", "my-header3"] + + + Output: + GET /foo HTTP/1.1 + my-header2: bar + items: + type: string + maxItems: 16 + type: array + x-kubernetes-list-type: set + set: + description: |- + Set overwrites the request with the given header (name, value) + before the action. + + + Input: + GET /foo HTTP/1.1 + my-header: foo + + + Config: + set: + - name: "my-header" + value: "bar" + + + Output: + GET /foo HTTP/1.1 + my-header: bar + items: + description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + + If multiple entries specify equivalent header names, the first entry with + an equivalent name MUST be considered for a match. Subsequent entries + with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + description: Value is the value of HTTP Header to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + type: object + requestMirror: + description: |- + RequestMirror defines a schema for a filter that mirrors requests. + Requests are sent to the specified destination, but responses from + that destination are ignored. + + + This filter can be used multiple times within the same rule. Note that + not all implementations will be able to support mirroring to multiple + backends. + + + Support: Extended + + + + properties: + backendRef: + description: |- + BackendRef references a resource where mirrored requests are sent. + + + Mirrored requests must be sent only to a single destination endpoint + within this BackendRef, irrespective of how many endpoints are present + within this BackendRef. + + + If the referent cannot be found, this BackendRef is invalid and must be + dropped from the Gateway. The controller must ensure the "ResolvedRefs" + condition on the Route status is set to `status: False` and not configure + this backend in the underlying implementation. + + + If there is a cross-namespace reference to an *existing* object + that is not allowed by a ReferenceGrant, the controller must ensure the + "ResolvedRefs" condition on the Route is set to `status: False`, + with the "RefNotPermitted" reason and not configure this backend in the + underlying implementation. + + + In either error case, the Message of the `ResolvedRefs` Condition + should be used to provide more detail about the problem. + + + Support: Extended for Kubernetes Service + + + Support: Implementation-specific for any other resource properties: - name: + group: + default: "" description: |- - Name is the name of the HTTP Header to be matched. Name matching MUST be - case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). - - - If multiple entries specify equivalent header names, the first entry with - an equivalent name MUST be considered for a match. Subsequent entries - with an equivalent header name MUST be ignored. Due to the - case-insensitivity of header names, "foo" and "Foo" are considered - equivalent. - maxLength: 256 + Group is the group of the referent. For example, "gateway.networking.k8s.io". + When unspecified or empty string, core API group is inferred. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + default: Service + description: |- + Kind is the Kubernetes resource kind of the referent. For example + "Service". + + + Defaults to "Service" when not specified. + + + ExternalName services can refer to CNAME DNS records that may live + outside of the cluster and as such are difficult to reason about in + terms of conformance. They also may not be safe to forward to (see + CVE-2021-25740 for more information). Implementations SHOULD NOT + support ExternalName Services. + + + Support: Core (Services with a type other than ExternalName) + + + Support: Implementation-specific (Services with type ExternalName) + maxLength: 63 minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ type: string - value: - description: Value is the value of HTTP Header to be matched. - maxLength: 4096 + name: + description: Name is the name of the referent. + maxLength: 253 + minLength: 1 + type: string + namespace: + description: |- + Namespace is the namespace of the backend. When unspecified, the local + namespace is inferred. + + + Note that when a namespace different than the local namespace is specified, + a ReferenceGrant object is required in the referent namespace to allow that + namespace's owner to accept the reference. See the ReferenceGrant + documentation for details. + + + Support: Core + maxLength: 63 minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ type: string + port: + description: |- + Port specifies the destination port number to use for this resource. + Port is required when the referent is a Kubernetes Service. In this + case, the port number is the service port number, not the target port. + For other resources, destination port might be derived from the referent + resource or this field. + format: int32 + maximum: 65535 + minimum: 1 + type: integer required: - - name - - value + - name type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - remove: - description: |- - Remove the given header(s) from the HTTP request before the action. The - value of Remove is a list of HTTP header names. Note that the header - names are case-insensitive (see - https://datatracker.ietf.org/doc/html/rfc2616#section-4.2). - - - Input: - GET /foo HTTP/1.1 - my-header1: foo - my-header2: bar - my-header3: baz - - - Config: - remove: ["my-header1", "my-header3"] - - - Output: - GET /foo HTTP/1.1 - my-header2: bar - items: + fraction: + description: |- + Fraction represents the fraction of requests that should be + mirrored to BackendRef. + + + Only one of Fraction or Percent may be specified. If neither field + is specified, 100% of requests will be mirrored. + + + + properties: + denominator: + default: 100 + format: int32 + minimum: 1 + type: integer + numerator: + format: int32 + minimum: 0 + type: integer + required: + - numerator + type: object + percent: + description: |- + Percent represents the percentage of requests that should be + mirrored to BackendRef. Its minimum value is 0 (indicating 0% of + requests) and its maximum value is 100 (indicating 100% of requests). + + + Only one of Fraction or Percent may be specified. If neither field + is specified, 100% of requests will be mirrored. + + + + format: int32 + maximum: 100 + minimum: 0 + type: integer + required: + - backendRef + type: object + requestRedirect: + description: |- + RequestRedirect defines a schema for a filter that responds to the + request with an HTTP redirection. + + + Support: Core + properties: + hostname: + description: |- + Hostname is the hostname to be used in the value of the `Location` + header in the response. + When empty, the hostname in the `Host` header of the request is used. + + + Support: Core + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ type: string - maxItems: 16 - type: array - x-kubernetes-list-type: set - set: - description: |- - Set overwrites the request with the given header (name, value) - before the action. - - - Input: - GET /foo HTTP/1.1 - my-header: foo - - - Config: - set: - - name: "my-header" - value: "bar" - - - Output: - GET /foo HTTP/1.1 - my-header: bar - items: - description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. + path: + description: |- + Path defines parameters used to modify the path of the incoming request. + The modified path is then used to construct the `Location` header. When + empty, the request path is used as-is. + + + Support: Extended properties: - name: + replaceFullPath: description: |- - Name is the name of the HTTP Header to be matched. Name matching MUST be - case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). - - - If multiple entries specify equivalent header names, the first entry with - an equivalent name MUST be considered for a match. Subsequent entries - with an equivalent header name MUST be ignored. Due to the - case-insensitivity of header names, "foo" and "Foo" are considered - equivalent. - maxLength: 256 - minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + ReplaceFullPath specifies the value with which to replace the full path + of a request during a rewrite or redirect. + maxLength: 1024 type: string - value: - description: Value is the value of HTTP Header to be matched. - maxLength: 4096 - minLength: 1 + replacePrefixMatch: + description: |- + ReplacePrefixMatch specifies the value with which to replace the prefix + match of a request during a rewrite or redirect. For example, a request + to "/foo/bar" with a prefix match of "/foo" and a ReplacePrefixMatch + of "/xyz" would be modified to "/xyz/bar". + + + Note that this matches the behavior of the PathPrefix match type. This + matches full path elements. A path element refers to the list of labels + in the path split by the `/` separator. When specified, a trailing `/` is + ignored. For example, the paths `/abc`, `/abc/`, and `/abc/def` would all + match the prefix `/abc`, but the path `/abcd` would not. + + + ReplacePrefixMatch is only compatible with a `PathPrefix` HTTPRouteMatch. + Using any other HTTPRouteMatch type on the same HTTPRouteRule will result in + the implementation setting the Accepted Condition for the Route to `status: False`. + + + Request Path | Prefix Match | Replace Prefix | Modified Path + -------------|--------------|----------------|---------- + /foo/bar | /foo | /xyz | /xyz/bar + /foo/bar | /foo | /xyz/ | /xyz/bar + /foo/bar | /foo/ | /xyz | /xyz/bar + /foo/bar | /foo/ | /xyz/ | /xyz/bar + /foo | /foo | /xyz | /xyz + /foo/ | /foo | /xyz | /xyz/ + /foo/bar | /foo | | /bar + /foo/ | /foo | | / + /foo | /foo | | / + /foo/ | /foo | / | / + /foo | /foo | / | / + maxLength: 1024 + type: string + type: + description: |- + Type defines the type of path modifier. Additional types may be + added in a future release of the API. + + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + enum: + - ReplaceFullPath + - ReplacePrefixMatch type: string required: - - name - - value + - type type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - type: object - requestMirror: - description: |- - RequestMirror defines a schema for a filter that mirrors requests. - Requests are sent to the specified destination, but responses from - that destination are ignored. - - - This filter can be used multiple times within the same rule. Note that - not all implementations will be able to support mirroring to multiple - backends. - - - Support: Extended - - - - properties: - backendRef: + port: + description: |- + Port is the port to be used in the value of the `Location` + header in the response. + + + If no port is specified, the redirect port MUST be derived using the + following rules: + + + * If redirect scheme is not-empty, the redirect port MUST be the well-known + port associated with the redirect scheme. Specifically "http" to port 80 + and "https" to port 443. If the redirect scheme does not have a + well-known port, the listener port of the Gateway SHOULD be used. + * If redirect scheme is empty, the redirect port MUST be the Gateway + Listener port. + + + Implementations SHOULD NOT add the port number in the 'Location' + header in the following cases: + + + * A Location header that will use HTTP (whether that is determined via + the Listener protocol or the Scheme field) _and_ use port 80. + * A Location header that will use HTTPS (whether that is determined via + the Listener protocol or the Scheme field) _and_ use port 443. + + + Support: Extended + format: int32 + maximum: 65535 + minimum: 1 + type: integer + scheme: + description: |- + Scheme is the scheme to be used in the value of the `Location` header in + the response. When empty, the scheme of the request is used. + + + Scheme redirects can affect the port of the redirect, for more information, + refer to the documentation for the port field of this filter. + + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + + + Support: Extended + enum: + - http + - https + type: string + statusCode: + default: 302 + description: |- + StatusCode is the HTTP status code to be used in response. + + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + + + Support: Core + enum: + - 301 + - 302 + type: integer + type: object + responseHeaderModifier: + description: |- + ResponseHeaderModifier defines a schema for a filter that modifies response + headers. + + + Support: Extended + properties: + add: + description: |- + Add adds the given header(s) (name, value) to the request + before the action. It appends to any existing values associated + with the header name. + + + Input: + GET /foo HTTP/1.1 + my-header: foo + + + Config: + add: + - name: "my-header" + value: "bar,baz" + + + Output: + GET /foo HTTP/1.1 + my-header: foo,bar,baz + items: + description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + + If multiple entries specify equivalent header names, the first entry with + an equivalent name MUST be considered for a match. Subsequent entries + with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + description: Value is the value of HTTP Header to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + remove: + description: |- + Remove the given header(s) from the HTTP request before the action. The + value of Remove is a list of HTTP header names. Note that the header + names are case-insensitive (see + https://datatracker.ietf.org/doc/html/rfc2616#section-4.2). + + + Input: + GET /foo HTTP/1.1 + my-header1: foo + my-header2: bar + my-header3: baz + + + Config: + remove: ["my-header1", "my-header3"] + + + Output: + GET /foo HTTP/1.1 + my-header2: bar + items: + type: string + maxItems: 16 + type: array + x-kubernetes-list-type: set + set: + description: |- + Set overwrites the request with the given header (name, value) + before the action. + + + Input: + GET /foo HTTP/1.1 + my-header: foo + + + Config: + set: + - name: "my-header" + value: "bar" + + + Output: + GET /foo HTTP/1.1 + my-header: bar + items: + description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + + If multiple entries specify equivalent header names, the first entry with + an equivalent name MUST be considered for a match. Subsequent entries + with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + description: Value is the value of HTTP Header to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + type: object + type: + description: |- + Type identifies the type of filter to apply. As with other API fields, + types are classified into three conformance levels: + + + - Core: Filter types and their corresponding configuration defined by + "Support: Core" in this package, e.g. "RequestHeaderModifier". All + implementations must support core filters. + + + - Extended: Filter types and their corresponding configuration defined by + "Support: Extended" in this package, e.g. "RequestMirror". Implementers + are encouraged to support extended filters. + + + - Implementation-specific: Filters that are defined and supported by + specific vendors. + In the future, filters showing convergence in behavior across multiple + implementations will be considered for inclusion in extended or core + conformance levels. Filter-specific configuration for such filters + is specified using the ExtensionRef field. `Type` should be set to + "ExtensionRef" for custom filters. + + + Implementers are encouraged to define custom implementation types to + extend the core API with implementation-specific behavior. + + + If a reference to a custom filter type cannot be resolved, the filter + MUST NOT be skipped. Instead, requests that would have been processed by + that filter MUST receive a HTTP error response. + + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + enum: + - RequestHeaderModifier + - ResponseHeaderModifier + - RequestMirror + - RequestRedirect + - URLRewrite + - ExtensionRef + type: string + urlRewrite: + description: |- + URLRewrite defines a schema for a filter that modifies a request during forwarding. + + + Support: Extended + properties: + hostname: + description: |- + Hostname is the value to be used to replace the Host header value during + forwarding. + + + Support: Extended + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + path: + description: |- + Path defines a path rewrite. + + + Support: Extended + properties: + replaceFullPath: + description: |- + ReplaceFullPath specifies the value with which to replace the full path + of a request during a rewrite or redirect. + maxLength: 1024 + type: string + replacePrefixMatch: + description: |- + ReplacePrefixMatch specifies the value with which to replace the prefix + match of a request during a rewrite or redirect. For example, a request + to "/foo/bar" with a prefix match of "/foo" and a ReplacePrefixMatch + of "/xyz" would be modified to "/xyz/bar". + + + Note that this matches the behavior of the PathPrefix match type. This + matches full path elements. A path element refers to the list of labels + in the path split by the `/` separator. When specified, a trailing `/` is + ignored. For example, the paths `/abc`, `/abc/`, and `/abc/def` would all + match the prefix `/abc`, but the path `/abcd` would not. + + + ReplacePrefixMatch is only compatible with a `PathPrefix` HTTPRouteMatch. + Using any other HTTPRouteMatch type on the same HTTPRouteRule will result in + the implementation setting the Accepted Condition for the Route to `status: False`. + + + Request Path | Prefix Match | Replace Prefix | Modified Path + -------------|--------------|----------------|---------- + /foo/bar | /foo | /xyz | /xyz/bar + /foo/bar | /foo | /xyz/ | /xyz/bar + /foo/bar | /foo/ | /xyz | /xyz/bar + /foo/bar | /foo/ | /xyz/ | /xyz/bar + /foo | /foo | /xyz | /xyz + /foo/ | /foo | /xyz | /xyz/ + /foo/bar | /foo | | /bar + /foo/ | /foo | | / + /foo | /foo | | / + /foo/ | /foo | / | / + /foo | /foo | / | / + maxLength: 1024 + type: string + type: + description: |- + Type defines the type of path modifier. Additional types may be + added in a future release of the API. + + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + enum: + - ReplaceFullPath + - ReplacePrefixMatch + type: string + required: + - type + type: object + type: object + required: + - type + type: object + maxItems: 16 + type: array + matches: + description: |- + Matches define conditions used for matching the rule against incoming + HTTP requests. Each match is independent, i.e. this rule will be matched + if **any** one of the matches is satisfied. + + + For example, take the following matches configuration: + + + ``` + matches: + - path: + value: "/foo" + headers: + - name: "version" + value: "v2" + - path: + value: "/v2/foo" + ``` + + + For a request to match against this rule, a request must satisfy + EITHER of the two conditions: + + + - path prefixed with `/foo` AND contains the header `version: v2` + - path prefix of `/v2/foo` + + + See the documentation for HTTPRouteMatch on how to specify multiple + match conditions that should be ANDed together. + + + If no matches are specified, the default is a prefix + path match on "/", which has the effect of matching every + HTTP request. + + + Proxy or Load Balancer routing configuration generated from HTTPRoutes + MUST prioritize matches based on the following criteria, continuing on + ties. Across all rules specified on applicable Routes, precedence must be + given to the match having: + + + * "Exact" path match. + * "Prefix" path match with largest number of characters. + * Method match. + * Largest number of header matches. + * Largest number of query param matches. + + + Note: The precedence of RegularExpression path matches are implementation-specific. + + + If ties still exist across multiple Routes, matching precedence MUST be + determined in order of the following criteria, continuing on ties: + + + * The oldest Route based on creation timestamp. + * The Route appearing first in alphabetical order by + "{namespace}/{name}". + + + If ties still exist within an HTTPRoute, matching precedence MUST be granted + to the FIRST matching rule (in list order) with a match meeting the above + criteria. + + + When no rules matching a request have been successfully attached to the + parent a request is coming from, a HTTP 404 status code MUST be returned. + items: + properties: + headers: + description: |- + Headers specifies HTTP request header matchers. Multiple match values are + ANDed together, meaning, a request must match all the specified headers + to select the route. + items: description: |- - BackendRef references a resource where mirrored requests are sent. - - - Mirrored requests must be sent only to a single destination endpoint - within this BackendRef, irrespective of how many endpoints are present - within this BackendRef. - - - If the referent cannot be found, this BackendRef is invalid and must be - dropped from the Gateway. The controller must ensure the "ResolvedRefs" - condition on the Route status is set to `status: False` and not configure - this backend in the underlying implementation. - - - If there is a cross-namespace reference to an *existing* object - that is not allowed by a ReferenceGrant, the controller must ensure the - "ResolvedRefs" condition on the Route is set to `status: False`, - with the "RefNotPermitted" reason and not configure this backend in the - underlying implementation. - - - In either error case, the Message of the `ResolvedRefs` Condition - should be used to provide more detail about the problem. - - - Support: Extended for Kubernetes Service - - - Support: Implementation-specific for any other resource + HTTPHeaderMatch describes how to select a HTTP route by matching HTTP request + headers. properties: - group: - default: "" + name: description: |- - Group is the group of the referent. For example, "gateway.networking.k8s.io". - When unspecified or empty string, core API group is inferred. - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + + If multiple entries specify equivalent header names, only the first + entry with an equivalent name MUST be considered for a match. Subsequent + entries with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + + + When a header is repeated in an HTTP request, it is + implementation-specific behavior as to how this is represented. + Generally, proxies should follow the guidance from the RFC: + https://www.rfc-editor.org/rfc/rfc7230.html#section-3.2.2 regarding + processing a repeated header, with special handling for "Set-Cookie". + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ type: string - kind: - default: Service + type: + default: Exact description: |- - Kind is the Kubernetes resource kind of the referent. For example - "Service". - - - Defaults to "Service" when not specified. - - - ExternalName services can refer to CNAME DNS records that may live - outside of the cluster and as such are difficult to reason about in - terms of conformance. They also may not be safe to forward to (see - CVE-2021-25740 for more information). Implementations SHOULD NOT - support ExternalName Services. - - - Support: Core (Services with a type other than ExternalName) - - - Support: Implementation-specific (Services with type ExternalName) - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + Type specifies how to match against the value of the header. + + + Support: Core (Exact) + + + Support: Implementation-specific (RegularExpression) + + + Since RegularExpression HeaderMatchType has implementation-specific + conformance, implementations can support POSIX, PCRE or any other dialects + of regular expressions. Please read the implementation's documentation to + determine the supported dialect. + enum: + - Exact + - RegularExpression type: string - name: - description: Name is the name of the referent. - maxLength: 253 + value: + description: Value is the value of HTTP Header to be matched. + maxLength: 4096 minLength: 1 type: string - namespace: - description: |- - Namespace is the namespace of the backend. When unspecified, the local - namespace is inferred. - - - Note that when a namespace different than the local namespace is specified, - a ReferenceGrant object is required in the referent namespace to allow that - namespace's owner to accept the reference. See the ReferenceGrant - documentation for details. - - - Support: Core - maxLength: 63 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ - type: string - port: - description: |- - Port specifies the destination port number to use for this resource. - Port is required when the referent is a Kubernetes Service. In this - case, the port number is the service port number, not the target port. - For other resources, destination port might be derived from the referent - resource or this field. - format: int32 - maximum: 65535 - minimum: 1 - type: integer - required: - - name - type: object - fraction: - description: |- - Fraction represents the fraction of requests that should be - mirrored to BackendRef. - - - Only one of Fraction or Percent may be specified. If neither field - is specified, 100% of requests will be mirrored. - - - - properties: - denominator: - default: 100 - format: int32 - minimum: 1 - type: integer - numerator: - format: int32 - minimum: 0 - type: integer required: - - numerator + - name + - value type: object - percent: - description: |- - Percent represents the percentage of requests that should be - mirrored to BackendRef. Its minimum value is 0 (indicating 0% of - requests) and its maximum value is 100 (indicating 100% of requests). - - - Only one of Fraction or Percent may be specified. If neither field - is specified, 100% of requests will be mirrored. - - - - format: int32 - maximum: 100 - minimum: 0 - type: integer - required: - - backendRef - type: object - requestRedirect: - description: |- - RequestRedirect defines a schema for a filter that responds to the - request with an HTTP redirection. - - - Support: Core - properties: - hostname: - description: |- - Hostname is the hostname to be used in the value of the `Location` - header in the response. - When empty, the hostname in the `Host` header of the request is used. - - - Support: Core - maxLength: 253 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - path: + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + path: + description: Path specifies a HTTP request path matcher. + properties: + type: + default: PathPrefix + description: |- + Type specifies how to match against the path Value. + + + Support: Core (Exact, PathPrefix) + + + Support: Implementation-specific (RegularExpression) + enum: + - Exact + - PathPrefix + - RegularExpression + type: string + value: + default: / + description: Value of the HTTP path to match against. + maxLength: 1024 + type: string + type: object + queryParams: + description: |- + QueryParams specifies HTTP query parameter matchers. Multiple match + values are ANDed together, meaning, a request must match all the + specified query parameters to select the route. + + + Support: Extended + items: description: |- - Path defines parameters used to modify the path of the incoming request. - The modified path is then used to construct the `Location` header. When - empty, the request path is used as-is. - - - Support: Extended + HTTPQueryParamMatch describes how to select a HTTP route by matching HTTP + query parameters. properties: - replaceFullPath: - description: |- - ReplaceFullPath specifies the value with which to replace the full path - of a request during a rewrite or redirect. - maxLength: 1024 - type: string - replacePrefixMatch: + name: description: |- - ReplacePrefixMatch specifies the value with which to replace the prefix - match of a request during a rewrite or redirect. For example, a request - to "/foo/bar" with a prefix match of "/foo" and a ReplacePrefixMatch - of "/xyz" would be modified to "/xyz/bar". - - - Note that this matches the behavior of the PathPrefix match type. This - matches full path elements. A path element refers to the list of labels - in the path split by the `/` separator. When specified, a trailing `/` is - ignored. For example, the paths `/abc`, `/abc/`, and `/abc/def` would all - match the prefix `/abc`, but the path `/abcd` would not. - - - ReplacePrefixMatch is only compatible with a `PathPrefix` HTTPRouteMatch. - Using any other HTTPRouteMatch type on the same HTTPRouteRule will result in - the implementation setting the Accepted Condition for the Route to `status: False`. - - - Request Path | Prefix Match | Replace Prefix | Modified Path - -------------|--------------|----------------|---------- - /foo/bar | /foo | /xyz | /xyz/bar - /foo/bar | /foo | /xyz/ | /xyz/bar - /foo/bar | /foo/ | /xyz | /xyz/bar - /foo/bar | /foo/ | /xyz/ | /xyz/bar - /foo | /foo | /xyz | /xyz - /foo/ | /foo | /xyz | /xyz/ - /foo/bar | /foo | | /bar - /foo/ | /foo | | / - /foo | /foo | | / - /foo/ | /foo | / | / - /foo | /foo | / | / - maxLength: 1024 + Name is the name of the HTTP query param to be matched. This must be an + exact string match. (See + https://tools.ietf.org/html/rfc7230#section-2.7.3). + + + If multiple entries specify equivalent query param names, only the first + entry with an equivalent name MUST be considered for a match. Subsequent + entries with an equivalent query param name MUST be ignored. + + + If a query param is repeated in an HTTP request, the behavior is + purposely left undefined, since different data planes have different + capabilities. However, it is *recommended* that implementations should + match against the first value of the param if the data plane supports it, + as this behavior is expected in other load balancing contexts outside of + the Gateway API. + + + Users SHOULD NOT route traffic based on repeated query params to guard + themselves against potential differences in the implementations. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ type: string type: + default: Exact description: |- - Type defines the type of path modifier. Additional types may be - added in a future release of the API. - - - Note that values may be added to this enum, implementations - must ensure that unknown values will not cause a crash. - - - Unknown values here must result in the implementation setting the - Accepted Condition for the Route to `status: False`, with a - Reason of `UnsupportedValue`. + Type specifies how to match against the value of the query parameter. + + + Support: Extended (Exact) + + + Support: Implementation-specific (RegularExpression) + + + Since RegularExpression QueryParamMatchType has Implementation-specific + conformance, implementations can support POSIX, PCRE or any other + dialects of regular expressions. Please read the implementation's + documentation to determine the supported dialect. enum: - - ReplaceFullPath - - ReplacePrefixMatch + - Exact + - RegularExpression + type: string + value: + description: Value is the value of HTTP query param to be matched. + maxLength: 1024 + minLength: 1 type: string required: - - type + - name + - value type: object - port: - description: |- - Port is the port to be used in the value of the `Location` - header in the response. - - - If no port is specified, the redirect port MUST be derived using the - following rules: - - - * If redirect scheme is not-empty, the redirect port MUST be the well-known - port associated with the redirect scheme. Specifically "http" to port 80 - and "https" to port 443. If the redirect scheme does not have a - well-known port, the listener port of the Gateway SHOULD be used. - * If redirect scheme is empty, the redirect port MUST be the Gateway - Listener port. - - - Implementations SHOULD NOT add the port number in the 'Location' - header in the following cases: - - - * A Location header that will use HTTP (whether that is determined via - the Listener protocol or the Scheme field) _and_ use port 80. - * A Location header that will use HTTPS (whether that is determined via - the Listener protocol or the Scheme field) _and_ use port 443. - - - Support: Extended - format: int32 - maximum: 65535 - minimum: 1 - type: integer - scheme: - description: |- - Scheme is the scheme to be used in the value of the `Location` header in - the response. When empty, the scheme of the request is used. - - - Scheme redirects can affect the port of the redirect, for more information, - refer to the documentation for the port field of this filter. - - - Note that values may be added to this enum, implementations - must ensure that unknown values will not cause a crash. - - - Unknown values here must result in the implementation setting the - Accepted Condition for the Route to `status: False`, with a - Reason of `UnsupportedValue`. - - - Support: Extended - enum: - - http - - https - type: string - statusCode: - default: 302 - description: |- - StatusCode is the HTTP status code to be used in response. - - - Note that values may be added to this enum, implementations - must ensure that unknown values will not cause a crash. - - - Unknown values here must result in the implementation setting the - Accepted Condition for the Route to `status: False`, with a - Reason of `UnsupportedValue`. - - - Support: Core - enum: - - 301 - - 302 - type: integer - type: object - responseHeaderModifier: + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + type: object + maxItems: 8 + type: array + stableTraffic: + description: StableTraffic indicate the base traffic rule + properties: + filters: description: |- - ResponseHeaderModifier defines a schema for a filter that modifies response - headers. - - - Support: Extended - properties: - add: - description: |- - Add adds the given header(s) (name, value) to the request - before the action. It appends to any existing values associated - with the header name. - - - Input: - GET /foo HTTP/1.1 - my-header: foo - - - Config: - add: - - name: "my-header" - value: "bar,baz" - - - Output: - GET /foo HTTP/1.1 - my-header: foo,bar,baz - items: - description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. + Filters define the filters that are applied to requests that match + this rule. + + + The effects of ordering of multiple behaviors are currently unspecified. + This can change in the future based on feedback during the alpha stage. + + + Conformance-levels at this level are defined based on the type of filter: + + + - ALL core filters MUST be supported by all implementations. + - Implementers are encouraged to support extended filters. + - Implementation-specific custom filters have no API guarantees across + implementations. + + + Specifying the same filter multiple times is not supported unless explicitly + indicated in the filter. + + + All filters are expected to be compatible with each other except for the + URLRewrite and RequestRedirect filters, which may not be combined. If an + implementation can not support other combinations of filters, they must clearly + document that limitation. In cases where incompatible or unsupported + filters are specified and cause the `Accepted` condition to be set to status + `False`, implementations may use the `IncompatibleFilters` reason to specify + this configuration error. + + + Support: Core + items: + description: |- + HTTPRouteFilter defines processing steps that must be completed during the + request or response lifecycle. HTTPRouteFilters are meant as an extension + point to express processing that may be done in Gateway implementations. Some + examples include request or response modification, implementing + authentication strategies, rate-limiting, and traffic shaping. API + guarantee/conformance is defined based on the type of the filter. + properties: + extensionRef: + description: |- + ExtensionRef is an optional, implementation-specific extension to the + "filter" behavior. For example, resource "myroutefilter" in group + "networking.example.net"). ExtensionRef MUST NOT be used for core and + extended filters. + + + This filter can be used multiple times within the same rule. + + + Support: Implementation-specific properties: - name: + group: description: |- - Name is the name of the HTTP Header to be matched. Name matching MUST be - case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). - - - If multiple entries specify equivalent header names, the first entry with - an equivalent name MUST be considered for a match. Subsequent entries - with an equivalent header name MUST be ignored. Due to the - case-insensitivity of header names, "foo" and "Foo" are considered - equivalent. - maxLength: 256 + Group is the group of the referent. For example, "gateway.networking.k8s.io". + When unspecified or empty string, core API group is inferred. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + description: Kind is kind of the referent. For example "HTTPRoute" or "Service". + maxLength: 63 minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ type: string - value: - description: Value is the value of HTTP Header to be matched. - maxLength: 4096 + name: + description: Name is the name of the referent. + maxLength: 253 minLength: 1 type: string required: - - name - - value + - group + - kind + - name type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - remove: - description: |- - Remove the given header(s) from the HTTP request before the action. The - value of Remove is a list of HTTP header names. Note that the header - names are case-insensitive (see - https://datatracker.ietf.org/doc/html/rfc2616#section-4.2). - - - Input: - GET /foo HTTP/1.1 - my-header1: foo - my-header2: bar - my-header3: baz - - - Config: - remove: ["my-header1", "my-header3"] - - - Output: - GET /foo HTTP/1.1 - my-header2: bar - items: - type: string - maxItems: 16 - type: array - x-kubernetes-list-type: set - set: - description: |- - Set overwrites the request with the given header (name, value) - before the action. - - - Input: - GET /foo HTTP/1.1 - my-header: foo - - - Config: + requestHeaderModifier: + description: |- + RequestHeaderModifier defines a schema for a filter that modifies request + headers. + + + Support: Core + properties: + add: + description: |- + Add adds the given header(s) (name, value) to the request + before the action. It appends to any existing values associated + with the header name. + + + Input: + GET /foo HTTP/1.1 + my-header: foo + + + Config: + add: + - name: "my-header" + value: "bar,baz" + + + Output: + GET /foo HTTP/1.1 + my-header: foo,bar,baz + items: + description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + + If multiple entries specify equivalent header names, the first entry with + an equivalent name MUST be considered for a match. Subsequent entries + with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + description: Value is the value of HTTP Header to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + remove: + description: |- + Remove the given header(s) from the HTTP request before the action. The + value of Remove is a list of HTTP header names. Note that the header + names are case-insensitive (see + https://datatracker.ietf.org/doc/html/rfc2616#section-4.2). + + + Input: + GET /foo HTTP/1.1 + my-header1: foo + my-header2: bar + my-header3: baz + + + Config: + remove: ["my-header1", "my-header3"] + + + Output: + GET /foo HTTP/1.1 + my-header2: bar + items: + type: string + maxItems: 16 + type: array + x-kubernetes-list-type: set set: - - name: "my-header" - value: "bar" - - - Output: - GET /foo HTTP/1.1 - my-header: bar - items: - description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. + description: |- + Set overwrites the request with the given header (name, value) + before the action. + + + Input: + GET /foo HTTP/1.1 + my-header: foo + + + Config: + set: + - name: "my-header" + value: "bar" + + + Output: + GET /foo HTTP/1.1 + my-header: bar + items: + description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + + If multiple entries specify equivalent header names, the first entry with + an equivalent name MUST be considered for a match. Subsequent entries + with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + description: Value is the value of HTTP Header to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + type: object + requestMirror: + description: |- + RequestMirror defines a schema for a filter that mirrors requests. + Requests are sent to the specified destination, but responses from + that destination are ignored. + + + This filter can be used multiple times within the same rule. Note that + not all implementations will be able to support mirroring to multiple + backends. + + + Support: Extended + + + properties: - name: + backendRef: description: |- - Name is the name of the HTTP Header to be matched. Name matching MUST be - case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). - - - If multiple entries specify equivalent header names, the first entry with - an equivalent name MUST be considered for a match. Subsequent entries - with an equivalent header name MUST be ignored. Due to the - case-insensitivity of header names, "foo" and "Foo" are considered - equivalent. - maxLength: 256 + BackendRef references a resource where mirrored requests are sent. + + + Mirrored requests must be sent only to a single destination endpoint + within this BackendRef, irrespective of how many endpoints are present + within this BackendRef. + + + If the referent cannot be found, this BackendRef is invalid and must be + dropped from the Gateway. The controller must ensure the "ResolvedRefs" + condition on the Route status is set to `status: False` and not configure + this backend in the underlying implementation. + + + If there is a cross-namespace reference to an *existing* object + that is not allowed by a ReferenceGrant, the controller must ensure the + "ResolvedRefs" condition on the Route is set to `status: False`, + with the "RefNotPermitted" reason and not configure this backend in the + underlying implementation. + + + In either error case, the Message of the `ResolvedRefs` Condition + should be used to provide more detail about the problem. + + + Support: Extended for Kubernetes Service + + + Support: Implementation-specific for any other resource + properties: + group: + default: "" + description: |- + Group is the group of the referent. For example, "gateway.networking.k8s.io". + When unspecified or empty string, core API group is inferred. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + default: Service + description: |- + Kind is the Kubernetes resource kind of the referent. For example + "Service". + + + Defaults to "Service" when not specified. + + + ExternalName services can refer to CNAME DNS records that may live + outside of the cluster and as such are difficult to reason about in + terms of conformance. They also may not be safe to forward to (see + CVE-2021-25740 for more information). Implementations SHOULD NOT + support ExternalName Services. + + + Support: Core (Services with a type other than ExternalName) + + + Support: Implementation-specific (Services with type ExternalName) + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: Name is the name of the referent. + maxLength: 253 + minLength: 1 + type: string + namespace: + description: |- + Namespace is the namespace of the backend. When unspecified, the local + namespace is inferred. + + + Note that when a namespace different than the local namespace is specified, + a ReferenceGrant object is required in the referent namespace to allow that + namespace's owner to accept the reference. See the ReferenceGrant + documentation for details. + + + Support: Core + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + port: + description: |- + Port specifies the destination port number to use for this resource. + Port is required when the referent is a Kubernetes Service. In this + case, the port number is the service port number, not the target port. + For other resources, destination port might be derived from the referent + resource or this field. + format: int32 + maximum: 65535 + minimum: 1 + type: integer + required: + - name + type: object + fraction: + description: |- + Fraction represents the fraction of requests that should be + mirrored to BackendRef. + + + Only one of Fraction or Percent may be specified. If neither field + is specified, 100% of requests will be mirrored. + + + + properties: + denominator: + default: 100 + format: int32 + minimum: 1 + type: integer + numerator: + format: int32 + minimum: 0 + type: integer + required: + - numerator + type: object + percent: + description: |- + Percent represents the percentage of requests that should be + mirrored to BackendRef. Its minimum value is 0 (indicating 0% of + requests) and its maximum value is 100 (indicating 100% of requests). + + + Only one of Fraction or Percent may be specified. If neither field + is specified, 100% of requests will be mirrored. + + + + format: int32 + maximum: 100 + minimum: 0 + type: integer + required: + - backendRef + type: object + requestRedirect: + description: |- + RequestRedirect defines a schema for a filter that responds to the + request with an HTTP redirection. + + + Support: Core + properties: + hostname: + description: |- + Hostname is the hostname to be used in the value of the `Location` + header in the response. + When empty, the hostname in the `Host` header of the request is used. + + + Support: Core + maxLength: 253 minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ type: string - value: - description: Value is the value of HTTP Header to be matched. - maxLength: 4096 + path: + description: |- + Path defines parameters used to modify the path of the incoming request. + The modified path is then used to construct the `Location` header. When + empty, the request path is used as-is. + + + Support: Extended + properties: + replaceFullPath: + description: |- + ReplaceFullPath specifies the value with which to replace the full path + of a request during a rewrite or redirect. + maxLength: 1024 + type: string + replacePrefixMatch: + description: |- + ReplacePrefixMatch specifies the value with which to replace the prefix + match of a request during a rewrite or redirect. For example, a request + to "/foo/bar" with a prefix match of "/foo" and a ReplacePrefixMatch + of "/xyz" would be modified to "/xyz/bar". + + + Note that this matches the behavior of the PathPrefix match type. This + matches full path elements. A path element refers to the list of labels + in the path split by the `/` separator. When specified, a trailing `/` is + ignored. For example, the paths `/abc`, `/abc/`, and `/abc/def` would all + match the prefix `/abc`, but the path `/abcd` would not. + + + ReplacePrefixMatch is only compatible with a `PathPrefix` HTTPRouteMatch. + Using any other HTTPRouteMatch type on the same HTTPRouteRule will result in + the implementation setting the Accepted Condition for the Route to `status: False`. + + + Request Path | Prefix Match | Replace Prefix | Modified Path + -------------|--------------|----------------|---------- + /foo/bar | /foo | /xyz | /xyz/bar + /foo/bar | /foo | /xyz/ | /xyz/bar + /foo/bar | /foo/ | /xyz | /xyz/bar + /foo/bar | /foo/ | /xyz/ | /xyz/bar + /foo | /foo | /xyz | /xyz + /foo/ | /foo | /xyz | /xyz/ + /foo/bar | /foo | | /bar + /foo/ | /foo | | / + /foo | /foo | | / + /foo/ | /foo | / | / + /foo | /foo | / | / + maxLength: 1024 + type: string + type: + description: |- + Type defines the type of path modifier. Additional types may be + added in a future release of the API. + + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + enum: + - ReplaceFullPath + - ReplacePrefixMatch + type: string + required: + - type + type: object + port: + description: |- + Port is the port to be used in the value of the `Location` + header in the response. + + + If no port is specified, the redirect port MUST be derived using the + following rules: + + + * If redirect scheme is not-empty, the redirect port MUST be the well-known + port associated with the redirect scheme. Specifically "http" to port 80 + and "https" to port 443. If the redirect scheme does not have a + well-known port, the listener port of the Gateway SHOULD be used. + * If redirect scheme is empty, the redirect port MUST be the Gateway + Listener port. + + + Implementations SHOULD NOT add the port number in the 'Location' + header in the following cases: + + + * A Location header that will use HTTP (whether that is determined via + the Listener protocol or the Scheme field) _and_ use port 80. + * A Location header that will use HTTPS (whether that is determined via + the Listener protocol or the Scheme field) _and_ use port 443. + + + Support: Extended + format: int32 + maximum: 65535 + minimum: 1 + type: integer + scheme: + description: |- + Scheme is the scheme to be used in the value of the `Location` header in + the response. When empty, the scheme of the request is used. + + + Scheme redirects can affect the port of the redirect, for more information, + refer to the documentation for the port field of this filter. + + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + + + Support: Extended + enum: + - http + - https + type: string + statusCode: + default: 302 + description: |- + StatusCode is the HTTP status code to be used in response. + + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + + + Support: Core + enum: + - 301 + - 302 + type: integer + type: object + responseHeaderModifier: + description: |- + ResponseHeaderModifier defines a schema for a filter that modifies response + headers. + + + Support: Extended + properties: + add: + description: |- + Add adds the given header(s) (name, value) to the request + before the action. It appends to any existing values associated + with the header name. + + + Input: + GET /foo HTTP/1.1 + my-header: foo + + + Config: + add: + - name: "my-header" + value: "bar,baz" + + + Output: + GET /foo HTTP/1.1 + my-header: foo,bar,baz + items: + description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + + If multiple entries specify equivalent header names, the first entry with + an equivalent name MUST be considered for a match. Subsequent entries + with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + description: Value is the value of HTTP Header to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + remove: + description: |- + Remove the given header(s) from the HTTP request before the action. The + value of Remove is a list of HTTP header names. Note that the header + names are case-insensitive (see + https://datatracker.ietf.org/doc/html/rfc2616#section-4.2). + + + Input: + GET /foo HTTP/1.1 + my-header1: foo + my-header2: bar + my-header3: baz + + + Config: + remove: ["my-header1", "my-header3"] + + + Output: + GET /foo HTTP/1.1 + my-header2: bar + items: + type: string + maxItems: 16 + type: array + x-kubernetes-list-type: set + set: + description: |- + Set overwrites the request with the given header (name, value) + before the action. + + + Input: + GET /foo HTTP/1.1 + my-header: foo + + + Config: + set: + - name: "my-header" + value: "bar" + + + Output: + GET /foo HTTP/1.1 + my-header: bar + items: + description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + + If multiple entries specify equivalent header names, the first entry with + an equivalent name MUST be considered for a match. Subsequent entries + with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + description: Value is the value of HTTP Header to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + type: object + type: + description: |- + Type identifies the type of filter to apply. As with other API fields, + types are classified into three conformance levels: + + + - Core: Filter types and their corresponding configuration defined by + "Support: Core" in this package, e.g. "RequestHeaderModifier". All + implementations must support core filters. + + + - Extended: Filter types and their corresponding configuration defined by + "Support: Extended" in this package, e.g. "RequestMirror". Implementers + are encouraged to support extended filters. + + + - Implementation-specific: Filters that are defined and supported by + specific vendors. + In the future, filters showing convergence in behavior across multiple + implementations will be considered for inclusion in extended or core + conformance levels. Filter-specific configuration for such filters + is specified using the ExtensionRef field. `Type` should be set to + "ExtensionRef" for custom filters. + + + Implementers are encouraged to define custom implementation types to + extend the core API with implementation-specific behavior. + + + If a reference to a custom filter type cannot be resolved, the filter + MUST NOT be skipped. Instead, requests that would have been processed by + that filter MUST receive a HTTP error response. + + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + enum: + - RequestHeaderModifier + - ResponseHeaderModifier + - RequestMirror + - RequestRedirect + - URLRewrite + - ExtensionRef + type: string + urlRewrite: + description: |- + URLRewrite defines a schema for a filter that modifies a request during forwarding. + + + Support: Extended + properties: + hostname: + description: |- + Hostname is the value to be used to replace the Host header value during + forwarding. + + + Support: Extended + maxLength: 253 minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ type: string - required: - - name - - value + path: + description: |- + Path defines a path rewrite. + + + Support: Extended + properties: + replaceFullPath: + description: |- + ReplaceFullPath specifies the value with which to replace the full path + of a request during a rewrite or redirect. + maxLength: 1024 + type: string + replacePrefixMatch: + description: |- + ReplacePrefixMatch specifies the value with which to replace the prefix + match of a request during a rewrite or redirect. For example, a request + to "/foo/bar" with a prefix match of "/foo" and a ReplacePrefixMatch + of "/xyz" would be modified to "/xyz/bar". + + + Note that this matches the behavior of the PathPrefix match type. This + matches full path elements. A path element refers to the list of labels + in the path split by the `/` separator. When specified, a trailing `/` is + ignored. For example, the paths `/abc`, `/abc/`, and `/abc/def` would all + match the prefix `/abc`, but the path `/abcd` would not. + + + ReplacePrefixMatch is only compatible with a `PathPrefix` HTTPRouteMatch. + Using any other HTTPRouteMatch type on the same HTTPRouteRule will result in + the implementation setting the Accepted Condition for the Route to `status: False`. + + + Request Path | Prefix Match | Replace Prefix | Modified Path + -------------|--------------|----------------|---------- + /foo/bar | /foo | /xyz | /xyz/bar + /foo/bar | /foo | /xyz/ | /xyz/bar + /foo/bar | /foo/ | /xyz | /xyz/bar + /foo/bar | /foo/ | /xyz/ | /xyz/bar + /foo | /foo | /xyz | /xyz + /foo/ | /foo | /xyz | /xyz/ + /foo/bar | /foo | | /bar + /foo/ | /foo | | / + /foo | /foo | | / + /foo/ | /foo | / | / + /foo | /foo | / | / + maxLength: 1024 + type: string + type: + description: |- + Type defines the type of path modifier. Additional types may be + added in a future release of the API. + + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + enum: + - ReplaceFullPath + - ReplacePrefixMatch + type: string + required: + - type + type: object type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - type: object - type: - description: |- - Type identifies the type of filter to apply. As with other API fields, - types are classified into three conformance levels: - - - - Core: Filter types and their corresponding configuration defined by - "Support: Core" in this package, e.g. "RequestHeaderModifier". All - implementations must support core filters. - - - - Extended: Filter types and their corresponding configuration defined by - "Support: Extended" in this package, e.g. "RequestMirror". Implementers - are encouraged to support extended filters. - - - - Implementation-specific: Filters that are defined and supported by - specific vendors. - In the future, filters showing convergence in behavior across multiple - implementations will be considered for inclusion in extended or core - conformance levels. Filter-specific configuration for such filters - is specified using the ExtensionRef field. `Type` should be set to - "ExtensionRef" for custom filters. - - - Implementers are encouraged to define custom implementation types to - extend the core API with implementation-specific behavior. - - - If a reference to a custom filter type cannot be resolved, the filter - MUST NOT be skipped. Instead, requests that would have been processed by - that filter MUST receive a HTTP error response. - - - Note that values may be added to this enum, implementations - must ensure that unknown values will not cause a crash. - - - Unknown values here must result in the implementation setting the - Accepted Condition for the Route to `status: False`, with a - Reason of `UnsupportedValue`. - enum: - - RequestHeaderModifier - - ResponseHeaderModifier - - RequestMirror - - RequestRedirect - - URLRewrite - - ExtensionRef - type: string - urlRewrite: + required: + - type + type: object + maxItems: 16 + type: array + matches: description: |- - URLRewrite defines a schema for a filter that modifies a request during forwarding. - - - Support: Extended - properties: - hostname: - description: |- - Hostname is the value to be used to replace the Host header value during - forwarding. - - - Support: Extended - maxLength: 253 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - path: - description: |- - Path defines a path rewrite. - - - Support: Extended - properties: - replaceFullPath: + Matches define conditions used for matching the rule against incoming + HTTP requests. Each match is independent, i.e. this rule will be matched + if **any** one of the matches is satisfied. + + + For example, take the following matches configuration: + + + ``` + matches: + - path: + value: "/foo" + headers: + - name: "version" + value: "v2" + - path: + value: "/v2/foo" + ``` + + + For a request to match against this rule, a request must satisfy + EITHER of the two conditions: + + + - path prefixed with `/foo` AND contains the header `version: v2` + - path prefix of `/v2/foo` + + + See the documentation for HTTPRouteMatch on how to specify multiple + match conditions that should be ANDed together. + + + If no matches are specified, the default is a prefix + path match on "/", which has the effect of matching every + HTTP request. + + + Proxy or Load Balancer routing configuration generated from HTTPRoutes + MUST prioritize matches based on the following criteria, continuing on + ties. Across all rules specified on applicable Routes, precedence must be + given to the match having: + + + * "Exact" path match. + * "Prefix" path match with largest number of characters. + * Method match. + * Largest number of header matches. + * Largest number of query param matches. + + + Note: The precedence of RegularExpression path matches are implementation-specific. + + + If ties still exist across multiple Routes, matching precedence MUST be + determined in order of the following criteria, continuing on ties: + + + * The oldest Route based on creation timestamp. + * The Route appearing first in alphabetical order by + "{namespace}/{name}". + + + If ties still exist within an HTTPRoute, matching precedence MUST be granted + to the FIRST matching rule (in list order) with a match meeting the above + criteria. + + + When no rules matching a request have been successfully attached to the + parent a request is coming from, a HTTP 404 status code MUST be returned. + items: + properties: + headers: + description: |- + Headers specifies HTTP request header matchers. Multiple match values are + ANDed together, meaning, a request must match all the specified headers + to select the route. + items: description: |- - ReplaceFullPath specifies the value with which to replace the full path - of a request during a rewrite or redirect. - maxLength: 1024 - type: string - replacePrefixMatch: + HTTPHeaderMatch describes how to select a HTTP route by matching HTTP request + headers. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + + If multiple entries specify equivalent header names, only the first + entry with an equivalent name MUST be considered for a match. Subsequent + entries with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + + + When a header is repeated in an HTTP request, it is + implementation-specific behavior as to how this is represented. + Generally, proxies should follow the guidance from the RFC: + https://www.rfc-editor.org/rfc/rfc7230.html#section-3.2.2 regarding + processing a repeated header, with special handling for "Set-Cookie". + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + type: + default: Exact + description: |- + Type specifies how to match against the value of the header. + + + Support: Core (Exact) + + + Support: Implementation-specific (RegularExpression) + + + Since RegularExpression HeaderMatchType has implementation-specific + conformance, implementations can support POSIX, PCRE or any other dialects + of regular expressions. Please read the implementation's documentation to + determine the supported dialect. + enum: + - Exact + - RegularExpression + type: string + value: + description: Value is the value of HTTP Header to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + path: + description: Path specifies a HTTP request path matcher. + properties: + type: + default: PathPrefix + description: |- + Type specifies how to match against the path Value. + + + Support: Core (Exact, PathPrefix) + + + Support: Implementation-specific (RegularExpression) + enum: + - Exact + - PathPrefix + - RegularExpression + type: string + value: + default: / + description: Value of the HTTP path to match against. + maxLength: 1024 + type: string + type: object + queryParams: + description: |- + QueryParams specifies HTTP query parameter matchers. Multiple match + values are ANDed together, meaning, a request must match all the + specified query parameters to select the route. + + + Support: Extended + items: description: |- - ReplacePrefixMatch specifies the value with which to replace the prefix - match of a request during a rewrite or redirect. For example, a request - to "/foo/bar" with a prefix match of "/foo" and a ReplacePrefixMatch - of "/xyz" would be modified to "/xyz/bar". - - - Note that this matches the behavior of the PathPrefix match type. This - matches full path elements. A path element refers to the list of labels - in the path split by the `/` separator. When specified, a trailing `/` is - ignored. For example, the paths `/abc`, `/abc/`, and `/abc/def` would all - match the prefix `/abc`, but the path `/abcd` would not. - - - ReplacePrefixMatch is only compatible with a `PathPrefix` HTTPRouteMatch. - Using any other HTTPRouteMatch type on the same HTTPRouteRule will result in - the implementation setting the Accepted Condition for the Route to `status: False`. - - - Request Path | Prefix Match | Replace Prefix | Modified Path - -------------|--------------|----------------|---------- - /foo/bar | /foo | /xyz | /xyz/bar - /foo/bar | /foo | /xyz/ | /xyz/bar - /foo/bar | /foo/ | /xyz | /xyz/bar - /foo/bar | /foo/ | /xyz/ | /xyz/bar - /foo | /foo | /xyz | /xyz - /foo/ | /foo | /xyz | /xyz/ - /foo/bar | /foo | | /bar - /foo/ | /foo | | / - /foo | /foo | | / - /foo/ | /foo | / | / - /foo | /foo | / | / - maxLength: 1024 + HTTPQueryParamMatch describes how to select a HTTP route by matching HTTP + query parameters. + properties: + name: + description: |- + Name is the name of the HTTP query param to be matched. This must be an + exact string match. (See + https://tools.ietf.org/html/rfc7230#section-2.7.3). + + + If multiple entries specify equivalent query param names, only the first + entry with an equivalent name MUST be considered for a match. Subsequent + entries with an equivalent query param name MUST be ignored. + + + If a query param is repeated in an HTTP request, the behavior is + purposely left undefined, since different data planes have different + capabilities. However, it is *recommended* that implementations should + match against the first value of the param if the data plane supports it, + as this behavior is expected in other load balancing contexts outside of + the Gateway API. + + + Users SHOULD NOT route traffic based on repeated query params to guard + themselves against potential differences in the implementations. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + type: + default: Exact + description: |- + Type specifies how to match against the value of the query parameter. + + + Support: Extended (Exact) + + + Support: Implementation-specific (RegularExpression) + + + Since RegularExpression QueryParamMatchType has Implementation-specific + conformance, implementations can support POSIX, PCRE or any other + dialects of regular expressions. Please read the implementation's + documentation to determine the supported dialect. + enum: + - Exact + - RegularExpression + type: string + value: + description: Value is the value of HTTP query param to be matched. + maxLength: 1024 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + type: object + maxItems: 8 + type: array + type: object + weight: + description: Weight indicate how many percentage of traffic the canary pods should receive + format: int32 + maximum: 100 + minimum: 0 + type: integer + type: object + type: object + required: + - replicas + type: object + type: array + toleration: + description: Toleration is the toleration policy of the canary strategy + properties: + initialDelaySeconds: + description: Number of seconds after the toleration check has started before the task are initiated. + format: int32 + type: integer + taskFailureThreshold: + anyOf: + - type: integer + - type: string + description: |- + FailureThreshold indicates how many failed pods can be tolerated before marking the rollout task as success + If not set, the default value is 0, which means no failed pods can be tolerated + This is a task level threshold. + x-kubernetes-int-or-string: true + workloadTotalFailureThreshold: + anyOf: + - type: integer + - type: string + description: |- + WorkloadFailureThreshold indicates how many failed pods can be tolerated in all upgraded pods of one workload. + The default value is 0, which means no failed pods can be tolerated. + This is a workload level threshold. + x-kubernetes-int-or-string: true + type: object + type: object + batchV2: + description: |- + BatchV2 is the batch strategy for upgrade and operation + Mutually exclusive with Batch. + If specified, Batch must be empty. + properties: + batches: + description: Batches define the order of phases to execute release in canary release + items: + properties: + breakpoint: + description: If set to true, the rollout will be paused before the step starts. + type: boolean + properties: + additionalProperties: + type: string + description: Properties contains additional information for step + type: object + targets: + description: rollout targets defines desired target replicas + items: + properties: + matchTargets: + description: Match defines condition used for matching resource cross clusterset + properties: + names: + description: Names is a list of workload name + items: + description: CrossClusterObjectNameReference contains cluster and name reference to a k8s object + properties: + cluster: + description: Cluster indicates the name of cluster + type: string + name: + description: Name is the resource name + type: string + required: + - name + type: object + type: array + selector: + description: Selector is a label query over a set of resources, in this case resource + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector applies to. type: string - type: + operator: description: |- - Type defines the type of path modifier. Additional types may be - added in a future release of the API. - - - Note that values may be added to this enum, implementations - must ensure that unknown values will not cause a crash. - - - Unknown values here must result in the implementation setting the - Accepted Condition for the Route to `status: False`, with a - Reason of `UnsupportedValue`. - enum: - - ReplaceFullPath - - ReplacePrefixMatch + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array required: - - type + - key + - operator type: object - type: object - required: - - type - type: object - maxItems: 16 - type: array - matches: + type: array + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + type: object + replicaSlidingWindow: + anyOf: + - type: integer + - type: string description: |- - Matches define conditions used for matching the rule against incoming - HTTP requests. Each match is independent, i.e. this rule will be matched - if **any** one of the matches is satisfied. - - - For example, take the following matches configuration: - - - ``` - matches: - - path: - value: "/foo" - headers: - - name: "version" - value: "v2" - - path: - value: "/v2/foo" - ``` - - - For a request to match against this rule, a request must satisfy - EITHER of the two conditions: - - - - path prefixed with `/foo` AND contains the header `version: v2` - - path prefix of `/v2/foo` - - - See the documentation for HTTPRouteMatch on how to specify multiple - match conditions that should be ANDed together. - - - If no matches are specified, the default is a prefix - path match on "/", which has the effect of matching every - HTTP request. - - - Proxy or Load Balancer routing configuration generated from HTTPRoutes - MUST prioritize matches based on the following criteria, continuing on - ties. Across all rules specified on applicable Routes, precedence must be - given to the match having: - - - * "Exact" path match. - * "Prefix" path match with largest number of characters. - * Method match. - * Largest number of header matches. - * Largest number of query param matches. - - - Note: The precedence of RegularExpression path matches are implementation-specific. - - - If ties still exist across multiple Routes, matching precedence MUST be - determined in order of the following criteria, continuing on ties: - - - * The oldest Route based on creation timestamp. - * The Route appearing first in alphabetical order by - "{namespace}/{name}". - - - If ties still exist within an HTTPRoute, matching precedence MUST be granted - to the FIRST matching rule (in list order) with a match meeting the above - criteria. - - - When no rules matching a request have been successfully attached to the - parent a request is coming from, a HTTP 404 status code MUST be returned. - items: - properties: - headers: - description: |- - Headers specifies HTTP request header matchers. Multiple match values are - ANDed together, meaning, a request must match all the specified headers - to select the route. - items: + ReplicaSlidingWindow used to control the number of pods that are allowed to be upgraded in + a sliding window for progressive rollout smoothly. + x-kubernetes-int-or-string: true + replicas: + anyOf: + - type: integer + - type: string + description: Replicas is the replicas of the rollout task, which represents the number of pods to be upgraded + x-kubernetes-int-or-string: true + required: + - replicas + type: object + type: array + traffic: + description: traffic strategy + properties: + http: + properties: + filters: + description: |- + Filters define the filters that are applied to requests that match + this rule. + + + The effects of ordering of multiple behaviors are currently unspecified. + This can change in the future based on feedback during the alpha stage. + + + Conformance-levels at this level are defined based on the type of filter: + + + - ALL core filters MUST be supported by all implementations. + - Implementers are encouraged to support extended filters. + - Implementation-specific custom filters have no API guarantees across + implementations. + + + Specifying the same filter multiple times is not supported unless explicitly + indicated in the filter. + + + All filters are expected to be compatible with each other except for the + URLRewrite and RequestRedirect filters, which may not be combined. If an + implementation can not support other combinations of filters, they must clearly + document that limitation. In cases where incompatible or unsupported + filters are specified and cause the `Accepted` condition to be set to status + `False`, implementations may use the `IncompatibleFilters` reason to specify + this configuration error. + + + Support: Core + items: + description: |- + HTTPRouteFilter defines processing steps that must be completed during the + request or response lifecycle. HTTPRouteFilters are meant as an extension + point to express processing that may be done in Gateway implementations. Some + examples include request or response modification, implementing + authentication strategies, rate-limiting, and traffic shaping. API + guarantee/conformance is defined based on the type of the filter. + properties: + extensionRef: description: |- - HTTPHeaderMatch describes how to select a HTTP route by matching HTTP request - headers. + ExtensionRef is an optional, implementation-specific extension to the + "filter" behavior. For example, resource "myroutefilter" in group + "networking.example.net"). ExtensionRef MUST NOT be used for core and + extended filters. + + + This filter can be used multiple times within the same rule. + + + Support: Implementation-specific properties: - name: + group: description: |- - Name is the name of the HTTP Header to be matched. Name matching MUST be - case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). - - - If multiple entries specify equivalent header names, only the first - entry with an equivalent name MUST be considered for a match. Subsequent - entries with an equivalent header name MUST be ignored. Due to the - case-insensitivity of header names, "foo" and "Foo" are considered - equivalent. - - - When a header is repeated in an HTTP request, it is - implementation-specific behavior as to how this is represented. - Generally, proxies should follow the guidance from the RFC: - https://www.rfc-editor.org/rfc/rfc7230.html#section-3.2.2 regarding - processing a repeated header, with special handling for "Set-Cookie". - maxLength: 256 - minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + Group is the group of the referent. For example, "gateway.networking.k8s.io". + When unspecified or empty string, core API group is inferred. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ type: string - type: - default: Exact - description: |- - Type specifies how to match against the value of the header. - - - Support: Core (Exact) - - - Support: Implementation-specific (RegularExpression) - - - Since RegularExpression HeaderMatchType has implementation-specific - conformance, implementations can support POSIX, PCRE or any other dialects - of regular expressions. Please read the implementation's documentation to - determine the supported dialect. - enum: - - Exact - - RegularExpression + kind: + description: Kind is kind of the referent. For example "HTTPRoute" or "Service". + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ type: string - value: - description: Value is the value of HTTP Header to be matched. - maxLength: 4096 + name: + description: Name is the name of the referent. + maxLength: 253 minLength: 1 type: string required: - - name - - value + - group + - kind + - name type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - path: - description: Path specifies a HTTP request path matcher. - properties: - type: - default: PathPrefix - description: |- - Type specifies how to match against the path Value. - - - Support: Core (Exact, PathPrefix) - - - Support: Implementation-specific (RegularExpression) - enum: - - Exact - - PathPrefix - - RegularExpression - type: string - value: - default: / - description: Value of the HTTP path to match against. - maxLength: 1024 - type: string - type: object - queryParams: - description: |- - QueryParams specifies HTTP query parameter matchers. Multiple match - values are ANDed together, meaning, a request must match all the - specified query parameters to select the route. - - - Support: Extended - items: + requestHeaderModifier: description: |- - HTTPQueryParamMatch describes how to select a HTTP route by matching HTTP - query parameters. + RequestHeaderModifier defines a schema for a filter that modifies request + headers. + + + Support: Core properties: - name: + add: description: |- - Name is the name of the HTTP query param to be matched. This must be an - exact string match. (See - https://tools.ietf.org/html/rfc7230#section-2.7.3). - - - If multiple entries specify equivalent query param names, only the first - entry with an equivalent name MUST be considered for a match. Subsequent - entries with an equivalent query param name MUST be ignored. - - - If a query param is repeated in an HTTP request, the behavior is - purposely left undefined, since different data planes have different - capabilities. However, it is *recommended* that implementations should - match against the first value of the param if the data plane supports it, - as this behavior is expected in other load balancing contexts outside of - the Gateway API. - - - Users SHOULD NOT route traffic based on repeated query params to guard - themselves against potential differences in the implementations. - maxLength: 256 - minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ - type: string - type: - default: Exact - description: |- - Type specifies how to match against the value of the query parameter. - - - Support: Extended (Exact) - - - Support: Implementation-specific (RegularExpression) - - - Since RegularExpression QueryParamMatchType has Implementation-specific - conformance, implementations can support POSIX, PCRE or any other - dialects of regular expressions. Please read the implementation's - documentation to determine the supported dialect. - enum: - - Exact - - RegularExpression - type: string - value: - description: Value is the value of HTTP query param to be matched. - maxLength: 1024 - minLength: 1 - type: string - required: - - name - - value - type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - type: object - maxItems: 8 - type: array - stableTraffic: - description: StableTraffic indicate the base traffic rule - properties: - filters: - description: |- - Filters define the filters that are applied to requests that match - this rule. - - - The effects of ordering of multiple behaviors are currently unspecified. - This can change in the future based on feedback during the alpha stage. - - - Conformance-levels at this level are defined based on the type of filter: - - - - ALL core filters MUST be supported by all implementations. - - Implementers are encouraged to support extended filters. - - Implementation-specific custom filters have no API guarantees across - implementations. - - - Specifying the same filter multiple times is not supported unless explicitly - indicated in the filter. - - - All filters are expected to be compatible with each other except for the - URLRewrite and RequestRedirect filters, which may not be combined. If an - implementation can not support other combinations of filters, they must clearly - document that limitation. In cases where incompatible or unsupported - filters are specified and cause the `Accepted` condition to be set to status - `False`, implementations may use the `IncompatibleFilters` reason to specify - this configuration error. - - - Support: Core - items: - description: |- - HTTPRouteFilter defines processing steps that must be completed during the - request or response lifecycle. HTTPRouteFilters are meant as an extension - point to express processing that may be done in Gateway implementations. Some - examples include request or response modification, implementing - authentication strategies, rate-limiting, and traffic shaping. API - guarantee/conformance is defined based on the type of the filter. - properties: - extensionRef: - description: |- - ExtensionRef is an optional, implementation-specific extension to the - "filter" behavior. For example, resource "myroutefilter" in group - "networking.example.net"). ExtensionRef MUST NOT be used for core and - extended filters. - - - This filter can be used multiple times within the same rule. - - - Support: Implementation-specific - properties: - group: - description: |- - Group is the group of the referent. For example, "gateway.networking.k8s.io". - When unspecified or empty string, core API group is inferred. - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - description: Kind is kind of the referent. For example "HTTPRoute" or "Service". - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - type: string - name: - description: Name is the name of the referent. - maxLength: 253 - minLength: 1 - type: string - required: - - group - - kind - - name - type: object - requestHeaderModifier: - description: |- - RequestHeaderModifier defines a schema for a filter that modifies request - headers. - - - Support: Core - properties: - add: - description: |- - Add adds the given header(s) (name, value) to the request - before the action. It appends to any existing values associated - with the header name. - - - Input: - GET /foo HTTP/1.1 - my-header: foo - - - Config: - add: - - name: "my-header" - value: "bar,baz" - - - Output: - GET /foo HTTP/1.1 - my-header: foo,bar,baz - items: - description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. - properties: - name: - description: |- - Name is the name of the HTTP Header to be matched. Name matching MUST be - case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). - - - If multiple entries specify equivalent header names, the first entry with - an equivalent name MUST be considered for a match. Subsequent entries - with an equivalent header name MUST be ignored. Due to the - case-insensitivity of header names, "foo" and "Foo" are considered - equivalent. - maxLength: 256 - minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ - type: string - value: - description: Value is the value of HTTP Header to be matched. - maxLength: 4096 - minLength: 1 - type: string - required: - - name - - value - type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - remove: - description: |- - Remove the given header(s) from the HTTP request before the action. The - value of Remove is a list of HTTP header names. Note that the header - names are case-insensitive (see - https://datatracker.ietf.org/doc/html/rfc2616#section-4.2). - - - Input: - GET /foo HTTP/1.1 - my-header1: foo - my-header2: bar - my-header3: baz - - - Config: - remove: ["my-header1", "my-header3"] - - - Output: - GET /foo HTTP/1.1 - my-header2: bar - items: - type: string - maxItems: 16 - type: array - x-kubernetes-list-type: set - set: - description: |- - Set overwrites the request with the given header (name, value) - before the action. - - - Input: - GET /foo HTTP/1.1 - my-header: foo - - - Config: - set: - - name: "my-header" - value: "bar" - - - Output: - GET /foo HTTP/1.1 - my-header: bar - items: - description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. - properties: - name: - description: |- - Name is the name of the HTTP Header to be matched. Name matching MUST be - case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). - - - If multiple entries specify equivalent header names, the first entry with - an equivalent name MUST be considered for a match. Subsequent entries - with an equivalent header name MUST be ignored. Due to the - case-insensitivity of header names, "foo" and "Foo" are considered - equivalent. - maxLength: 256 - minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ - type: string - value: - description: Value is the value of HTTP Header to be matched. - maxLength: 4096 - minLength: 1 - type: string - required: - - name - - value - type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - type: object - requestMirror: - description: |- - RequestMirror defines a schema for a filter that mirrors requests. - Requests are sent to the specified destination, but responses from - that destination are ignored. - - - This filter can be used multiple times within the same rule. Note that - not all implementations will be able to support mirroring to multiple - backends. - - - Support: Extended - - - - properties: - backendRef: - description: |- - BackendRef references a resource where mirrored requests are sent. - - - Mirrored requests must be sent only to a single destination endpoint - within this BackendRef, irrespective of how many endpoints are present - within this BackendRef. - - - If the referent cannot be found, this BackendRef is invalid and must be - dropped from the Gateway. The controller must ensure the "ResolvedRefs" - condition on the Route status is set to `status: False` and not configure - this backend in the underlying implementation. - - - If there is a cross-namespace reference to an *existing* object - that is not allowed by a ReferenceGrant, the controller must ensure the - "ResolvedRefs" condition on the Route is set to `status: False`, - with the "RefNotPermitted" reason and not configure this backend in the - underlying implementation. - - - In either error case, the Message of the `ResolvedRefs` Condition - should be used to provide more detail about the problem. - - - Support: Extended for Kubernetes Service - - - Support: Implementation-specific for any other resource + Add adds the given header(s) (name, value) to the request + before the action. It appends to any existing values associated + with the header name. + + + Input: + GET /foo HTTP/1.1 + my-header: foo + + + Config: + add: + - name: "my-header" + value: "bar,baz" + + + Output: + GET /foo HTTP/1.1 + my-header: foo,bar,baz + items: + description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. properties: - group: - default: "" + name: description: |- - Group is the group of the referent. For example, "gateway.networking.k8s.io". - When unspecified or empty string, core API group is inferred. - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + + If multiple entries specify equivalent header names, the first entry with + an equivalent name MUST be considered for a match. Subsequent entries + with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ type: string - kind: - default: Service - description: |- - Kind is the Kubernetes resource kind of the referent. For example - "Service". - - - Defaults to "Service" when not specified. - - - ExternalName services can refer to CNAME DNS records that may live - outside of the cluster and as such are difficult to reason about in - terms of conformance. They also may not be safe to forward to (see - CVE-2021-25740 for more information). Implementations SHOULD NOT - support ExternalName Services. - - - Support: Core (Services with a type other than ExternalName) - - - Support: Implementation-specific (Services with type ExternalName) - maxLength: 63 + value: + description: Value is the value of HTTP Header to be matched. + maxLength: 4096 minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + remove: + description: |- + Remove the given header(s) from the HTTP request before the action. The + value of Remove is a list of HTTP header names. Note that the header + names are case-insensitive (see + https://datatracker.ietf.org/doc/html/rfc2616#section-4.2). + + + Input: + GET /foo HTTP/1.1 + my-header1: foo + my-header2: bar + my-header3: baz + + + Config: + remove: ["my-header1", "my-header3"] + + + Output: + GET /foo HTTP/1.1 + my-header2: bar + items: + type: string + maxItems: 16 + type: array + x-kubernetes-list-type: set + set: + description: |- + Set overwrites the request with the given header (name, value) + before the action. + + + Input: + GET /foo HTTP/1.1 + my-header: foo + + + Config: + set: + - name: "my-header" + value: "bar" + + + Output: + GET /foo HTTP/1.1 + my-header: bar + items: + description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. + properties: name: - description: Name is the name of the referent. - maxLength: 253 + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + + If multiple entries specify equivalent header names, the first entry with + an equivalent name MUST be considered for a match. Subsequent entries + with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + maxLength: 256 minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ type: string - namespace: - description: |- - Namespace is the namespace of the backend. When unspecified, the local - namespace is inferred. - - - Note that when a namespace different than the local namespace is specified, - a ReferenceGrant object is required in the referent namespace to allow that - namespace's owner to accept the reference. See the ReferenceGrant - documentation for details. - - - Support: Core - maxLength: 63 + value: + description: Value is the value of HTTP Header to be matched. + maxLength: 4096 minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ type: string - port: - description: |- - Port specifies the destination port number to use for this resource. - Port is required when the referent is a Kubernetes Service. In this - case, the port number is the service port number, not the target port. - For other resources, destination port might be derived from the referent - resource or this field. - format: int32 - maximum: 65535 - minimum: 1 - type: integer required: - - name + - name + - value type: object - fraction: - description: |- - Fraction represents the fraction of requests that should be - mirrored to BackendRef. - - - Only one of Fraction or Percent may be specified. If neither field - is specified, 100% of requests will be mirrored. - - - - properties: - denominator: - default: 100 - format: int32 - minimum: 1 - type: integer - numerator: - format: int32 - minimum: 0 - type: integer - required: + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + type: object + requestMirror: + description: |- + RequestMirror defines a schema for a filter that mirrors requests. + Requests are sent to the specified destination, but responses from + that destination are ignored. + + + This filter can be used multiple times within the same rule. Note that + not all implementations will be able to support mirroring to multiple + backends. + + + Support: Extended + + + + properties: + backendRef: + description: |- + BackendRef references a resource where mirrored requests are sent. + + + Mirrored requests must be sent only to a single destination endpoint + within this BackendRef, irrespective of how many endpoints are present + within this BackendRef. + + + If the referent cannot be found, this BackendRef is invalid and must be + dropped from the Gateway. The controller must ensure the "ResolvedRefs" + condition on the Route status is set to `status: False` and not configure + this backend in the underlying implementation. + + + If there is a cross-namespace reference to an *existing* object + that is not allowed by a ReferenceGrant, the controller must ensure the + "ResolvedRefs" condition on the Route is set to `status: False`, + with the "RefNotPermitted" reason and not configure this backend in the + underlying implementation. + + + In either error case, the Message of the `ResolvedRefs` Condition + should be used to provide more detail about the problem. + + + Support: Extended for Kubernetes Service + + + Support: Implementation-specific for any other resource + properties: + group: + default: "" + description: |- + Group is the group of the referent. For example, "gateway.networking.k8s.io". + When unspecified or empty string, core API group is inferred. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + default: Service + description: |- + Kind is the Kubernetes resource kind of the referent. For example + "Service". + + + Defaults to "Service" when not specified. + + + ExternalName services can refer to CNAME DNS records that may live + outside of the cluster and as such are difficult to reason about in + terms of conformance. They also may not be safe to forward to (see + CVE-2021-25740 for more information). Implementations SHOULD NOT + support ExternalName Services. + + + Support: Core (Services with a type other than ExternalName) + + + Support: Implementation-specific (Services with type ExternalName) + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: Name is the name of the referent. + maxLength: 253 + minLength: 1 + type: string + namespace: + description: |- + Namespace is the namespace of the backend. When unspecified, the local + namespace is inferred. + + + Note that when a namespace different than the local namespace is specified, + a ReferenceGrant object is required in the referent namespace to allow that + namespace's owner to accept the reference. See the ReferenceGrant + documentation for details. + + + Support: Core + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + port: + description: |- + Port specifies the destination port number to use for this resource. + Port is required when the referent is a Kubernetes Service. In this + case, the port number is the service port number, not the target port. + For other resources, destination port might be derived from the referent + resource or this field. + format: int32 + maximum: 65535 + minimum: 1 + type: integer + required: + - name + type: object + fraction: + description: |- + Fraction represents the fraction of requests that should be + mirrored to BackendRef. + + + Only one of Fraction or Percent may be specified. If neither field + is specified, 100% of requests will be mirrored. + + + + properties: + denominator: + default: 100 + format: int32 + minimum: 1 + type: integer + numerator: + format: int32 + minimum: 0 + type: integer + required: - numerator - type: object - percent: - description: |- - Percent represents the percentage of requests that should be - mirrored to BackendRef. Its minimum value is 0 (indicating 0% of - requests) and its maximum value is 100 (indicating 100% of requests). - - - Only one of Fraction or Percent may be specified. If neither field - is specified, 100% of requests will be mirrored. - - - - format: int32 - maximum: 100 - minimum: 0 - type: integer - required: + type: object + percent: + description: |- + Percent represents the percentage of requests that should be + mirrored to BackendRef. Its minimum value is 0 (indicating 0% of + requests) and its maximum value is 100 (indicating 100% of requests). + + + Only one of Fraction or Percent may be specified. If neither field + is specified, 100% of requests will be mirrored. + + + + format: int32 + maximum: 100 + minimum: 0 + type: integer + required: - backendRef - type: object - requestRedirect: - description: |- - RequestRedirect defines a schema for a filter that responds to the - request with an HTTP redirection. - - - Support: Core - properties: - hostname: - description: |- - Hostname is the hostname to be used in the value of the `Location` - header in the response. - When empty, the hostname in the `Host` header of the request is used. - - - Support: Core - maxLength: 253 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - path: - description: |- - Path defines parameters used to modify the path of the incoming request. - The modified path is then used to construct the `Location` header. When - empty, the request path is used as-is. - - - Support: Extended + type: object + requestRedirect: + description: |- + RequestRedirect defines a schema for a filter that responds to the + request with an HTTP redirection. + + + Support: Core + properties: + hostname: + description: |- + Hostname is the hostname to be used in the value of the `Location` + header in the response. + When empty, the hostname in the `Host` header of the request is used. + + + Support: Core + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + path: + description: |- + Path defines parameters used to modify the path of the incoming request. + The modified path is then used to construct the `Location` header. When + empty, the request path is used as-is. + + + Support: Extended + properties: + replaceFullPath: + description: |- + ReplaceFullPath specifies the value with which to replace the full path + of a request during a rewrite or redirect. + maxLength: 1024 + type: string + replacePrefixMatch: + description: |- + ReplacePrefixMatch specifies the value with which to replace the prefix + match of a request during a rewrite or redirect. For example, a request + to "/foo/bar" with a prefix match of "/foo" and a ReplacePrefixMatch + of "/xyz" would be modified to "/xyz/bar". + + + Note that this matches the behavior of the PathPrefix match type. This + matches full path elements. A path element refers to the list of labels + in the path split by the `/` separator. When specified, a trailing `/` is + ignored. For example, the paths `/abc`, `/abc/`, and `/abc/def` would all + match the prefix `/abc`, but the path `/abcd` would not. + + + ReplacePrefixMatch is only compatible with a `PathPrefix` HTTPRouteMatch. + Using any other HTTPRouteMatch type on the same HTTPRouteRule will result in + the implementation setting the Accepted Condition for the Route to `status: False`. + + + Request Path | Prefix Match | Replace Prefix | Modified Path + -------------|--------------|----------------|---------- + /foo/bar | /foo | /xyz | /xyz/bar + /foo/bar | /foo | /xyz/ | /xyz/bar + /foo/bar | /foo/ | /xyz | /xyz/bar + /foo/bar | /foo/ | /xyz/ | /xyz/bar + /foo | /foo | /xyz | /xyz + /foo/ | /foo | /xyz | /xyz/ + /foo/bar | /foo | | /bar + /foo/ | /foo | | / + /foo | /foo | | / + /foo/ | /foo | / | / + /foo | /foo | / | / + maxLength: 1024 + type: string + type: + description: |- + Type defines the type of path modifier. Additional types may be + added in a future release of the API. + + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + enum: + - ReplaceFullPath + - ReplacePrefixMatch + type: string + required: + - type + type: object + port: + description: |- + Port is the port to be used in the value of the `Location` + header in the response. + + + If no port is specified, the redirect port MUST be derived using the + following rules: + + + * If redirect scheme is not-empty, the redirect port MUST be the well-known + port associated with the redirect scheme. Specifically "http" to port 80 + and "https" to port 443. If the redirect scheme does not have a + well-known port, the listener port of the Gateway SHOULD be used. + * If redirect scheme is empty, the redirect port MUST be the Gateway + Listener port. + + + Implementations SHOULD NOT add the port number in the 'Location' + header in the following cases: + + + * A Location header that will use HTTP (whether that is determined via + the Listener protocol or the Scheme field) _and_ use port 80. + * A Location header that will use HTTPS (whether that is determined via + the Listener protocol or the Scheme field) _and_ use port 443. + + + Support: Extended + format: int32 + maximum: 65535 + minimum: 1 + type: integer + scheme: + description: |- + Scheme is the scheme to be used in the value of the `Location` header in + the response. When empty, the scheme of the request is used. + + + Scheme redirects can affect the port of the redirect, for more information, + refer to the documentation for the port field of this filter. + + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + + + Support: Extended + enum: + - http + - https + type: string + statusCode: + default: 302 + description: |- + StatusCode is the HTTP status code to be used in response. + + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + + + Support: Core + enum: + - 301 + - 302 + type: integer + type: object + responseHeaderModifier: + description: |- + ResponseHeaderModifier defines a schema for a filter that modifies response + headers. + + + Support: Extended + properties: + add: + description: |- + Add adds the given header(s) (name, value) to the request + before the action. It appends to any existing values associated + with the header name. + + + Input: + GET /foo HTTP/1.1 + my-header: foo + + + Config: + add: + - name: "my-header" + value: "bar,baz" + + + Output: + GET /foo HTTP/1.1 + my-header: foo,bar,baz + items: + description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. properties: - replaceFullPath: + name: description: |- - ReplaceFullPath specifies the value with which to replace the full path - of a request during a rewrite or redirect. - maxLength: 1024 + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + + If multiple entries specify equivalent header names, the first entry with + an equivalent name MUST be considered for a match. Subsequent entries + with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ type: string - replacePrefixMatch: - description: |- - ReplacePrefixMatch specifies the value with which to replace the prefix - match of a request during a rewrite or redirect. For example, a request - to "/foo/bar" with a prefix match of "/foo" and a ReplacePrefixMatch - of "/xyz" would be modified to "/xyz/bar". - - - Note that this matches the behavior of the PathPrefix match type. This - matches full path elements. A path element refers to the list of labels - in the path split by the `/` separator. When specified, a trailing `/` is - ignored. For example, the paths `/abc`, `/abc/`, and `/abc/def` would all - match the prefix `/abc`, but the path `/abcd` would not. - - - ReplacePrefixMatch is only compatible with a `PathPrefix` HTTPRouteMatch. - Using any other HTTPRouteMatch type on the same HTTPRouteRule will result in - the implementation setting the Accepted Condition for the Route to `status: False`. - - - Request Path | Prefix Match | Replace Prefix | Modified Path - -------------|--------------|----------------|---------- - /foo/bar | /foo | /xyz | /xyz/bar - /foo/bar | /foo | /xyz/ | /xyz/bar - /foo/bar | /foo/ | /xyz | /xyz/bar - /foo/bar | /foo/ | /xyz/ | /xyz/bar - /foo | /foo | /xyz | /xyz - /foo/ | /foo | /xyz | /xyz/ - /foo/bar | /foo | | /bar - /foo/ | /foo | | / - /foo | /foo | | / - /foo/ | /foo | / | / - /foo | /foo | / | / - maxLength: 1024 + value: + description: Value is the value of HTTP Header to be matched. + maxLength: 4096 + minLength: 1 type: string - type: + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + remove: + description: |- + Remove the given header(s) from the HTTP request before the action. The + value of Remove is a list of HTTP header names. Note that the header + names are case-insensitive (see + https://datatracker.ietf.org/doc/html/rfc2616#section-4.2). + + + Input: + GET /foo HTTP/1.1 + my-header1: foo + my-header2: bar + my-header3: baz + + + Config: + remove: ["my-header1", "my-header3"] + + + Output: + GET /foo HTTP/1.1 + my-header2: bar + items: + type: string + maxItems: 16 + type: array + x-kubernetes-list-type: set + set: + description: |- + Set overwrites the request with the given header (name, value) + before the action. + + + Input: + GET /foo HTTP/1.1 + my-header: foo + + + Config: + set: + - name: "my-header" + value: "bar" + + + Output: + GET /foo HTTP/1.1 + my-header: bar + items: + description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. + properties: + name: description: |- - Type defines the type of path modifier. Additional types may be - added in a future release of the API. - - - Note that values may be added to this enum, implementations - must ensure that unknown values will not cause a crash. - - - Unknown values here must result in the implementation setting the - Accepted Condition for the Route to `status: False`, with a - Reason of `UnsupportedValue`. - enum: - - ReplaceFullPath - - ReplacePrefixMatch + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + + If multiple entries specify equivalent header names, the first entry with + an equivalent name MUST be considered for a match. Subsequent entries + with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + description: Value is the value of HTTP Header to be matched. + maxLength: 4096 + minLength: 1 type: string required: - - type + - name + - value type: object - port: - description: |- - Port is the port to be used in the value of the `Location` - header in the response. - - - If no port is specified, the redirect port MUST be derived using the - following rules: - - - * If redirect scheme is not-empty, the redirect port MUST be the well-known - port associated with the redirect scheme. Specifically "http" to port 80 - and "https" to port 443. If the redirect scheme does not have a - well-known port, the listener port of the Gateway SHOULD be used. - * If redirect scheme is empty, the redirect port MUST be the Gateway - Listener port. - - - Implementations SHOULD NOT add the port number in the 'Location' - header in the following cases: - - - * A Location header that will use HTTP (whether that is determined via - the Listener protocol or the Scheme field) _and_ use port 80. - * A Location header that will use HTTPS (whether that is determined via - the Listener protocol or the Scheme field) _and_ use port 443. - - - Support: Extended - format: int32 - maximum: 65535 - minimum: 1 - type: integer - scheme: - description: |- - Scheme is the scheme to be used in the value of the `Location` header in - the response. When empty, the scheme of the request is used. - - - Scheme redirects can affect the port of the redirect, for more information, - refer to the documentation for the port field of this filter. - - - Note that values may be added to this enum, implementations - must ensure that unknown values will not cause a crash. - - - Unknown values here must result in the implementation setting the - Accepted Condition for the Route to `status: False`, with a - Reason of `UnsupportedValue`. - - - Support: Extended - enum: - - http - - https - type: string - statusCode: - default: 302 - description: |- - StatusCode is the HTTP status code to be used in response. - - - Note that values may be added to this enum, implementations - must ensure that unknown values will not cause a crash. - - - Unknown values here must result in the implementation setting the - Accepted Condition for the Route to `status: False`, with a - Reason of `UnsupportedValue`. - - - Support: Core - enum: - - 301 - - 302 - type: integer - type: object - responseHeaderModifier: - description: |- - ResponseHeaderModifier defines a schema for a filter that modifies response - headers. - - - Support: Extended - properties: - add: - description: |- - Add adds the given header(s) (name, value) to the request - before the action. It appends to any existing values associated - with the header name. - - - Input: - GET /foo HTTP/1.1 - my-header: foo - - - Config: - add: - - name: "my-header" - value: "bar,baz" - - - Output: - GET /foo HTTP/1.1 - my-header: foo,bar,baz - items: - description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. - properties: - name: - description: |- - Name is the name of the HTTP Header to be matched. Name matching MUST be - case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). - - - If multiple entries specify equivalent header names, the first entry with - an equivalent name MUST be considered for a match. Subsequent entries - with an equivalent header name MUST be ignored. Due to the - case-insensitivity of header names, "foo" and "Foo" are considered - equivalent. - maxLength: 256 - minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ - type: string - value: - description: Value is the value of HTTP Header to be matched. - maxLength: 4096 - minLength: 1 - type: string - required: - - name - - value - type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - remove: - description: |- - Remove the given header(s) from the HTTP request before the action. The - value of Remove is a list of HTTP header names. Note that the header - names are case-insensitive (see - https://datatracker.ietf.org/doc/html/rfc2616#section-4.2). - - - Input: - GET /foo HTTP/1.1 - my-header1: foo - my-header2: bar - my-header3: baz - - - Config: - remove: ["my-header1", "my-header3"] - - - Output: - GET /foo HTTP/1.1 - my-header2: bar - items: - type: string - maxItems: 16 - type: array - x-kubernetes-list-type: set - set: - description: |- - Set overwrites the request with the given header (name, value) - before the action. - - - Input: - GET /foo HTTP/1.1 - my-header: foo - - - Config: - set: - - name: "my-header" - value: "bar" - - - Output: - GET /foo HTTP/1.1 - my-header: bar - items: - description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. - properties: - name: - description: |- - Name is the name of the HTTP Header to be matched. Name matching MUST be - case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). - - - If multiple entries specify equivalent header names, the first entry with - an equivalent name MUST be considered for a match. Subsequent entries - with an equivalent header name MUST be ignored. Due to the - case-insensitivity of header names, "foo" and "Foo" are considered - equivalent. - maxLength: 256 - minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ - type: string - value: - description: Value is the value of HTTP Header to be matched. - maxLength: 4096 - minLength: 1 - type: string - required: - - name - - value - type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: + maxItems: 16 + type: array + x-kubernetes-list-map-keys: - name - x-kubernetes-list-type: map - type: object - type: - description: |- - Type identifies the type of filter to apply. As with other API fields, - types are classified into three conformance levels: - - - - Core: Filter types and their corresponding configuration defined by - "Support: Core" in this package, e.g. "RequestHeaderModifier". All - implementations must support core filters. - - - - Extended: Filter types and their corresponding configuration defined by - "Support: Extended" in this package, e.g. "RequestMirror". Implementers - are encouraged to support extended filters. - - - - Implementation-specific: Filters that are defined and supported by - specific vendors. - In the future, filters showing convergence in behavior across multiple - implementations will be considered for inclusion in extended or core - conformance levels. Filter-specific configuration for such filters - is specified using the ExtensionRef field. `Type` should be set to - "ExtensionRef" for custom filters. - - - Implementers are encouraged to define custom implementation types to - extend the core API with implementation-specific behavior. - - - If a reference to a custom filter type cannot be resolved, the filter - MUST NOT be skipped. Instead, requests that would have been processed by - that filter MUST receive a HTTP error response. - - - Note that values may be added to this enum, implementations - must ensure that unknown values will not cause a crash. - - - Unknown values here must result in the implementation setting the - Accepted Condition for the Route to `status: False`, with a - Reason of `UnsupportedValue`. - enum: + x-kubernetes-list-type: map + type: object + type: + description: |- + Type identifies the type of filter to apply. As with other API fields, + types are classified into three conformance levels: + + + - Core: Filter types and their corresponding configuration defined by + "Support: Core" in this package, e.g. "RequestHeaderModifier". All + implementations must support core filters. + + + - Extended: Filter types and their corresponding configuration defined by + "Support: Extended" in this package, e.g. "RequestMirror". Implementers + are encouraged to support extended filters. + + + - Implementation-specific: Filters that are defined and supported by + specific vendors. + In the future, filters showing convergence in behavior across multiple + implementations will be considered for inclusion in extended or core + conformance levels. Filter-specific configuration for such filters + is specified using the ExtensionRef field. `Type` should be set to + "ExtensionRef" for custom filters. + + + Implementers are encouraged to define custom implementation types to + extend the core API with implementation-specific behavior. + + + If a reference to a custom filter type cannot be resolved, the filter + MUST NOT be skipped. Instead, requests that would have been processed by + that filter MUST receive a HTTP error response. + + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + enum: - RequestHeaderModifier - ResponseHeaderModifier - RequestMirror - RequestRedirect - URLRewrite - ExtensionRef - type: string - urlRewrite: - description: |- - URLRewrite defines a schema for a filter that modifies a request during forwarding. - - - Support: Extended - properties: - hostname: - description: |- - Hostname is the value to be used to replace the Host header value during - forwarding. - - - Support: Extended - maxLength: 253 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - path: - description: |- - Path defines a path rewrite. - - - Support: Extended - properties: - replaceFullPath: - description: |- - ReplaceFullPath specifies the value with which to replace the full path - of a request during a rewrite or redirect. - maxLength: 1024 - type: string - replacePrefixMatch: - description: |- - ReplacePrefixMatch specifies the value with which to replace the prefix - match of a request during a rewrite or redirect. For example, a request - to "/foo/bar" with a prefix match of "/foo" and a ReplacePrefixMatch - of "/xyz" would be modified to "/xyz/bar". - - - Note that this matches the behavior of the PathPrefix match type. This - matches full path elements. A path element refers to the list of labels - in the path split by the `/` separator. When specified, a trailing `/` is - ignored. For example, the paths `/abc`, `/abc/`, and `/abc/def` would all - match the prefix `/abc`, but the path `/abcd` would not. - - - ReplacePrefixMatch is only compatible with a `PathPrefix` HTTPRouteMatch. - Using any other HTTPRouteMatch type on the same HTTPRouteRule will result in - the implementation setting the Accepted Condition for the Route to `status: False`. - - - Request Path | Prefix Match | Replace Prefix | Modified Path - -------------|--------------|----------------|---------- - /foo/bar | /foo | /xyz | /xyz/bar - /foo/bar | /foo | /xyz/ | /xyz/bar - /foo/bar | /foo/ | /xyz | /xyz/bar - /foo/bar | /foo/ | /xyz/ | /xyz/bar - /foo | /foo | /xyz | /xyz - /foo/ | /foo | /xyz | /xyz/ - /foo/bar | /foo | | /bar - /foo/ | /foo | | / - /foo | /foo | | / - /foo/ | /foo | / | / - /foo | /foo | / | / - maxLength: 1024 - type: string - type: - description: |- - Type defines the type of path modifier. Additional types may be - added in a future release of the API. - - - Note that values may be added to this enum, implementations - must ensure that unknown values will not cause a crash. - - - Unknown values here must result in the implementation setting the - Accepted Condition for the Route to `status: False`, with a - Reason of `UnsupportedValue`. - enum: - - ReplaceFullPath - - ReplacePrefixMatch - type: string - required: - - type - type: object - type: object - required: - - type - type: object - maxItems: 16 - type: array - matches: - description: |- - Matches define conditions used for matching the rule against incoming - HTTP requests. Each match is independent, i.e. this rule will be matched - if **any** one of the matches is satisfied. - - - For example, take the following matches configuration: - - - ``` - matches: - - path: - value: "/foo" - headers: - - name: "version" - value: "v2" - - path: - value: "/v2/foo" - ``` - - - For a request to match against this rule, a request must satisfy - EITHER of the two conditions: - - - - path prefixed with `/foo` AND contains the header `version: v2` - - path prefix of `/v2/foo` - - - See the documentation for HTTPRouteMatch on how to specify multiple - match conditions that should be ANDed together. - - - If no matches are specified, the default is a prefix - path match on "/", which has the effect of matching every - HTTP request. - - - Proxy or Load Balancer routing configuration generated from HTTPRoutes - MUST prioritize matches based on the following criteria, continuing on - ties. Across all rules specified on applicable Routes, precedence must be - given to the match having: - - - * "Exact" path match. - * "Prefix" path match with largest number of characters. - * Method match. - * Largest number of header matches. - * Largest number of query param matches. - - - Note: The precedence of RegularExpression path matches are implementation-specific. - - - If ties still exist across multiple Routes, matching precedence MUST be - determined in order of the following criteria, continuing on ties: - - - * The oldest Route based on creation timestamp. - * The Route appearing first in alphabetical order by - "{namespace}/{name}". - - - If ties still exist within an HTTPRoute, matching precedence MUST be granted - to the FIRST matching rule (in list order) with a match meeting the above - criteria. - - - When no rules matching a request have been successfully attached to the - parent a request is coming from, a HTTP 404 status code MUST be returned. - items: - properties: - headers: - description: |- - Headers specifies HTTP request header matchers. Multiple match values are - ANDed together, meaning, a request must match all the specified headers - to select the route. - items: + type: string + urlRewrite: + description: |- + URLRewrite defines a schema for a filter that modifies a request during forwarding. + + + Support: Extended + properties: + hostname: description: |- - HTTPHeaderMatch describes how to select a HTTP route by matching HTTP request - headers. + Hostname is the value to be used to replace the Host header value during + forwarding. + + + Support: Extended + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + path: + description: |- + Path defines a path rewrite. + + + Support: Extended properties: - name: + replaceFullPath: description: |- - Name is the name of the HTTP Header to be matched. Name matching MUST be - case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). - - - If multiple entries specify equivalent header names, only the first - entry with an equivalent name MUST be considered for a match. Subsequent - entries with an equivalent header name MUST be ignored. Due to the - case-insensitivity of header names, "foo" and "Foo" are considered - equivalent. - - - When a header is repeated in an HTTP request, it is - implementation-specific behavior as to how this is represented. - Generally, proxies should follow the guidance from the RFC: - https://www.rfc-editor.org/rfc/rfc7230.html#section-3.2.2 regarding - processing a repeated header, with special handling for "Set-Cookie". - maxLength: 256 - minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + ReplaceFullPath specifies the value with which to replace the full path + of a request during a rewrite or redirect. + maxLength: 1024 + type: string + replacePrefixMatch: + description: |- + ReplacePrefixMatch specifies the value with which to replace the prefix + match of a request during a rewrite or redirect. For example, a request + to "/foo/bar" with a prefix match of "/foo" and a ReplacePrefixMatch + of "/xyz" would be modified to "/xyz/bar". + + + Note that this matches the behavior of the PathPrefix match type. This + matches full path elements. A path element refers to the list of labels + in the path split by the `/` separator. When specified, a trailing `/` is + ignored. For example, the paths `/abc`, `/abc/`, and `/abc/def` would all + match the prefix `/abc`, but the path `/abcd` would not. + + + ReplacePrefixMatch is only compatible with a `PathPrefix` HTTPRouteMatch. + Using any other HTTPRouteMatch type on the same HTTPRouteRule will result in + the implementation setting the Accepted Condition for the Route to `status: False`. + + + Request Path | Prefix Match | Replace Prefix | Modified Path + -------------|--------------|----------------|---------- + /foo/bar | /foo | /xyz | /xyz/bar + /foo/bar | /foo | /xyz/ | /xyz/bar + /foo/bar | /foo/ | /xyz | /xyz/bar + /foo/bar | /foo/ | /xyz/ | /xyz/bar + /foo | /foo | /xyz | /xyz + /foo/ | /foo | /xyz | /xyz/ + /foo/bar | /foo | | /bar + /foo/ | /foo | | / + /foo | /foo | | / + /foo/ | /foo | / | / + /foo | /foo | / | / + maxLength: 1024 type: string type: - default: Exact description: |- - Type specifies how to match against the value of the header. - - - Support: Core (Exact) - - - Support: Implementation-specific (RegularExpression) - - - Since RegularExpression HeaderMatchType has implementation-specific - conformance, implementations can support POSIX, PCRE or any other dialects - of regular expressions. Please read the implementation's documentation to - determine the supported dialect. + Type defines the type of path modifier. Additional types may be + added in a future release of the API. + + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. enum: - - Exact - - RegularExpression - type: string - value: - description: Value is the value of HTTP Header to be matched. - maxLength: 4096 - minLength: 1 + - ReplaceFullPath + - ReplacePrefixMatch type: string required: - - name - - value + - type type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - path: - description: Path specifies a HTTP request path matcher. + type: object + required: + - type + type: object + maxItems: 16 + type: array + matches: + description: |- + Matches define conditions used for matching the rule against incoming + HTTP requests. Each match is independent, i.e. this rule will be matched + if **any** one of the matches is satisfied. + + + For example, take the following matches configuration: + + + ``` + matches: + - path: + value: "/foo" + headers: + - name: "version" + value: "v2" + - path: + value: "/v2/foo" + ``` + + + For a request to match against this rule, a request must satisfy + EITHER of the two conditions: + + + - path prefixed with `/foo` AND contains the header `version: v2` + - path prefix of `/v2/foo` + + + See the documentation for HTTPRouteMatch on how to specify multiple + match conditions that should be ANDed together. + + + If no matches are specified, the default is a prefix + path match on "/", which has the effect of matching every + HTTP request. + + + Proxy or Load Balancer routing configuration generated from HTTPRoutes + MUST prioritize matches based on the following criteria, continuing on + ties. Across all rules specified on applicable Routes, precedence must be + given to the match having: + + + * "Exact" path match. + * "Prefix" path match with largest number of characters. + * Method match. + * Largest number of header matches. + * Largest number of query param matches. + + + Note: The precedence of RegularExpression path matches are implementation-specific. + + + If ties still exist across multiple Routes, matching precedence MUST be + determined in order of the following criteria, continuing on ties: + + + * The oldest Route based on creation timestamp. + * The Route appearing first in alphabetical order by + "{namespace}/{name}". + + + If ties still exist within an HTTPRoute, matching precedence MUST be granted + to the FIRST matching rule (in list order) with a match meeting the above + criteria. + + + When no rules matching a request have been successfully attached to the + parent a request is coming from, a HTTP 404 status code MUST be returned. + items: + properties: + headers: + description: |- + Headers specifies HTTP request header matchers. Multiple match values are + ANDed together, meaning, a request must match all the specified headers + to select the route. + items: + description: |- + HTTPHeaderMatch describes how to select a HTTP route by matching HTTP request + headers. properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + + If multiple entries specify equivalent header names, only the first + entry with an equivalent name MUST be considered for a match. Subsequent + entries with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + + + When a header is repeated in an HTTP request, it is + implementation-specific behavior as to how this is represented. + Generally, proxies should follow the guidance from the RFC: + https://www.rfc-editor.org/rfc/rfc7230.html#section-3.2.2 regarding + processing a repeated header, with special handling for "Set-Cookie". + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string type: - default: PathPrefix + default: Exact description: |- - Type specifies how to match against the path Value. - - - Support: Core (Exact, PathPrefix) - - + Type specifies how to match against the value of the header. + + + Support: Core (Exact) + + Support: Implementation-specific (RegularExpression) + + + Since RegularExpression HeaderMatchType has implementation-specific + conformance, implementations can support POSIX, PCRE or any other dialects + of regular expressions. Please read the implementation's documentation to + determine the supported dialect. enum: + - Exact + - RegularExpression + type: string + value: + description: Value is the value of HTTP Header to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + path: + description: Path specifies a HTTP request path matcher. + properties: + type: + default: PathPrefix + description: |- + Type specifies how to match against the path Value. + + + Support: Core (Exact, PathPrefix) + + + Support: Implementation-specific (RegularExpression) + enum: - Exact - PathPrefix - RegularExpression + type: string + value: + default: / + description: Value of the HTTP path to match against. + maxLength: 1024 + type: string + type: object + queryParams: + description: |- + QueryParams specifies HTTP query parameter matchers. Multiple match + values are ANDed together, meaning, a request must match all the + specified query parameters to select the route. + + + Support: Extended + items: + description: |- + HTTPQueryParamMatch describes how to select a HTTP route by matching HTTP + query parameters. + properties: + name: + description: |- + Name is the name of the HTTP query param to be matched. This must be an + exact string match. (See + https://tools.ietf.org/html/rfc7230#section-2.7.3). + + + If multiple entries specify equivalent query param names, only the first + entry with an equivalent name MUST be considered for a match. Subsequent + entries with an equivalent query param name MUST be ignored. + + + If a query param is repeated in an HTTP request, the behavior is + purposely left undefined, since different data planes have different + capabilities. However, it is *recommended* that implementations should + match against the first value of the param if the data plane supports it, + as this behavior is expected in other load balancing contexts outside of + the Gateway API. + + + Users SHOULD NOT route traffic based on repeated query params to guard + themselves against potential differences in the implementations. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + type: + default: Exact + description: |- + Type specifies how to match against the value of the query parameter. + + + Support: Extended (Exact) + + + Support: Implementation-specific (RegularExpression) + + + Since RegularExpression QueryParamMatchType has Implementation-specific + conformance, implementations can support POSIX, PCRE or any other + dialects of regular expressions. Please read the implementation's + documentation to determine the supported dialect. + enum: + - Exact + - RegularExpression type: string value: - default: / - description: Value of the HTTP path to match against. + description: Value is the value of HTTP query param to be matched. maxLength: 1024 + minLength: 1 type: string + required: + - name + - value type: object - queryParams: - description: |- - QueryParams specifies HTTP query parameter matchers. Multiple match - values are ANDed together, meaning, a request must match all the - specified query parameters to select the route. - - - Support: Extended - items: + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + type: object + maxItems: 8 + type: array + stableTraffic: + description: StableTraffic indicate the base traffic rule + properties: + filters: + description: |- + Filters define the filters that are applied to requests that match + this rule. + + + The effects of ordering of multiple behaviors are currently unspecified. + This can change in the future based on feedback during the alpha stage. + + + Conformance-levels at this level are defined based on the type of filter: + + + - ALL core filters MUST be supported by all implementations. + - Implementers are encouraged to support extended filters. + - Implementation-specific custom filters have no API guarantees across + implementations. + + + Specifying the same filter multiple times is not supported unless explicitly + indicated in the filter. + + + All filters are expected to be compatible with each other except for the + URLRewrite and RequestRedirect filters, which may not be combined. If an + implementation can not support other combinations of filters, they must clearly + document that limitation. In cases where incompatible or unsupported + filters are specified and cause the `Accepted` condition to be set to status + `False`, implementations may use the `IncompatibleFilters` reason to specify + this configuration error. + + + Support: Core + items: + description: |- + HTTPRouteFilter defines processing steps that must be completed during the + request or response lifecycle. HTTPRouteFilters are meant as an extension + point to express processing that may be done in Gateway implementations. Some + examples include request or response modification, implementing + authentication strategies, rate-limiting, and traffic shaping. API + guarantee/conformance is defined based on the type of the filter. + properties: + extensionRef: description: |- - HTTPQueryParamMatch describes how to select a HTTP route by matching HTTP - query parameters. + ExtensionRef is an optional, implementation-specific extension to the + "filter" behavior. For example, resource "myroutefilter" in group + "networking.example.net"). ExtensionRef MUST NOT be used for core and + extended filters. + + + This filter can be used multiple times within the same rule. + + + Support: Implementation-specific properties: - name: + group: description: |- - Name is the name of the HTTP query param to be matched. This must be an - exact string match. (See - https://tools.ietf.org/html/rfc7230#section-2.7.3). - - - If multiple entries specify equivalent query param names, only the first - entry with an equivalent name MUST be considered for a match. Subsequent - entries with an equivalent query param name MUST be ignored. - - - If a query param is repeated in an HTTP request, the behavior is - purposely left undefined, since different data planes have different - capabilities. However, it is *recommended* that implementations should - match against the first value of the param if the data plane supports it, - as this behavior is expected in other load balancing contexts outside of - the Gateway API. - - - Users SHOULD NOT route traffic based on repeated query params to guard - themselves against potential differences in the implementations. - maxLength: 256 - minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + Group is the group of the referent. For example, "gateway.networking.k8s.io". + When unspecified or empty string, core API group is inferred. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ type: string - type: - default: Exact - description: |- - Type specifies how to match against the value of the query parameter. - - - Support: Extended (Exact) - - - Support: Implementation-specific (RegularExpression) - - - Since RegularExpression QueryParamMatchType has Implementation-specific - conformance, implementations can support POSIX, PCRE or any other - dialects of regular expressions. Please read the implementation's - documentation to determine the supported dialect. - enum: - - Exact - - RegularExpression + kind: + description: Kind is kind of the referent. For example "HTTPRoute" or "Service". + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ type: string - value: - description: Value is the value of HTTP query param to be matched. - maxLength: 1024 + name: + description: Name is the name of the referent. + maxLength: 253 minLength: 1 type: string required: - - name - - value + - group + - kind + - name type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - type: object - maxItems: 8 - type: array - type: object - weight: - description: Weight indicate how many percentage of traffic the canary pods should receive - format: int32 - maximum: 100 - minimum: 0 - type: integer + requestHeaderModifier: + description: |- + RequestHeaderModifier defines a schema for a filter that modifies request + headers. + + + Support: Core + properties: + add: + description: |- + Add adds the given header(s) (name, value) to the request + before the action. It appends to any existing values associated + with the header name. + + + Input: + GET /foo HTTP/1.1 + my-header: foo + + + Config: + add: + - name: "my-header" + value: "bar,baz" + + + Output: + GET /foo HTTP/1.1 + my-header: foo,bar,baz + items: + description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + + If multiple entries specify equivalent header names, the first entry with + an equivalent name MUST be considered for a match. Subsequent entries + with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + description: Value is the value of HTTP Header to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + remove: + description: |- + Remove the given header(s) from the HTTP request before the action. The + value of Remove is a list of HTTP header names. Note that the header + names are case-insensitive (see + https://datatracker.ietf.org/doc/html/rfc2616#section-4.2). + + + Input: + GET /foo HTTP/1.1 + my-header1: foo + my-header2: bar + my-header3: baz + + + Config: + remove: ["my-header1", "my-header3"] + + + Output: + GET /foo HTTP/1.1 + my-header2: bar + items: + type: string + maxItems: 16 + type: array + x-kubernetes-list-type: set + set: + description: |- + Set overwrites the request with the given header (name, value) + before the action. + + + Input: + GET /foo HTTP/1.1 + my-header: foo + + + Config: + set: + - name: "my-header" + value: "bar" + + + Output: + GET /foo HTTP/1.1 + my-header: bar + items: + description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + + If multiple entries specify equivalent header names, the first entry with + an equivalent name MUST be considered for a match. Subsequent entries + with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + description: Value is the value of HTTP Header to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + type: object + requestMirror: + description: |- + RequestMirror defines a schema for a filter that mirrors requests. + Requests are sent to the specified destination, but responses from + that destination are ignored. + + + This filter can be used multiple times within the same rule. Note that + not all implementations will be able to support mirroring to multiple + backends. + + + Support: Extended + + + + properties: + backendRef: + description: |- + BackendRef references a resource where mirrored requests are sent. + + + Mirrored requests must be sent only to a single destination endpoint + within this BackendRef, irrespective of how many endpoints are present + within this BackendRef. + + + If the referent cannot be found, this BackendRef is invalid and must be + dropped from the Gateway. The controller must ensure the "ResolvedRefs" + condition on the Route status is set to `status: False` and not configure + this backend in the underlying implementation. + + + If there is a cross-namespace reference to an *existing* object + that is not allowed by a ReferenceGrant, the controller must ensure the + "ResolvedRefs" condition on the Route is set to `status: False`, + with the "RefNotPermitted" reason and not configure this backend in the + underlying implementation. + + + In either error case, the Message of the `ResolvedRefs` Condition + should be used to provide more detail about the problem. + + + Support: Extended for Kubernetes Service + + + Support: Implementation-specific for any other resource + properties: + group: + default: "" + description: |- + Group is the group of the referent. For example, "gateway.networking.k8s.io". + When unspecified or empty string, core API group is inferred. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + default: Service + description: |- + Kind is the Kubernetes resource kind of the referent. For example + "Service". + + + Defaults to "Service" when not specified. + + + ExternalName services can refer to CNAME DNS records that may live + outside of the cluster and as such are difficult to reason about in + terms of conformance. They also may not be safe to forward to (see + CVE-2021-25740 for more information). Implementations SHOULD NOT + support ExternalName Services. + + + Support: Core (Services with a type other than ExternalName) + + + Support: Implementation-specific (Services with type ExternalName) + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: Name is the name of the referent. + maxLength: 253 + minLength: 1 + type: string + namespace: + description: |- + Namespace is the namespace of the backend. When unspecified, the local + namespace is inferred. + + + Note that when a namespace different than the local namespace is specified, + a ReferenceGrant object is required in the referent namespace to allow that + namespace's owner to accept the reference. See the ReferenceGrant + documentation for details. + + + Support: Core + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + port: + description: |- + Port specifies the destination port number to use for this resource. + Port is required when the referent is a Kubernetes Service. In this + case, the port number is the service port number, not the target port. + For other resources, destination port might be derived from the referent + resource or this field. + format: int32 + maximum: 65535 + minimum: 1 + type: integer + required: + - name + type: object + fraction: + description: |- + Fraction represents the fraction of requests that should be + mirrored to BackendRef. + + + Only one of Fraction or Percent may be specified. If neither field + is specified, 100% of requests will be mirrored. + + + + properties: + denominator: + default: 100 + format: int32 + minimum: 1 + type: integer + numerator: + format: int32 + minimum: 0 + type: integer + required: + - numerator + type: object + percent: + description: |- + Percent represents the percentage of requests that should be + mirrored to BackendRef. Its minimum value is 0 (indicating 0% of + requests) and its maximum value is 100 (indicating 100% of requests). + + + Only one of Fraction or Percent may be specified. If neither field + is specified, 100% of requests will be mirrored. + + + + format: int32 + maximum: 100 + minimum: 0 + type: integer + required: + - backendRef + type: object + requestRedirect: + description: |- + RequestRedirect defines a schema for a filter that responds to the + request with an HTTP redirection. + + + Support: Core + properties: + hostname: + description: |- + Hostname is the hostname to be used in the value of the `Location` + header in the response. + When empty, the hostname in the `Host` header of the request is used. + + + Support: Core + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + path: + description: |- + Path defines parameters used to modify the path of the incoming request. + The modified path is then used to construct the `Location` header. When + empty, the request path is used as-is. + + + Support: Extended + properties: + replaceFullPath: + description: |- + ReplaceFullPath specifies the value with which to replace the full path + of a request during a rewrite or redirect. + maxLength: 1024 + type: string + replacePrefixMatch: + description: |- + ReplacePrefixMatch specifies the value with which to replace the prefix + match of a request during a rewrite or redirect. For example, a request + to "/foo/bar" with a prefix match of "/foo" and a ReplacePrefixMatch + of "/xyz" would be modified to "/xyz/bar". + + + Note that this matches the behavior of the PathPrefix match type. This + matches full path elements. A path element refers to the list of labels + in the path split by the `/` separator. When specified, a trailing `/` is + ignored. For example, the paths `/abc`, `/abc/`, and `/abc/def` would all + match the prefix `/abc`, but the path `/abcd` would not. + + + ReplacePrefixMatch is only compatible with a `PathPrefix` HTTPRouteMatch. + Using any other HTTPRouteMatch type on the same HTTPRouteRule will result in + the implementation setting the Accepted Condition for the Route to `status: False`. + + + Request Path | Prefix Match | Replace Prefix | Modified Path + -------------|--------------|----------------|---------- + /foo/bar | /foo | /xyz | /xyz/bar + /foo/bar | /foo | /xyz/ | /xyz/bar + /foo/bar | /foo/ | /xyz | /xyz/bar + /foo/bar | /foo/ | /xyz/ | /xyz/bar + /foo | /foo | /xyz | /xyz + /foo/ | /foo | /xyz | /xyz/ + /foo/bar | /foo | | /bar + /foo/ | /foo | | / + /foo | /foo | | / + /foo/ | /foo | / | / + /foo | /foo | / | / + maxLength: 1024 + type: string + type: + description: |- + Type defines the type of path modifier. Additional types may be + added in a future release of the API. + + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + enum: + - ReplaceFullPath + - ReplacePrefixMatch + type: string + required: + - type + type: object + port: + description: |- + Port is the port to be used in the value of the `Location` + header in the response. + + + If no port is specified, the redirect port MUST be derived using the + following rules: + + + * If redirect scheme is not-empty, the redirect port MUST be the well-known + port associated with the redirect scheme. Specifically "http" to port 80 + and "https" to port 443. If the redirect scheme does not have a + well-known port, the listener port of the Gateway SHOULD be used. + * If redirect scheme is empty, the redirect port MUST be the Gateway + Listener port. + + + Implementations SHOULD NOT add the port number in the 'Location' + header in the following cases: + + + * A Location header that will use HTTP (whether that is determined via + the Listener protocol or the Scheme field) _and_ use port 80. + * A Location header that will use HTTPS (whether that is determined via + the Listener protocol or the Scheme field) _and_ use port 443. + + + Support: Extended + format: int32 + maximum: 65535 + minimum: 1 + type: integer + scheme: + description: |- + Scheme is the scheme to be used in the value of the `Location` header in + the response. When empty, the scheme of the request is used. + + + Scheme redirects can affect the port of the redirect, for more information, + refer to the documentation for the port field of this filter. + + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + + + Support: Extended + enum: + - http + - https + type: string + statusCode: + default: 302 + description: |- + StatusCode is the HTTP status code to be used in response. + + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + + + Support: Core + enum: + - 301 + - 302 + type: integer + type: object + responseHeaderModifier: + description: |- + ResponseHeaderModifier defines a schema for a filter that modifies response + headers. + + + Support: Extended + properties: + add: + description: |- + Add adds the given header(s) (name, value) to the request + before the action. It appends to any existing values associated + with the header name. + + + Input: + GET /foo HTTP/1.1 + my-header: foo + + + Config: + add: + - name: "my-header" + value: "bar,baz" + + + Output: + GET /foo HTTP/1.1 + my-header: foo,bar,baz + items: + description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + + If multiple entries specify equivalent header names, the first entry with + an equivalent name MUST be considered for a match. Subsequent entries + with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + description: Value is the value of HTTP Header to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + remove: + description: |- + Remove the given header(s) from the HTTP request before the action. The + value of Remove is a list of HTTP header names. Note that the header + names are case-insensitive (see + https://datatracker.ietf.org/doc/html/rfc2616#section-4.2). + + + Input: + GET /foo HTTP/1.1 + my-header1: foo + my-header2: bar + my-header3: baz + + + Config: + remove: ["my-header1", "my-header3"] + + + Output: + GET /foo HTTP/1.1 + my-header2: bar + items: + type: string + maxItems: 16 + type: array + x-kubernetes-list-type: set + set: + description: |- + Set overwrites the request with the given header (name, value) + before the action. + + + Input: + GET /foo HTTP/1.1 + my-header: foo + + + Config: + set: + - name: "my-header" + value: "bar" + + + Output: + GET /foo HTTP/1.1 + my-header: bar + items: + description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + + If multiple entries specify equivalent header names, the first entry with + an equivalent name MUST be considered for a match. Subsequent entries + with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + description: Value is the value of HTTP Header to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + type: object + type: + description: |- + Type identifies the type of filter to apply. As with other API fields, + types are classified into three conformance levels: + + + - Core: Filter types and their corresponding configuration defined by + "Support: Core" in this package, e.g. "RequestHeaderModifier". All + implementations must support core filters. + + + - Extended: Filter types and their corresponding configuration defined by + "Support: Extended" in this package, e.g. "RequestMirror". Implementers + are encouraged to support extended filters. + + + - Implementation-specific: Filters that are defined and supported by + specific vendors. + In the future, filters showing convergence in behavior across multiple + implementations will be considered for inclusion in extended or core + conformance levels. Filter-specific configuration for such filters + is specified using the ExtensionRef field. `Type` should be set to + "ExtensionRef" for custom filters. + + + Implementers are encouraged to define custom implementation types to + extend the core API with implementation-specific behavior. + + + If a reference to a custom filter type cannot be resolved, the filter + MUST NOT be skipped. Instead, requests that would have been processed by + that filter MUST receive a HTTP error response. + + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + enum: + - RequestHeaderModifier + - ResponseHeaderModifier + - RequestMirror + - RequestRedirect + - URLRewrite + - ExtensionRef + type: string + urlRewrite: + description: |- + URLRewrite defines a schema for a filter that modifies a request during forwarding. + + + Support: Extended + properties: + hostname: + description: |- + Hostname is the value to be used to replace the Host header value during + forwarding. + + + Support: Extended + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + path: + description: |- + Path defines a path rewrite. + + + Support: Extended + properties: + replaceFullPath: + description: |- + ReplaceFullPath specifies the value with which to replace the full path + of a request during a rewrite or redirect. + maxLength: 1024 + type: string + replacePrefixMatch: + description: |- + ReplacePrefixMatch specifies the value with which to replace the prefix + match of a request during a rewrite or redirect. For example, a request + to "/foo/bar" with a prefix match of "/foo" and a ReplacePrefixMatch + of "/xyz" would be modified to "/xyz/bar". + + + Note that this matches the behavior of the PathPrefix match type. This + matches full path elements. A path element refers to the list of labels + in the path split by the `/` separator. When specified, a trailing `/` is + ignored. For example, the paths `/abc`, `/abc/`, and `/abc/def` would all + match the prefix `/abc`, but the path `/abcd` would not. + + + ReplacePrefixMatch is only compatible with a `PathPrefix` HTTPRouteMatch. + Using any other HTTPRouteMatch type on the same HTTPRouteRule will result in + the implementation setting the Accepted Condition for the Route to `status: False`. + + + Request Path | Prefix Match | Replace Prefix | Modified Path + -------------|--------------|----------------|---------- + /foo/bar | /foo | /xyz | /xyz/bar + /foo/bar | /foo | /xyz/ | /xyz/bar + /foo/bar | /foo/ | /xyz | /xyz/bar + /foo/bar | /foo/ | /xyz/ | /xyz/bar + /foo | /foo | /xyz | /xyz + /foo/ | /foo | /xyz | /xyz/ + /foo/bar | /foo | | /bar + /foo/ | /foo | | / + /foo | /foo | | / + /foo/ | /foo | / | / + /foo | /foo | / | / + maxLength: 1024 + type: string + type: + description: |- + Type defines the type of path modifier. Additional types may be + added in a future release of the API. + + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + enum: + - ReplaceFullPath + - ReplacePrefixMatch + type: string + required: + - type + type: object + type: object + required: + - type + type: object + maxItems: 16 + type: array + matches: + description: |- + Matches define conditions used for matching the rule against incoming + HTTP requests. Each match is independent, i.e. this rule will be matched + if **any** one of the matches is satisfied. + + + For example, take the following matches configuration: + + + ``` + matches: + - path: + value: "/foo" + headers: + - name: "version" + value: "v2" + - path: + value: "/v2/foo" + ``` + + + For a request to match against this rule, a request must satisfy + EITHER of the two conditions: + + + - path prefixed with `/foo` AND contains the header `version: v2` + - path prefix of `/v2/foo` + + + See the documentation for HTTPRouteMatch on how to specify multiple + match conditions that should be ANDed together. + + + If no matches are specified, the default is a prefix + path match on "/", which has the effect of matching every + HTTP request. + + + Proxy or Load Balancer routing configuration generated from HTTPRoutes + MUST prioritize matches based on the following criteria, continuing on + ties. Across all rules specified on applicable Routes, precedence must be + given to the match having: + + + * "Exact" path match. + * "Prefix" path match with largest number of characters. + * Method match. + * Largest number of header matches. + * Largest number of query param matches. + + + Note: The precedence of RegularExpression path matches are implementation-specific. + + + If ties still exist across multiple Routes, matching precedence MUST be + determined in order of the following criteria, continuing on ties: + + + * The oldest Route based on creation timestamp. + * The Route appearing first in alphabetical order by + "{namespace}/{name}". + + + If ties still exist within an HTTPRoute, matching precedence MUST be granted + to the FIRST matching rule (in list order) with a match meeting the above + criteria. + + + When no rules matching a request have been successfully attached to the + parent a request is coming from, a HTTP 404 status code MUST be returned. + items: + properties: + headers: + description: |- + Headers specifies HTTP request header matchers. Multiple match values are + ANDed together, meaning, a request must match all the specified headers + to select the route. + items: + description: |- + HTTPHeaderMatch describes how to select a HTTP route by matching HTTP request + headers. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + + If multiple entries specify equivalent header names, only the first + entry with an equivalent name MUST be considered for a match. Subsequent + entries with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + + + When a header is repeated in an HTTP request, it is + implementation-specific behavior as to how this is represented. + Generally, proxies should follow the guidance from the RFC: + https://www.rfc-editor.org/rfc/rfc7230.html#section-3.2.2 regarding + processing a repeated header, with special handling for "Set-Cookie". + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + type: + default: Exact + description: |- + Type specifies how to match against the value of the header. + + + Support: Core (Exact) + + + Support: Implementation-specific (RegularExpression) + + + Since RegularExpression HeaderMatchType has implementation-specific + conformance, implementations can support POSIX, PCRE or any other dialects + of regular expressions. Please read the implementation's documentation to + determine the supported dialect. + enum: + - Exact + - RegularExpression + type: string + value: + description: Value is the value of HTTP Header to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + path: + description: Path specifies a HTTP request path matcher. + properties: + type: + default: PathPrefix + description: |- + Type specifies how to match against the path Value. + + + Support: Core (Exact, PathPrefix) + + + Support: Implementation-specific (RegularExpression) + enum: + - Exact + - PathPrefix + - RegularExpression + type: string + value: + default: / + description: Value of the HTTP path to match against. + maxLength: 1024 + type: string + type: object + queryParams: + description: |- + QueryParams specifies HTTP query parameter matchers. Multiple match + values are ANDed together, meaning, a request must match all the + specified query parameters to select the route. + + + Support: Extended + items: + description: |- + HTTPQueryParamMatch describes how to select a HTTP route by matching HTTP + query parameters. + properties: + name: + description: |- + Name is the name of the HTTP query param to be matched. This must be an + exact string match. (See + https://tools.ietf.org/html/rfc7230#section-2.7.3). + + + If multiple entries specify equivalent query param names, only the first + entry with an equivalent name MUST be considered for a match. Subsequent + entries with an equivalent query param name MUST be ignored. + + + If a query param is repeated in an HTTP request, the behavior is + purposely left undefined, since different data planes have different + capabilities. However, it is *recommended* that implementations should + match against the first value of the param if the data plane supports it, + as this behavior is expected in other load balancing contexts outside of + the Gateway API. + + + Users SHOULD NOT route traffic based on repeated query params to guard + themselves against potential differences in the implementations. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + type: + default: Exact + description: |- + Type specifies how to match against the value of the query parameter. + + + Support: Extended (Exact) + + + Support: Implementation-specific (RegularExpression) + + + Since RegularExpression QueryParamMatchType has Implementation-specific + conformance, implementations can support POSIX, PCRE or any other + dialects of regular expressions. Please read the implementation's + documentation to determine the supported dialect. + enum: + - Exact + - RegularExpression + type: string + value: + description: Value is the value of HTTP query param to be matched. + maxLength: 1024 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + type: object + maxItems: 8 + type: array + type: object + weight: + description: Weight indicate how many percentage of traffic the canary pods should receive + format: int32 + maximum: 100 + minimum: 0 + type: integer + type: object + type: object + required: + - targets + type: object + type: array + toleration: + description: Toleration is the toleration policy of the canary strategy + properties: + initialDelaySeconds: + description: Number of seconds after the toleration check has started before the task are initiated. + format: int32 + type: integer + taskFailureThreshold: + anyOf: + - type: integer + - type: string + description: |- + FailureThreshold indicates how many failed pods can be tolerated before marking the rollout task as success + If not set, the default value is 0, which means no failed pods can be tolerated + This is a task level threshold. + x-kubernetes-int-or-string: true + workloadTotalFailureThreshold: + anyOf: + - type: integer + - type: string + description: |- + WorkloadFailureThreshold indicates how many failed pods can be tolerated in all upgraded pods of one workload. + The default value is 0, which means no failed pods can be tolerated. + This is a workload level threshold. + x-kubernetes-int-or-string: true + type: object + type: object + canary: + description: Canary defines the canary strategy for upgrade and operation + properties: + matchTargets: + description: Match defines condition used for matching resource cross clusterset + properties: + names: + description: Names is a list of workload name + items: + description: CrossClusterObjectNameReference contains cluster and name reference to a k8s object + properties: + cluster: + description: Cluster indicates the name of cluster + type: string + name: + description: Name is the resource name + type: string + required: + - name + type: object + type: array + selector: + description: Selector is a label query over a set of resources, in this case resource + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. type: object type: object - required: - - replicas + x-kubernetes-map-type: atomic type: object - type: array - toleration: - description: Toleration is the toleration policy of the canary strategy properties: - initialDelaySeconds: - description: Number of seconds after the toleration check has started before the task are initiated. - format: int32 - type: integer - taskFailureThreshold: - anyOf: - - type: integer - - type: string - description: |- - FailureThreshold indicates how many failed pods can be tolerated before marking the rollout task as success - If not set, the default value is 0, which means no failed pods can be tolerated - This is a task level threshold. - x-kubernetes-int-or-string: true - workloadTotalFailureThreshold: - anyOf: + additionalProperties: + type: string + description: Properties contains additional information for step + type: object + replicas: + anyOf: - type: integer - type: string - description: |- - WorkloadFailureThreshold indicates how many failed pods can be tolerated in all upgraded pods of one workload. - The default value is 0, which means no failed pods can be tolerated. - This is a workload level threshold. - x-kubernetes-int-or-string: true - type: object - type: object - canary: - description: Canary defines the canary strategy for upgrade and operation - properties: - matchTargets: - description: Match defines condition used for matching resource cross clusterset - properties: - names: - description: Names is a list of workload name - items: - description: CrossClusterObjectNameReference contains cluster and name reference to a k8s object - properties: - cluster: - description: Cluster indicates the name of cluster - type: string - name: - description: Name is the resource name - type: string - required: - - name + description: Replicas is the replicas of the rollout task, which represents the number of pods to be upgraded + x-kubernetes-int-or-string: true + templateMetadataPatch: + description: TemplateMetadataPatch defines a patch for workload template metadata. + properties: + annotations: + additionalProperties: + type: string + description: Annotations are additional metadata that can be included. type: object - type: array - selector: - description: Selector is a label query over a set of resources, in this case resource - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. - items: - description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. - properties: - key: - description: key is the label key that the selector applies to. - type: string - operator: - description: |- - operator represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists and DoesNotExist. - type: string - values: - description: |- - values is an array of string values. If the operator is In or NotIn, - the values array must be non-empty. If the operator is Exists or DoesNotExist, - the values array must be empty. This array is replaced during a strategic - merge patch. - items: - type: string - type: array - required: - - key - - operator - type: object - type: array - matchLabels: - additionalProperties: - type: string - description: |- - matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels - map is equivalent to an element of matchExpressions, whose key field is "key", the - operator is "In", and the values array contains only "value". The requirements are ANDed. - type: object - type: object - x-kubernetes-map-type: atomic - type: object - properties: - additionalProperties: - type: string - description: Properties contains additional information for step - type: object - replicas: - anyOf: - - type: integer - - type: string - description: Replicas is the replicas of the rollout task, which represents the number of pods to be upgraded - x-kubernetes-int-or-string: true - templateMetadataPatch: - description: TemplateMetadataPatch defines a patch for workload template metadata. - properties: - annotations: - additionalProperties: - type: string - description: Annotations are additional metadata that can be included. - type: object - labels: - additionalProperties: - type: string - description: Labels are additional metadata that can be included. - type: object - type: object - traffic: - description: traffic strategy - properties: - http: - properties: - filters: - description: |- - Filters define the filters that are applied to requests that match - this rule. - - - The effects of ordering of multiple behaviors are currently unspecified. - This can change in the future based on feedback during the alpha stage. - - - Conformance-levels at this level are defined based on the type of filter: - - - - ALL core filters MUST be supported by all implementations. - - Implementers are encouraged to support extended filters. - - Implementation-specific custom filters have no API guarantees across - implementations. - - - Specifying the same filter multiple times is not supported unless explicitly - indicated in the filter. - - - All filters are expected to be compatible with each other except for the - URLRewrite and RequestRedirect filters, which may not be combined. If an - implementation can not support other combinations of filters, they must clearly - document that limitation. In cases where incompatible or unsupported - filters are specified and cause the `Accepted` condition to be set to status - `False`, implementations may use the `IncompatibleFilters` reason to specify - this configuration error. - - - Support: Core - items: + labels: + additionalProperties: + type: string + description: Labels are additional metadata that can be included. + type: object + type: object + traffic: + description: traffic strategy + properties: + http: + properties: + filters: description: |- - HTTPRouteFilter defines processing steps that must be completed during the - request or response lifecycle. HTTPRouteFilters are meant as an extension - point to express processing that may be done in Gateway implementations. Some - examples include request or response modification, implementing - authentication strategies, rate-limiting, and traffic shaping. API - guarantee/conformance is defined based on the type of the filter. - properties: - extensionRef: - description: |- - ExtensionRef is an optional, implementation-specific extension to the - "filter" behavior. For example, resource "myroutefilter" in group - "networking.example.net"). ExtensionRef MUST NOT be used for core and - extended filters. - - - This filter can be used multiple times within the same rule. - - - Support: Implementation-specific - properties: - group: - description: |- - Group is the group of the referent. For example, "gateway.networking.k8s.io". - When unspecified or empty string, core API group is inferred. - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - description: Kind is kind of the referent. For example "HTTPRoute" or "Service". - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - type: string - name: - description: Name is the name of the referent. - maxLength: 253 - minLength: 1 - type: string - required: - - group - - kind - - name - type: object - requestHeaderModifier: - description: |- - RequestHeaderModifier defines a schema for a filter that modifies request - headers. - - - Support: Core - properties: - add: - description: |- - Add adds the given header(s) (name, value) to the request - before the action. It appends to any existing values associated - with the header name. - - - Input: - GET /foo HTTP/1.1 - my-header: foo - - - Config: - add: - - name: "my-header" - value: "bar,baz" - - - Output: - GET /foo HTTP/1.1 - my-header: foo,bar,baz - items: - description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. + Filters define the filters that are applied to requests that match + this rule. + + + The effects of ordering of multiple behaviors are currently unspecified. + This can change in the future based on feedback during the alpha stage. + + + Conformance-levels at this level are defined based on the type of filter: + + + - ALL core filters MUST be supported by all implementations. + - Implementers are encouraged to support extended filters. + - Implementation-specific custom filters have no API guarantees across + implementations. + + + Specifying the same filter multiple times is not supported unless explicitly + indicated in the filter. + + + All filters are expected to be compatible with each other except for the + URLRewrite and RequestRedirect filters, which may not be combined. If an + implementation can not support other combinations of filters, they must clearly + document that limitation. In cases where incompatible or unsupported + filters are specified and cause the `Accepted` condition to be set to status + `False`, implementations may use the `IncompatibleFilters` reason to specify + this configuration error. + + + Support: Core + items: + description: |- + HTTPRouteFilter defines processing steps that must be completed during the + request or response lifecycle. HTTPRouteFilters are meant as an extension + point to express processing that may be done in Gateway implementations. Some + examples include request or response modification, implementing + authentication strategies, rate-limiting, and traffic shaping. API + guarantee/conformance is defined based on the type of the filter. + properties: + extensionRef: + description: |- + ExtensionRef is an optional, implementation-specific extension to the + "filter" behavior. For example, resource "myroutefilter" in group + "networking.example.net"). ExtensionRef MUST NOT be used for core and + extended filters. + + + This filter can be used multiple times within the same rule. + + + Support: Implementation-specific + properties: + group: + description: |- + Group is the group of the referent. For example, "gateway.networking.k8s.io". + When unspecified or empty string, core API group is inferred. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + description: Kind is kind of the referent. For example "HTTPRoute" or "Service". + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: Name is the name of the referent. + maxLength: 253 + minLength: 1 + type: string + required: + - group + - kind + - name + type: object + requestHeaderModifier: + description: |- + RequestHeaderModifier defines a schema for a filter that modifies request + headers. + + + Support: Core + properties: + add: + description: |- + Add adds the given header(s) (name, value) to the request + before the action. It appends to any existing values associated + with the header name. + + + Input: + GET /foo HTTP/1.1 + my-header: foo + + + Config: + add: + - name: "my-header" + value: "bar,baz" + + + Output: + GET /foo HTTP/1.1 + my-header: foo,bar,baz + items: + description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + + If multiple entries specify equivalent header names, the first entry with + an equivalent name MUST be considered for a match. Subsequent entries + with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + description: Value is the value of HTTP Header to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + remove: + description: |- + Remove the given header(s) from the HTTP request before the action. The + value of Remove is a list of HTTP header names. Note that the header + names are case-insensitive (see + https://datatracker.ietf.org/doc/html/rfc2616#section-4.2). + + + Input: + GET /foo HTTP/1.1 + my-header1: foo + my-header2: bar + my-header3: baz + + + Config: + remove: ["my-header1", "my-header3"] + + + Output: + GET /foo HTTP/1.1 + my-header2: bar + items: + type: string + maxItems: 16 + type: array + x-kubernetes-list-type: set + set: + description: |- + Set overwrites the request with the given header (name, value) + before the action. + + + Input: + GET /foo HTTP/1.1 + my-header: foo + + + Config: + set: + - name: "my-header" + value: "bar" + + + Output: + GET /foo HTTP/1.1 + my-header: bar + items: + description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + + If multiple entries specify equivalent header names, the first entry with + an equivalent name MUST be considered for a match. Subsequent entries + with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + description: Value is the value of HTTP Header to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + type: object + requestMirror: + description: |- + RequestMirror defines a schema for a filter that mirrors requests. + Requests are sent to the specified destination, but responses from + that destination are ignored. + + + This filter can be used multiple times within the same rule. Note that + not all implementations will be able to support mirroring to multiple + backends. + + + Support: Extended + + + + properties: + backendRef: + description: |- + BackendRef references a resource where mirrored requests are sent. + + + Mirrored requests must be sent only to a single destination endpoint + within this BackendRef, irrespective of how many endpoints are present + within this BackendRef. + + + If the referent cannot be found, this BackendRef is invalid and must be + dropped from the Gateway. The controller must ensure the "ResolvedRefs" + condition on the Route status is set to `status: False` and not configure + this backend in the underlying implementation. + + + If there is a cross-namespace reference to an *existing* object + that is not allowed by a ReferenceGrant, the controller must ensure the + "ResolvedRefs" condition on the Route is set to `status: False`, + with the "RefNotPermitted" reason and not configure this backend in the + underlying implementation. + + + In either error case, the Message of the `ResolvedRefs` Condition + should be used to provide more detail about the problem. + + + Support: Extended for Kubernetes Service + + + Support: Implementation-specific for any other resource properties: - name: + group: + default: "" description: |- - Name is the name of the HTTP Header to be matched. Name matching MUST be - case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). - - - If multiple entries specify equivalent header names, the first entry with - an equivalent name MUST be considered for a match. Subsequent entries - with an equivalent header name MUST be ignored. Due to the - case-insensitivity of header names, "foo" and "Foo" are considered - equivalent. - maxLength: 256 - minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + Group is the group of the referent. For example, "gateway.networking.k8s.io". + When unspecified or empty string, core API group is inferred. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ type: string - value: - description: Value is the value of HTTP Header to be matched. - maxLength: 4096 + kind: + default: Service + description: |- + Kind is the Kubernetes resource kind of the referent. For example + "Service". + + + Defaults to "Service" when not specified. + + + ExternalName services can refer to CNAME DNS records that may live + outside of the cluster and as such are difficult to reason about in + terms of conformance. They also may not be safe to forward to (see + CVE-2021-25740 for more information). Implementations SHOULD NOT + support ExternalName Services. + + + Support: Core (Services with a type other than ExternalName) + + + Support: Implementation-specific (Services with type ExternalName) + maxLength: 63 minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ type: string - required: - - name - - value - type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - remove: - description: |- - Remove the given header(s) from the HTTP request before the action. The - value of Remove is a list of HTTP header names. Note that the header - names are case-insensitive (see - https://datatracker.ietf.org/doc/html/rfc2616#section-4.2). - - - Input: - GET /foo HTTP/1.1 - my-header1: foo - my-header2: bar - my-header3: baz - - - Config: - remove: ["my-header1", "my-header3"] - - - Output: - GET /foo HTTP/1.1 - my-header2: bar - items: - type: string - maxItems: 16 - type: array - x-kubernetes-list-type: set - set: - description: |- - Set overwrites the request with the given header (name, value) - before the action. - - - Input: - GET /foo HTTP/1.1 - my-header: foo - - - Config: - set: - - name: "my-header" - value: "bar" - - - Output: - GET /foo HTTP/1.1 - my-header: bar - items: - description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. - properties: name: - description: |- - Name is the name of the HTTP Header to be matched. Name matching MUST be - case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). - - - If multiple entries specify equivalent header names, the first entry with - an equivalent name MUST be considered for a match. Subsequent entries - with an equivalent header name MUST be ignored. Due to the - case-insensitivity of header names, "foo" and "Foo" are considered - equivalent. - maxLength: 256 + description: Name is the name of the referent. + maxLength: 253 minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ type: string - value: - description: Value is the value of HTTP Header to be matched. - maxLength: 4096 + namespace: + description: |- + Namespace is the namespace of the backend. When unspecified, the local + namespace is inferred. + + + Note that when a namespace different than the local namespace is specified, + a ReferenceGrant object is required in the referent namespace to allow that + namespace's owner to accept the reference. See the ReferenceGrant + documentation for details. + + + Support: Core + maxLength: 63 minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ type: string + port: + description: |- + Port specifies the destination port number to use for this resource. + Port is required when the referent is a Kubernetes Service. In this + case, the port number is the service port number, not the target port. + For other resources, destination port might be derived from the referent + resource or this field. + format: int32 + maximum: 65535 + minimum: 1 + type: integer required: - - name - - value + - name type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - type: object - requestMirror: - description: |- - RequestMirror defines a schema for a filter that mirrors requests. - Requests are sent to the specified destination, but responses from - that destination are ignored. - - - This filter can be used multiple times within the same rule. Note that - not all implementations will be able to support mirroring to multiple - backends. - - - Support: Extended - - - - properties: - backendRef: - description: |- - BackendRef references a resource where mirrored requests are sent. - - - Mirrored requests must be sent only to a single destination endpoint - within this BackendRef, irrespective of how many endpoints are present - within this BackendRef. - - - If the referent cannot be found, this BackendRef is invalid and must be - dropped from the Gateway. The controller must ensure the "ResolvedRefs" - condition on the Route status is set to `status: False` and not configure - this backend in the underlying implementation. - - - If there is a cross-namespace reference to an *existing* object - that is not allowed by a ReferenceGrant, the controller must ensure the - "ResolvedRefs" condition on the Route is set to `status: False`, - with the "RefNotPermitted" reason and not configure this backend in the - underlying implementation. - - - In either error case, the Message of the `ResolvedRefs` Condition - should be used to provide more detail about the problem. - - - Support: Extended for Kubernetes Service - - - Support: Implementation-specific for any other resource - properties: - group: - default: "" - description: |- - Group is the group of the referent. For example, "gateway.networking.k8s.io". - When unspecified or empty string, core API group is inferred. - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - default: Service - description: |- - Kind is the Kubernetes resource kind of the referent. For example - "Service". - - - Defaults to "Service" when not specified. - - - ExternalName services can refer to CNAME DNS records that may live - outside of the cluster and as such are difficult to reason about in - terms of conformance. They also may not be safe to forward to (see - CVE-2021-25740 for more information). Implementations SHOULD NOT - support ExternalName Services. - - - Support: Core (Services with a type other than ExternalName) - - - Support: Implementation-specific (Services with type ExternalName) - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - type: string - name: - description: Name is the name of the referent. - maxLength: 253 - minLength: 1 - type: string - namespace: - description: |- - Namespace is the namespace of the backend. When unspecified, the local - namespace is inferred. - - - Note that when a namespace different than the local namespace is specified, - a ReferenceGrant object is required in the referent namespace to allow that - namespace's owner to accept the reference. See the ReferenceGrant - documentation for details. - - - Support: Core - maxLength: 63 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ - type: string - port: - description: |- - Port specifies the destination port number to use for this resource. - Port is required when the referent is a Kubernetes Service. In this - case, the port number is the service port number, not the target port. - For other resources, destination port might be derived from the referent - resource or this field. - format: int32 - maximum: 65535 - minimum: 1 - type: integer - required: - - name - type: object - fraction: - description: |- - Fraction represents the fraction of requests that should be - mirrored to BackendRef. - - - Only one of Fraction or Percent may be specified. If neither field - is specified, 100% of requests will be mirrored. - - - - properties: - denominator: - default: 100 - format: int32 - minimum: 1 - type: integer - numerator: - format: int32 - minimum: 0 - type: integer - required: - - numerator - type: object - percent: - description: |- - Percent represents the percentage of requests that should be - mirrored to BackendRef. Its minimum value is 0 (indicating 0% of - requests) and its maximum value is 100 (indicating 100% of requests). - - - Only one of Fraction or Percent may be specified. If neither field - is specified, 100% of requests will be mirrored. - - - - format: int32 - maximum: 100 - minimum: 0 - type: integer - required: - - backendRef - type: object - requestRedirect: - description: |- - RequestRedirect defines a schema for a filter that responds to the - request with an HTTP redirection. - - - Support: Core - properties: - hostname: - description: |- - Hostname is the hostname to be used in the value of the `Location` - header in the response. - When empty, the hostname in the `Host` header of the request is used. - - - Support: Core - maxLength: 253 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - path: - description: |- - Path defines parameters used to modify the path of the incoming request. - The modified path is then used to construct the `Location` header. When - empty, the request path is used as-is. - - - Support: Extended - properties: - replaceFullPath: - description: |- - ReplaceFullPath specifies the value with which to replace the full path - of a request during a rewrite or redirect. - maxLength: 1024 - type: string - replacePrefixMatch: - description: |- - ReplacePrefixMatch specifies the value with which to replace the prefix - match of a request during a rewrite or redirect. For example, a request - to "/foo/bar" with a prefix match of "/foo" and a ReplacePrefixMatch - of "/xyz" would be modified to "/xyz/bar". - - - Note that this matches the behavior of the PathPrefix match type. This - matches full path elements. A path element refers to the list of labels - in the path split by the `/` separator. When specified, a trailing `/` is - ignored. For example, the paths `/abc`, `/abc/`, and `/abc/def` would all - match the prefix `/abc`, but the path `/abcd` would not. - - - ReplacePrefixMatch is only compatible with a `PathPrefix` HTTPRouteMatch. - Using any other HTTPRouteMatch type on the same HTTPRouteRule will result in - the implementation setting the Accepted Condition for the Route to `status: False`. - - - Request Path | Prefix Match | Replace Prefix | Modified Path - -------------|--------------|----------------|---------- - /foo/bar | /foo | /xyz | /xyz/bar - /foo/bar | /foo | /xyz/ | /xyz/bar - /foo/bar | /foo/ | /xyz | /xyz/bar - /foo/bar | /foo/ | /xyz/ | /xyz/bar - /foo | /foo | /xyz | /xyz - /foo/ | /foo | /xyz | /xyz/ - /foo/bar | /foo | | /bar - /foo/ | /foo | | / - /foo | /foo | | / - /foo/ | /foo | / | / - /foo | /foo | / | / - maxLength: 1024 - type: string - type: - description: |- - Type defines the type of path modifier. Additional types may be - added in a future release of the API. - - - Note that values may be added to this enum, implementations - must ensure that unknown values will not cause a crash. - - - Unknown values here must result in the implementation setting the - Accepted Condition for the Route to `status: False`, with a - Reason of `UnsupportedValue`. - enum: - - ReplaceFullPath - - ReplacePrefixMatch - type: string - required: - - type - type: object - port: - description: |- - Port is the port to be used in the value of the `Location` - header in the response. - - - If no port is specified, the redirect port MUST be derived using the - following rules: - - - * If redirect scheme is not-empty, the redirect port MUST be the well-known - port associated with the redirect scheme. Specifically "http" to port 80 - and "https" to port 443. If the redirect scheme does not have a - well-known port, the listener port of the Gateway SHOULD be used. - * If redirect scheme is empty, the redirect port MUST be the Gateway - Listener port. - - - Implementations SHOULD NOT add the port number in the 'Location' - header in the following cases: - - - * A Location header that will use HTTP (whether that is determined via - the Listener protocol or the Scheme field) _and_ use port 80. - * A Location header that will use HTTPS (whether that is determined via - the Listener protocol or the Scheme field) _and_ use port 443. - - - Support: Extended - format: int32 - maximum: 65535 - minimum: 1 - type: integer - scheme: - description: |- - Scheme is the scheme to be used in the value of the `Location` header in - the response. When empty, the scheme of the request is used. - - - Scheme redirects can affect the port of the redirect, for more information, - refer to the documentation for the port field of this filter. - - - Note that values may be added to this enum, implementations - must ensure that unknown values will not cause a crash. - - - Unknown values here must result in the implementation setting the - Accepted Condition for the Route to `status: False`, with a - Reason of `UnsupportedValue`. - - - Support: Extended - enum: - - http - - https - type: string - statusCode: - default: 302 - description: |- - StatusCode is the HTTP status code to be used in response. - - - Note that values may be added to this enum, implementations - must ensure that unknown values will not cause a crash. - - - Unknown values here must result in the implementation setting the - Accepted Condition for the Route to `status: False`, with a - Reason of `UnsupportedValue`. - - - Support: Core - enum: - - 301 - - 302 - type: integer - type: object - responseHeaderModifier: - description: |- - ResponseHeaderModifier defines a schema for a filter that modifies response - headers. - - - Support: Extended - properties: - add: - description: |- - Add adds the given header(s) (name, value) to the request - before the action. It appends to any existing values associated - with the header name. - - - Input: - GET /foo HTTP/1.1 - my-header: foo - - - Config: - add: - - name: "my-header" - value: "bar,baz" - - - Output: - GET /foo HTTP/1.1 - my-header: foo,bar,baz - items: - description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. + fraction: + description: |- + Fraction represents the fraction of requests that should be + mirrored to BackendRef. + + + Only one of Fraction or Percent may be specified. If neither field + is specified, 100% of requests will be mirrored. + + + properties: - name: - description: |- - Name is the name of the HTTP Header to be matched. Name matching MUST be - case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). - - - If multiple entries specify equivalent header names, the first entry with - an equivalent name MUST be considered for a match. Subsequent entries - with an equivalent header name MUST be ignored. Due to the - case-insensitivity of header names, "foo" and "Foo" are considered - equivalent. - maxLength: 256 - minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ - type: string - value: - description: Value is the value of HTTP Header to be matched. - maxLength: 4096 - minLength: 1 - type: string + denominator: + default: 100 + format: int32 + minimum: 1 + type: integer + numerator: + format: int32 + minimum: 0 + type: integer required: - - name - - value + - numerator type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - remove: - description: |- - Remove the given header(s) from the HTTP request before the action. The - value of Remove is a list of HTTP header names. Note that the header - names are case-insensitive (see - https://datatracker.ietf.org/doc/html/rfc2616#section-4.2). - - - Input: - GET /foo HTTP/1.1 - my-header1: foo - my-header2: bar - my-header3: baz - - - Config: - remove: ["my-header1", "my-header3"] - - - Output: - GET /foo HTTP/1.1 - my-header2: bar - items: + percent: + description: |- + Percent represents the percentage of requests that should be + mirrored to BackendRef. Its minimum value is 0 (indicating 0% of + requests) and its maximum value is 100 (indicating 100% of requests). + + + Only one of Fraction or Percent may be specified. If neither field + is specified, 100% of requests will be mirrored. + + + + format: int32 + maximum: 100 + minimum: 0 + type: integer + required: + - backendRef + type: object + requestRedirect: + description: |- + RequestRedirect defines a schema for a filter that responds to the + request with an HTTP redirection. + + + Support: Core + properties: + hostname: + description: |- + Hostname is the hostname to be used in the value of the `Location` + header in the response. + When empty, the hostname in the `Host` header of the request is used. + + + Support: Core + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ type: string - maxItems: 16 - type: array - x-kubernetes-list-type: set - set: - description: |- - Set overwrites the request with the given header (name, value) - before the action. - - - Input: - GET /foo HTTP/1.1 - my-header: foo - - - Config: - set: - - name: "my-header" - value: "bar" - - - Output: - GET /foo HTTP/1.1 - my-header: bar - items: - description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. + path: + description: |- + Path defines parameters used to modify the path of the incoming request. + The modified path is then used to construct the `Location` header. When + empty, the request path is used as-is. + + + Support: Extended properties: - name: + replaceFullPath: description: |- - Name is the name of the HTTP Header to be matched. Name matching MUST be - case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). - - - If multiple entries specify equivalent header names, the first entry with - an equivalent name MUST be considered for a match. Subsequent entries - with an equivalent header name MUST be ignored. Due to the - case-insensitivity of header names, "foo" and "Foo" are considered - equivalent. - maxLength: 256 - minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + ReplaceFullPath specifies the value with which to replace the full path + of a request during a rewrite or redirect. + maxLength: 1024 type: string - value: - description: Value is the value of HTTP Header to be matched. - maxLength: 4096 - minLength: 1 + replacePrefixMatch: + description: |- + ReplacePrefixMatch specifies the value with which to replace the prefix + match of a request during a rewrite or redirect. For example, a request + to "/foo/bar" with a prefix match of "/foo" and a ReplacePrefixMatch + of "/xyz" would be modified to "/xyz/bar". + + + Note that this matches the behavior of the PathPrefix match type. This + matches full path elements. A path element refers to the list of labels + in the path split by the `/` separator. When specified, a trailing `/` is + ignored. For example, the paths `/abc`, `/abc/`, and `/abc/def` would all + match the prefix `/abc`, but the path `/abcd` would not. + + + ReplacePrefixMatch is only compatible with a `PathPrefix` HTTPRouteMatch. + Using any other HTTPRouteMatch type on the same HTTPRouteRule will result in + the implementation setting the Accepted Condition for the Route to `status: False`. + + + Request Path | Prefix Match | Replace Prefix | Modified Path + -------------|--------------|----------------|---------- + /foo/bar | /foo | /xyz | /xyz/bar + /foo/bar | /foo | /xyz/ | /xyz/bar + /foo/bar | /foo/ | /xyz | /xyz/bar + /foo/bar | /foo/ | /xyz/ | /xyz/bar + /foo | /foo | /xyz | /xyz + /foo/ | /foo | /xyz | /xyz/ + /foo/bar | /foo | | /bar + /foo/ | /foo | | / + /foo | /foo | | / + /foo/ | /foo | / | / + /foo | /foo | / | / + maxLength: 1024 + type: string + type: + description: |- + Type defines the type of path modifier. Additional types may be + added in a future release of the API. + + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + enum: + - ReplaceFullPath + - ReplacePrefixMatch type: string required: - - name - - value + - type type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - type: object - type: - description: |- - Type identifies the type of filter to apply. As with other API fields, - types are classified into three conformance levels: - - - - Core: Filter types and their corresponding configuration defined by - "Support: Core" in this package, e.g. "RequestHeaderModifier". All - implementations must support core filters. - - - - Extended: Filter types and their corresponding configuration defined by - "Support: Extended" in this package, e.g. "RequestMirror". Implementers - are encouraged to support extended filters. - - - - Implementation-specific: Filters that are defined and supported by - specific vendors. - In the future, filters showing convergence in behavior across multiple - implementations will be considered for inclusion in extended or core - conformance levels. Filter-specific configuration for such filters - is specified using the ExtensionRef field. `Type` should be set to - "ExtensionRef" for custom filters. - - - Implementers are encouraged to define custom implementation types to - extend the core API with implementation-specific behavior. - - - If a reference to a custom filter type cannot be resolved, the filter - MUST NOT be skipped. Instead, requests that would have been processed by - that filter MUST receive a HTTP error response. - - - Note that values may be added to this enum, implementations - must ensure that unknown values will not cause a crash. - - - Unknown values here must result in the implementation setting the - Accepted Condition for the Route to `status: False`, with a - Reason of `UnsupportedValue`. - enum: - - RequestHeaderModifier - - ResponseHeaderModifier - - RequestMirror - - RequestRedirect - - URLRewrite - - ExtensionRef - type: string - urlRewrite: - description: |- - URLRewrite defines a schema for a filter that modifies a request during forwarding. - - - Support: Extended - properties: - hostname: - description: |- - Hostname is the value to be used to replace the Host header value during - forwarding. - - - Support: Extended - maxLength: 253 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - path: - description: |- - Path defines a path rewrite. - - - Support: Extended - properties: - replaceFullPath: - description: |- - ReplaceFullPath specifies the value with which to replace the full path - of a request during a rewrite or redirect. - maxLength: 1024 - type: string - replacePrefixMatch: - description: |- - ReplacePrefixMatch specifies the value with which to replace the prefix - match of a request during a rewrite or redirect. For example, a request - to "/foo/bar" with a prefix match of "/foo" and a ReplacePrefixMatch - of "/xyz" would be modified to "/xyz/bar". - - - Note that this matches the behavior of the PathPrefix match type. This - matches full path elements. A path element refers to the list of labels - in the path split by the `/` separator. When specified, a trailing `/` is - ignored. For example, the paths `/abc`, `/abc/`, and `/abc/def` would all - match the prefix `/abc`, but the path `/abcd` would not. - - - ReplacePrefixMatch is only compatible with a `PathPrefix` HTTPRouteMatch. - Using any other HTTPRouteMatch type on the same HTTPRouteRule will result in - the implementation setting the Accepted Condition for the Route to `status: False`. - - - Request Path | Prefix Match | Replace Prefix | Modified Path - -------------|--------------|----------------|---------- - /foo/bar | /foo | /xyz | /xyz/bar - /foo/bar | /foo | /xyz/ | /xyz/bar - /foo/bar | /foo/ | /xyz | /xyz/bar - /foo/bar | /foo/ | /xyz/ | /xyz/bar - /foo | /foo | /xyz | /xyz - /foo/ | /foo | /xyz | /xyz/ - /foo/bar | /foo | | /bar - /foo/ | /foo | | / - /foo | /foo | | / - /foo/ | /foo | / | / - /foo | /foo | / | / - maxLength: 1024 - type: string - type: - description: |- - Type defines the type of path modifier. Additional types may be - added in a future release of the API. - - - Note that values may be added to this enum, implementations - must ensure that unknown values will not cause a crash. - - - Unknown values here must result in the implementation setting the - Accepted Condition for the Route to `status: False`, with a - Reason of `UnsupportedValue`. - enum: - - ReplaceFullPath - - ReplacePrefixMatch - type: string - required: - - type - type: object - type: object - required: - - type - type: object - maxItems: 16 - type: array - matches: - description: |- - Matches define conditions used for matching the rule against incoming - HTTP requests. Each match is independent, i.e. this rule will be matched - if **any** one of the matches is satisfied. - - - For example, take the following matches configuration: - - - ``` - matches: - - path: - value: "/foo" - headers: - - name: "version" - value: "v2" - - path: - value: "/v2/foo" - ``` - - - For a request to match against this rule, a request must satisfy - EITHER of the two conditions: - - - - path prefixed with `/foo` AND contains the header `version: v2` - - path prefix of `/v2/foo` - - - See the documentation for HTTPRouteMatch on how to specify multiple - match conditions that should be ANDed together. - - - If no matches are specified, the default is a prefix - path match on "/", which has the effect of matching every - HTTP request. - - - Proxy or Load Balancer routing configuration generated from HTTPRoutes - MUST prioritize matches based on the following criteria, continuing on - ties. Across all rules specified on applicable Routes, precedence must be - given to the match having: - - - * "Exact" path match. - * "Prefix" path match with largest number of characters. - * Method match. - * Largest number of header matches. - * Largest number of query param matches. - - - Note: The precedence of RegularExpression path matches are implementation-specific. - - - If ties still exist across multiple Routes, matching precedence MUST be - determined in order of the following criteria, continuing on ties: - - - * The oldest Route based on creation timestamp. - * The Route appearing first in alphabetical order by - "{namespace}/{name}". - - - If ties still exist within an HTTPRoute, matching precedence MUST be granted - to the FIRST matching rule (in list order) with a match meeting the above - criteria. - - - When no rules matching a request have been successfully attached to the - parent a request is coming from, a HTTP 404 status code MUST be returned. - items: - properties: - headers: - description: |- - Headers specifies HTTP request header matchers. Multiple match values are - ANDed together, meaning, a request must match all the specified headers - to select the route. - items: + port: + description: |- + Port is the port to be used in the value of the `Location` + header in the response. + + + If no port is specified, the redirect port MUST be derived using the + following rules: + + + * If redirect scheme is not-empty, the redirect port MUST be the well-known + port associated with the redirect scheme. Specifically "http" to port 80 + and "https" to port 443. If the redirect scheme does not have a + well-known port, the listener port of the Gateway SHOULD be used. + * If redirect scheme is empty, the redirect port MUST be the Gateway + Listener port. + + + Implementations SHOULD NOT add the port number in the 'Location' + header in the following cases: + + + * A Location header that will use HTTP (whether that is determined via + the Listener protocol or the Scheme field) _and_ use port 80. + * A Location header that will use HTTPS (whether that is determined via + the Listener protocol or the Scheme field) _and_ use port 443. + + + Support: Extended + format: int32 + maximum: 65535 + minimum: 1 + type: integer + scheme: + description: |- + Scheme is the scheme to be used in the value of the `Location` header in + the response. When empty, the scheme of the request is used. + + + Scheme redirects can affect the port of the redirect, for more information, + refer to the documentation for the port field of this filter. + + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + + + Support: Extended + enum: + - http + - https + type: string + statusCode: + default: 302 + description: |- + StatusCode is the HTTP status code to be used in response. + + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + + + Support: Core + enum: + - 301 + - 302 + type: integer + type: object + responseHeaderModifier: description: |- - HTTPHeaderMatch describes how to select a HTTP route by matching HTTP request + ResponseHeaderModifier defines a schema for a filter that modifies response headers. + + + Support: Extended properties: - name: + add: description: |- - Name is the name of the HTTP Header to be matched. Name matching MUST be - case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). - - - If multiple entries specify equivalent header names, only the first - entry with an equivalent name MUST be considered for a match. Subsequent - entries with an equivalent header name MUST be ignored. Due to the - case-insensitivity of header names, "foo" and "Foo" are considered - equivalent. - - - When a header is repeated in an HTTP request, it is - implementation-specific behavior as to how this is represented. - Generally, proxies should follow the guidance from the RFC: - https://www.rfc-editor.org/rfc/rfc7230.html#section-3.2.2 regarding - processing a repeated header, with special handling for "Set-Cookie". - maxLength: 256 - minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ - type: string - type: - default: Exact + Add adds the given header(s) (name, value) to the request + before the action. It appends to any existing values associated + with the header name. + + + Input: + GET /foo HTTP/1.1 + my-header: foo + + + Config: + add: + - name: "my-header" + value: "bar,baz" + + + Output: + GET /foo HTTP/1.1 + my-header: foo,bar,baz + items: + description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + + If multiple entries specify equivalent header names, the first entry with + an equivalent name MUST be considered for a match. Subsequent entries + with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + description: Value is the value of HTTP Header to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + remove: description: |- - Type specifies how to match against the value of the header. - - - Support: Core (Exact) - - - Support: Implementation-specific (RegularExpression) - - - Since RegularExpression HeaderMatchType has implementation-specific - conformance, implementations can support POSIX, PCRE or any other dialects - of regular expressions. Please read the implementation's documentation to - determine the supported dialect. - enum: - - Exact - - RegularExpression - type: string - value: - description: Value is the value of HTTP Header to be matched. - maxLength: 4096 - minLength: 1 - type: string - required: - - name - - value + Remove the given header(s) from the HTTP request before the action. The + value of Remove is a list of HTTP header names. Note that the header + names are case-insensitive (see + https://datatracker.ietf.org/doc/html/rfc2616#section-4.2). + + + Input: + GET /foo HTTP/1.1 + my-header1: foo + my-header2: bar + my-header3: baz + + + Config: + remove: ["my-header1", "my-header3"] + + + Output: + GET /foo HTTP/1.1 + my-header2: bar + items: + type: string + maxItems: 16 + type: array + x-kubernetes-list-type: set + set: + description: |- + Set overwrites the request with the given header (name, value) + before the action. + + + Input: + GET /foo HTTP/1.1 + my-header: foo + + + Config: + set: + - name: "my-header" + value: "bar" + + + Output: + GET /foo HTTP/1.1 + my-header: bar + items: + description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + + If multiple entries specify equivalent header names, the first entry with + an equivalent name MUST be considered for a match. Subsequent entries + with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + description: Value is the value of HTTP Header to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - path: - description: Path specifies a HTTP request path matcher. - properties: - type: - default: PathPrefix - description: |- - Type specifies how to match against the path Value. - - - Support: Core (Exact, PathPrefix) - - - Support: Implementation-specific (RegularExpression) - enum: - - Exact - - PathPrefix - - RegularExpression - type: string - value: - default: / - description: Value of the HTTP path to match against. - maxLength: 1024 - type: string - type: object - queryParams: - description: |- - QueryParams specifies HTTP query parameter matchers. Multiple match - values are ANDed together, meaning, a request must match all the - specified query parameters to select the route. - - - Support: Extended - items: + type: + description: |- + Type identifies the type of filter to apply. As with other API fields, + types are classified into three conformance levels: + + + - Core: Filter types and their corresponding configuration defined by + "Support: Core" in this package, e.g. "RequestHeaderModifier". All + implementations must support core filters. + + + - Extended: Filter types and their corresponding configuration defined by + "Support: Extended" in this package, e.g. "RequestMirror". Implementers + are encouraged to support extended filters. + + + - Implementation-specific: Filters that are defined and supported by + specific vendors. + In the future, filters showing convergence in behavior across multiple + implementations will be considered for inclusion in extended or core + conformance levels. Filter-specific configuration for such filters + is specified using the ExtensionRef field. `Type` should be set to + "ExtensionRef" for custom filters. + + + Implementers are encouraged to define custom implementation types to + extend the core API with implementation-specific behavior. + + + If a reference to a custom filter type cannot be resolved, the filter + MUST NOT be skipped. Instead, requests that would have been processed by + that filter MUST receive a HTTP error response. + + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + enum: + - RequestHeaderModifier + - ResponseHeaderModifier + - RequestMirror + - RequestRedirect + - URLRewrite + - ExtensionRef + type: string + urlRewrite: description: |- - HTTPQueryParamMatch describes how to select a HTTP route by matching HTTP - query parameters. + URLRewrite defines a schema for a filter that modifies a request during forwarding. + + + Support: Extended properties: - name: + hostname: description: |- - Name is the name of the HTTP query param to be matched. This must be an - exact string match. (See - https://tools.ietf.org/html/rfc7230#section-2.7.3). - - - If multiple entries specify equivalent query param names, only the first - entry with an equivalent name MUST be considered for a match. Subsequent - entries with an equivalent query param name MUST be ignored. - - - If a query param is repeated in an HTTP request, the behavior is - purposely left undefined, since different data planes have different - capabilities. However, it is *recommended* that implementations should - match against the first value of the param if the data plane supports it, - as this behavior is expected in other load balancing contexts outside of - the Gateway API. - - - Users SHOULD NOT route traffic based on repeated query params to guard - themselves against potential differences in the implementations. - maxLength: 256 + Hostname is the value to be used to replace the Host header value during + forwarding. + + + Support: Extended + maxLength: 253 minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ type: string + path: + description: |- + Path defines a path rewrite. + + + Support: Extended + properties: + replaceFullPath: + description: |- + ReplaceFullPath specifies the value with which to replace the full path + of a request during a rewrite or redirect. + maxLength: 1024 + type: string + replacePrefixMatch: + description: |- + ReplacePrefixMatch specifies the value with which to replace the prefix + match of a request during a rewrite or redirect. For example, a request + to "/foo/bar" with a prefix match of "/foo" and a ReplacePrefixMatch + of "/xyz" would be modified to "/xyz/bar". + + + Note that this matches the behavior of the PathPrefix match type. This + matches full path elements. A path element refers to the list of labels + in the path split by the `/` separator. When specified, a trailing `/` is + ignored. For example, the paths `/abc`, `/abc/`, and `/abc/def` would all + match the prefix `/abc`, but the path `/abcd` would not. + + + ReplacePrefixMatch is only compatible with a `PathPrefix` HTTPRouteMatch. + Using any other HTTPRouteMatch type on the same HTTPRouteRule will result in + the implementation setting the Accepted Condition for the Route to `status: False`. + + + Request Path | Prefix Match | Replace Prefix | Modified Path + -------------|--------------|----------------|---------- + /foo/bar | /foo | /xyz | /xyz/bar + /foo/bar | /foo | /xyz/ | /xyz/bar + /foo/bar | /foo/ | /xyz | /xyz/bar + /foo/bar | /foo/ | /xyz/ | /xyz/bar + /foo | /foo | /xyz | /xyz + /foo/ | /foo | /xyz | /xyz/ + /foo/bar | /foo | | /bar + /foo/ | /foo | | / + /foo | /foo | | / + /foo/ | /foo | / | / + /foo | /foo | / | / + maxLength: 1024 + type: string + type: + description: |- + Type defines the type of path modifier. Additional types may be + added in a future release of the API. + + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + enum: + - ReplaceFullPath + - ReplacePrefixMatch + type: string + required: + - type + type: object + type: object + required: + - type + type: object + maxItems: 16 + type: array + matches: + description: |- + Matches define conditions used for matching the rule against incoming + HTTP requests. Each match is independent, i.e. this rule will be matched + if **any** one of the matches is satisfied. + + + For example, take the following matches configuration: + + + ``` + matches: + - path: + value: "/foo" + headers: + - name: "version" + value: "v2" + - path: + value: "/v2/foo" + ``` + + + For a request to match against this rule, a request must satisfy + EITHER of the two conditions: + + + - path prefixed with `/foo` AND contains the header `version: v2` + - path prefix of `/v2/foo` + + + See the documentation for HTTPRouteMatch on how to specify multiple + match conditions that should be ANDed together. + + + If no matches are specified, the default is a prefix + path match on "/", which has the effect of matching every + HTTP request. + + + Proxy or Load Balancer routing configuration generated from HTTPRoutes + MUST prioritize matches based on the following criteria, continuing on + ties. Across all rules specified on applicable Routes, precedence must be + given to the match having: + + + * "Exact" path match. + * "Prefix" path match with largest number of characters. + * Method match. + * Largest number of header matches. + * Largest number of query param matches. + + + Note: The precedence of RegularExpression path matches are implementation-specific. + + + If ties still exist across multiple Routes, matching precedence MUST be + determined in order of the following criteria, continuing on ties: + + + * The oldest Route based on creation timestamp. + * The Route appearing first in alphabetical order by + "{namespace}/{name}". + + + If ties still exist within an HTTPRoute, matching precedence MUST be granted + to the FIRST matching rule (in list order) with a match meeting the above + criteria. + + + When no rules matching a request have been successfully attached to the + parent a request is coming from, a HTTP 404 status code MUST be returned. + items: + properties: + headers: + description: |- + Headers specifies HTTP request header matchers. Multiple match values are + ANDed together, meaning, a request must match all the specified headers + to select the route. + items: + description: |- + HTTPHeaderMatch describes how to select a HTTP route by matching HTTP request + headers. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + + If multiple entries specify equivalent header names, only the first + entry with an equivalent name MUST be considered for a match. Subsequent + entries with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + + + When a header is repeated in an HTTP request, it is + implementation-specific behavior as to how this is represented. + Generally, proxies should follow the guidance from the RFC: + https://www.rfc-editor.org/rfc/rfc7230.html#section-3.2.2 regarding + processing a repeated header, with special handling for "Set-Cookie". + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + type: + default: Exact + description: |- + Type specifies how to match against the value of the header. + + + Support: Core (Exact) + + + Support: Implementation-specific (RegularExpression) + + + Since RegularExpression HeaderMatchType has implementation-specific + conformance, implementations can support POSIX, PCRE or any other dialects + of regular expressions. Please read the implementation's documentation to + determine the supported dialect. + enum: + - Exact + - RegularExpression + type: string + value: + description: Value is the value of HTTP Header to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + path: + description: Path specifies a HTTP request path matcher. + properties: type: - default: Exact + default: PathPrefix description: |- - Type specifies how to match against the value of the query parameter. - - - Support: Extended (Exact) - - + Type specifies how to match against the path Value. + + + Support: Core (Exact, PathPrefix) + + Support: Implementation-specific (RegularExpression) - - - Since RegularExpression QueryParamMatchType has Implementation-specific - conformance, implementations can support POSIX, PCRE or any other - dialects of regular expressions. Please read the implementation's - documentation to determine the supported dialect. enum: - - Exact - - RegularExpression + - Exact + - PathPrefix + - RegularExpression type: string value: - description: Value is the value of HTTP query param to be matched. + default: / + description: Value of the HTTP path to match against. maxLength: 1024 - minLength: 1 type: string - required: - - name - - value type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - type: object - maxItems: 8 - type: array - stableTraffic: - description: StableTraffic indicate the base traffic rule - properties: - filters: - description: |- - Filters define the filters that are applied to requests that match - this rule. - - - The effects of ordering of multiple behaviors are currently unspecified. - This can change in the future based on feedback during the alpha stage. - - - Conformance-levels at this level are defined based on the type of filter: - - - - ALL core filters MUST be supported by all implementations. - - Implementers are encouraged to support extended filters. - - Implementation-specific custom filters have no API guarantees across - implementations. - - - Specifying the same filter multiple times is not supported unless explicitly - indicated in the filter. - - - All filters are expected to be compatible with each other except for the - URLRewrite and RequestRedirect filters, which may not be combined. If an - implementation can not support other combinations of filters, they must clearly - document that limitation. In cases where incompatible or unsupported - filters are specified and cause the `Accepted` condition to be set to status - `False`, implementations may use the `IncompatibleFilters` reason to specify - this configuration error. - - - Support: Core - items: - description: |- - HTTPRouteFilter defines processing steps that must be completed during the - request or response lifecycle. HTTPRouteFilters are meant as an extension - point to express processing that may be done in Gateway implementations. Some - examples include request or response modification, implementing - authentication strategies, rate-limiting, and traffic shaping. API - guarantee/conformance is defined based on the type of the filter. - properties: - extensionRef: + queryParams: + description: |- + QueryParams specifies HTTP query parameter matchers. Multiple match + values are ANDed together, meaning, a request must match all the + specified query parameters to select the route. + + + Support: Extended + items: description: |- - ExtensionRef is an optional, implementation-specific extension to the - "filter" behavior. For example, resource "myroutefilter" in group - "networking.example.net"). ExtensionRef MUST NOT be used for core and - extended filters. - - - This filter can be used multiple times within the same rule. - - - Support: Implementation-specific + HTTPQueryParamMatch describes how to select a HTTP route by matching HTTP + query parameters. properties: - group: + name: description: |- - Group is the group of the referent. For example, "gateway.networking.k8s.io". - When unspecified or empty string, core API group is inferred. - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - description: Kind is kind of the referent. For example "HTTPRoute" or "Service". - maxLength: 63 + Name is the name of the HTTP query param to be matched. This must be an + exact string match. (See + https://tools.ietf.org/html/rfc7230#section-2.7.3). + + + If multiple entries specify equivalent query param names, only the first + entry with an equivalent name MUST be considered for a match. Subsequent + entries with an equivalent query param name MUST be ignored. + + + If a query param is repeated in an HTTP request, the behavior is + purposely left undefined, since different data planes have different + capabilities. However, it is *recommended* that implementations should + match against the first value of the param if the data plane supports it, + as this behavior is expected in other load balancing contexts outside of + the Gateway API. + + + Users SHOULD NOT route traffic based on repeated query params to guard + themselves against potential differences in the implementations. + maxLength: 256 minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ type: string - name: - description: Name is the name of the referent. - maxLength: 253 + type: + default: Exact + description: |- + Type specifies how to match against the value of the query parameter. + + + Support: Extended (Exact) + + + Support: Implementation-specific (RegularExpression) + + + Since RegularExpression QueryParamMatchType has Implementation-specific + conformance, implementations can support POSIX, PCRE or any other + dialects of regular expressions. Please read the implementation's + documentation to determine the supported dialect. + enum: + - Exact + - RegularExpression + type: string + value: + description: Value is the value of HTTP query param to be matched. + maxLength: 1024 minLength: 1 type: string required: - - group - - kind - - name + - name + - value type: object - requestHeaderModifier: - description: |- - RequestHeaderModifier defines a schema for a filter that modifies request - headers. - - - Support: Core - properties: - add: - description: |- - Add adds the given header(s) (name, value) to the request - before the action. It appends to any existing values associated - with the header name. - - - Input: - GET /foo HTTP/1.1 - my-header: foo - - - Config: - add: - - name: "my-header" - value: "bar,baz" - - - Output: - GET /foo HTTP/1.1 - my-header: foo,bar,baz - items: - description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. - properties: - name: - description: |- - Name is the name of the HTTP Header to be matched. Name matching MUST be - case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). - - - If multiple entries specify equivalent header names, the first entry with - an equivalent name MUST be considered for a match. Subsequent entries - with an equivalent header name MUST be ignored. Due to the - case-insensitivity of header names, "foo" and "Foo" are considered - equivalent. - maxLength: 256 - minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + type: object + maxItems: 8 + type: array + stableTraffic: + description: StableTraffic indicate the base traffic rule + properties: + filters: + description: |- + Filters define the filters that are applied to requests that match + this rule. + + + The effects of ordering of multiple behaviors are currently unspecified. + This can change in the future based on feedback during the alpha stage. + + + Conformance-levels at this level are defined based on the type of filter: + + + - ALL core filters MUST be supported by all implementations. + - Implementers are encouraged to support extended filters. + - Implementation-specific custom filters have no API guarantees across + implementations. + + + Specifying the same filter multiple times is not supported unless explicitly + indicated in the filter. + + + All filters are expected to be compatible with each other except for the + URLRewrite and RequestRedirect filters, which may not be combined. If an + implementation can not support other combinations of filters, they must clearly + document that limitation. In cases where incompatible or unsupported + filters are specified and cause the `Accepted` condition to be set to status + `False`, implementations may use the `IncompatibleFilters` reason to specify + this configuration error. + + + Support: Core + items: + description: |- + HTTPRouteFilter defines processing steps that must be completed during the + request or response lifecycle. HTTPRouteFilters are meant as an extension + point to express processing that may be done in Gateway implementations. Some + examples include request or response modification, implementing + authentication strategies, rate-limiting, and traffic shaping. API + guarantee/conformance is defined based on the type of the filter. + properties: + extensionRef: + description: |- + ExtensionRef is an optional, implementation-specific extension to the + "filter" behavior. For example, resource "myroutefilter" in group + "networking.example.net"). ExtensionRef MUST NOT be used for core and + extended filters. + + + This filter can be used multiple times within the same rule. + + + Support: Implementation-specific + properties: + group: + description: |- + Group is the group of the referent. For example, "gateway.networking.k8s.io". + When unspecified or empty string, core API group is inferred. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + description: Kind is kind of the referent. For example "HTTPRoute" or "Service". + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: Name is the name of the referent. + maxLength: 253 + minLength: 1 + type: string + required: + - group + - kind + - name + type: object + requestHeaderModifier: + description: |- + RequestHeaderModifier defines a schema for a filter that modifies request + headers. + + + Support: Core + properties: + add: + description: |- + Add adds the given header(s) (name, value) to the request + before the action. It appends to any existing values associated + with the header name. + + + Input: + GET /foo HTTP/1.1 + my-header: foo + + + Config: + add: + - name: "my-header" + value: "bar,baz" + + + Output: + GET /foo HTTP/1.1 + my-header: foo,bar,baz + items: + description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + + If multiple entries specify equivalent header names, the first entry with + an equivalent name MUST be considered for a match. Subsequent entries + with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + description: Value is the value of HTTP Header to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + remove: + description: |- + Remove the given header(s) from the HTTP request before the action. The + value of Remove is a list of HTTP header names. Note that the header + names are case-insensitive (see + https://datatracker.ietf.org/doc/html/rfc2616#section-4.2). + + + Input: + GET /foo HTTP/1.1 + my-header1: foo + my-header2: bar + my-header3: baz + + + Config: + remove: ["my-header1", "my-header3"] + + + Output: + GET /foo HTTP/1.1 + my-header2: bar + items: + type: string + maxItems: 16 + type: array + x-kubernetes-list-type: set + set: + description: |- + Set overwrites the request with the given header (name, value) + before the action. + + + Input: + GET /foo HTTP/1.1 + my-header: foo + + + Config: + set: + - name: "my-header" + value: "bar" + + + Output: + GET /foo HTTP/1.1 + my-header: bar + items: + description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + + If multiple entries specify equivalent header names, the first entry with + an equivalent name MUST be considered for a match. Subsequent entries + with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + description: Value is the value of HTTP Header to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + type: object + requestMirror: + description: |- + RequestMirror defines a schema for a filter that mirrors requests. + Requests are sent to the specified destination, but responses from + that destination are ignored. + + + This filter can be used multiple times within the same rule. Note that + not all implementations will be able to support mirroring to multiple + backends. + + + Support: Extended + + + + properties: + backendRef: + description: |- + BackendRef references a resource where mirrored requests are sent. + + + Mirrored requests must be sent only to a single destination endpoint + within this BackendRef, irrespective of how many endpoints are present + within this BackendRef. + + + If the referent cannot be found, this BackendRef is invalid and must be + dropped from the Gateway. The controller must ensure the "ResolvedRefs" + condition on the Route status is set to `status: False` and not configure + this backend in the underlying implementation. + + + If there is a cross-namespace reference to an *existing* object + that is not allowed by a ReferenceGrant, the controller must ensure the + "ResolvedRefs" condition on the Route is set to `status: False`, + with the "RefNotPermitted" reason and not configure this backend in the + underlying implementation. + + + In either error case, the Message of the `ResolvedRefs` Condition + should be used to provide more detail about the problem. + + + Support: Extended for Kubernetes Service + + + Support: Implementation-specific for any other resource + properties: + group: + default: "" + description: |- + Group is the group of the referent. For example, "gateway.networking.k8s.io". + When unspecified or empty string, core API group is inferred. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + default: Service + description: |- + Kind is the Kubernetes resource kind of the referent. For example + "Service". + + + Defaults to "Service" when not specified. + + + ExternalName services can refer to CNAME DNS records that may live + outside of the cluster and as such are difficult to reason about in + terms of conformance. They also may not be safe to forward to (see + CVE-2021-25740 for more information). Implementations SHOULD NOT + support ExternalName Services. + + + Support: Core (Services with a type other than ExternalName) + + + Support: Implementation-specific (Services with type ExternalName) + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: Name is the name of the referent. + maxLength: 253 + minLength: 1 + type: string + namespace: + description: |- + Namespace is the namespace of the backend. When unspecified, the local + namespace is inferred. + + + Note that when a namespace different than the local namespace is specified, + a ReferenceGrant object is required in the referent namespace to allow that + namespace's owner to accept the reference. See the ReferenceGrant + documentation for details. + + + Support: Core + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + port: + description: |- + Port specifies the destination port number to use for this resource. + Port is required when the referent is a Kubernetes Service. In this + case, the port number is the service port number, not the target port. + For other resources, destination port might be derived from the referent + resource or this field. + format: int32 + maximum: 65535 + minimum: 1 + type: integer + required: + - name + type: object + fraction: + description: |- + Fraction represents the fraction of requests that should be + mirrored to BackendRef. + + + Only one of Fraction or Percent may be specified. If neither field + is specified, 100% of requests will be mirrored. + + + + properties: + denominator: + default: 100 + format: int32 + minimum: 1 + type: integer + numerator: + format: int32 + minimum: 0 + type: integer + required: + - numerator + type: object + percent: + description: |- + Percent represents the percentage of requests that should be + mirrored to BackendRef. Its minimum value is 0 (indicating 0% of + requests) and its maximum value is 100 (indicating 100% of requests). + + + Only one of Fraction or Percent may be specified. If neither field + is specified, 100% of requests will be mirrored. + + + + format: int32 + maximum: 100 + minimum: 0 + type: integer + required: + - backendRef + type: object + requestRedirect: + description: |- + RequestRedirect defines a schema for a filter that responds to the + request with an HTTP redirection. + + + Support: Core + properties: + hostname: + description: |- + Hostname is the hostname to be used in the value of the `Location` + header in the response. + When empty, the hostname in the `Host` header of the request is used. + + + Support: Core + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + path: + description: |- + Path defines parameters used to modify the path of the incoming request. + The modified path is then used to construct the `Location` header. When + empty, the request path is used as-is. + + + Support: Extended + properties: + replaceFullPath: + description: |- + ReplaceFullPath specifies the value with which to replace the full path + of a request during a rewrite or redirect. + maxLength: 1024 + type: string + replacePrefixMatch: + description: |- + ReplacePrefixMatch specifies the value with which to replace the prefix + match of a request during a rewrite or redirect. For example, a request + to "/foo/bar" with a prefix match of "/foo" and a ReplacePrefixMatch + of "/xyz" would be modified to "/xyz/bar". + + + Note that this matches the behavior of the PathPrefix match type. This + matches full path elements. A path element refers to the list of labels + in the path split by the `/` separator. When specified, a trailing `/` is + ignored. For example, the paths `/abc`, `/abc/`, and `/abc/def` would all + match the prefix `/abc`, but the path `/abcd` would not. + + + ReplacePrefixMatch is only compatible with a `PathPrefix` HTTPRouteMatch. + Using any other HTTPRouteMatch type on the same HTTPRouteRule will result in + the implementation setting the Accepted Condition for the Route to `status: False`. + + + Request Path | Prefix Match | Replace Prefix | Modified Path + -------------|--------------|----------------|---------- + /foo/bar | /foo | /xyz | /xyz/bar + /foo/bar | /foo | /xyz/ | /xyz/bar + /foo/bar | /foo/ | /xyz | /xyz/bar + /foo/bar | /foo/ | /xyz/ | /xyz/bar + /foo | /foo | /xyz | /xyz + /foo/ | /foo | /xyz | /xyz/ + /foo/bar | /foo | | /bar + /foo/ | /foo | | / + /foo | /foo | | / + /foo/ | /foo | / | / + /foo | /foo | / | / + maxLength: 1024 + type: string + type: + description: |- + Type defines the type of path modifier. Additional types may be + added in a future release of the API. + + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + enum: + - ReplaceFullPath + - ReplacePrefixMatch + type: string + required: + - type + type: object + port: + description: |- + Port is the port to be used in the value of the `Location` + header in the response. + + + If no port is specified, the redirect port MUST be derived using the + following rules: + + + * If redirect scheme is not-empty, the redirect port MUST be the well-known + port associated with the redirect scheme. Specifically "http" to port 80 + and "https" to port 443. If the redirect scheme does not have a + well-known port, the listener port of the Gateway SHOULD be used. + * If redirect scheme is empty, the redirect port MUST be the Gateway + Listener port. + + + Implementations SHOULD NOT add the port number in the 'Location' + header in the following cases: + + + * A Location header that will use HTTP (whether that is determined via + the Listener protocol or the Scheme field) _and_ use port 80. + * A Location header that will use HTTPS (whether that is determined via + the Listener protocol or the Scheme field) _and_ use port 443. + + + Support: Extended + format: int32 + maximum: 65535 + minimum: 1 + type: integer + scheme: + description: |- + Scheme is the scheme to be used in the value of the `Location` header in + the response. When empty, the scheme of the request is used. + + + Scheme redirects can affect the port of the redirect, for more information, + refer to the documentation for the port field of this filter. + + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + + + Support: Extended + enum: + - http + - https + type: string + statusCode: + default: 302 + description: |- + StatusCode is the HTTP status code to be used in response. + + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + + + Support: Core + enum: + - 301 + - 302 + type: integer + type: object + responseHeaderModifier: + description: |- + ResponseHeaderModifier defines a schema for a filter that modifies response + headers. + + + Support: Extended + properties: + add: + description: |- + Add adds the given header(s) (name, value) to the request + before the action. It appends to any existing values associated + with the header name. + + + Input: + GET /foo HTTP/1.1 + my-header: foo + + + Config: + add: + - name: "my-header" + value: "bar,baz" + + + Output: + GET /foo HTTP/1.1 + my-header: foo,bar,baz + items: + description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + + If multiple entries specify equivalent header names, the first entry with + an equivalent name MUST be considered for a match. Subsequent entries + with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + description: Value is the value of HTTP Header to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + remove: + description: |- + Remove the given header(s) from the HTTP request before the action. The + value of Remove is a list of HTTP header names. Note that the header + names are case-insensitive (see + https://datatracker.ietf.org/doc/html/rfc2616#section-4.2). + + + Input: + GET /foo HTTP/1.1 + my-header1: foo + my-header2: bar + my-header3: baz + + + Config: + remove: ["my-header1", "my-header3"] + + + Output: + GET /foo HTTP/1.1 + my-header2: bar + items: + type: string + maxItems: 16 + type: array + x-kubernetes-list-type: set + set: + description: |- + Set overwrites the request with the given header (name, value) + before the action. + + + Input: + GET /foo HTTP/1.1 + my-header: foo + + + Config: + set: + - name: "my-header" + value: "bar" + + + Output: + GET /foo HTTP/1.1 + my-header: bar + items: + description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + + If multiple entries specify equivalent header names, the first entry with + an equivalent name MUST be considered for a match. Subsequent entries + with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + description: Value is the value of HTTP Header to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + type: object + type: + description: |- + Type identifies the type of filter to apply. As with other API fields, + types are classified into three conformance levels: + + + - Core: Filter types and their corresponding configuration defined by + "Support: Core" in this package, e.g. "RequestHeaderModifier". All + implementations must support core filters. + + + - Extended: Filter types and their corresponding configuration defined by + "Support: Extended" in this package, e.g. "RequestMirror". Implementers + are encouraged to support extended filters. + + + - Implementation-specific: Filters that are defined and supported by + specific vendors. + In the future, filters showing convergence in behavior across multiple + implementations will be considered for inclusion in extended or core + conformance levels. Filter-specific configuration for such filters + is specified using the ExtensionRef field. `Type` should be set to + "ExtensionRef" for custom filters. + + + Implementers are encouraged to define custom implementation types to + extend the core API with implementation-specific behavior. + + + If a reference to a custom filter type cannot be resolved, the filter + MUST NOT be skipped. Instead, requests that would have been processed by + that filter MUST receive a HTTP error response. + + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + enum: + - RequestHeaderModifier + - ResponseHeaderModifier + - RequestMirror + - RequestRedirect + - URLRewrite + - ExtensionRef + type: string + urlRewrite: + description: |- + URLRewrite defines a schema for a filter that modifies a request during forwarding. + + + Support: Extended + properties: + hostname: + description: |- + Hostname is the value to be used to replace the Host header value during + forwarding. + + + Support: Extended + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + path: + description: |- + Path defines a path rewrite. + + + Support: Extended + properties: + replaceFullPath: + description: |- + ReplaceFullPath specifies the value with which to replace the full path + of a request during a rewrite or redirect. + maxLength: 1024 + type: string + replacePrefixMatch: + description: |- + ReplacePrefixMatch specifies the value with which to replace the prefix + match of a request during a rewrite or redirect. For example, a request + to "/foo/bar" with a prefix match of "/foo" and a ReplacePrefixMatch + of "/xyz" would be modified to "/xyz/bar". + + + Note that this matches the behavior of the PathPrefix match type. This + matches full path elements. A path element refers to the list of labels + in the path split by the `/` separator. When specified, a trailing `/` is + ignored. For example, the paths `/abc`, `/abc/`, and `/abc/def` would all + match the prefix `/abc`, but the path `/abcd` would not. + + + ReplacePrefixMatch is only compatible with a `PathPrefix` HTTPRouteMatch. + Using any other HTTPRouteMatch type on the same HTTPRouteRule will result in + the implementation setting the Accepted Condition for the Route to `status: False`. + + + Request Path | Prefix Match | Replace Prefix | Modified Path + -------------|--------------|----------------|---------- + /foo/bar | /foo | /xyz | /xyz/bar + /foo/bar | /foo | /xyz/ | /xyz/bar + /foo/bar | /foo/ | /xyz | /xyz/bar + /foo/bar | /foo/ | /xyz/ | /xyz/bar + /foo | /foo | /xyz | /xyz + /foo/ | /foo | /xyz | /xyz/ + /foo/bar | /foo | | /bar + /foo/ | /foo | | / + /foo | /foo | | / + /foo/ | /foo | / | / + /foo | /foo | / | / + maxLength: 1024 + type: string + type: + description: |- + Type defines the type of path modifier. Additional types may be + added in a future release of the API. + + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + enum: + - ReplaceFullPath + - ReplacePrefixMatch + type: string + required: + - type + type: object + type: object + required: + - type + type: object + maxItems: 16 + type: array + matches: + description: |- + Matches define conditions used for matching the rule against incoming + HTTP requests. Each match is independent, i.e. this rule will be matched + if **any** one of the matches is satisfied. + + + For example, take the following matches configuration: + + + ``` + matches: + - path: + value: "/foo" + headers: + - name: "version" + value: "v2" + - path: + value: "/v2/foo" + ``` + + + For a request to match against this rule, a request must satisfy + EITHER of the two conditions: + + + - path prefixed with `/foo` AND contains the header `version: v2` + - path prefix of `/v2/foo` + + + See the documentation for HTTPRouteMatch on how to specify multiple + match conditions that should be ANDed together. + + + If no matches are specified, the default is a prefix + path match on "/", which has the effect of matching every + HTTP request. + + + Proxy or Load Balancer routing configuration generated from HTTPRoutes + MUST prioritize matches based on the following criteria, continuing on + ties. Across all rules specified on applicable Routes, precedence must be + given to the match having: + + + * "Exact" path match. + * "Prefix" path match with largest number of characters. + * Method match. + * Largest number of header matches. + * Largest number of query param matches. + + + Note: The precedence of RegularExpression path matches are implementation-specific. + + + If ties still exist across multiple Routes, matching precedence MUST be + determined in order of the following criteria, continuing on ties: + + + * The oldest Route based on creation timestamp. + * The Route appearing first in alphabetical order by + "{namespace}/{name}". + + + If ties still exist within an HTTPRoute, matching precedence MUST be granted + to the FIRST matching rule (in list order) with a match meeting the above + criteria. + + + When no rules matching a request have been successfully attached to the + parent a request is coming from, a HTTP 404 status code MUST be returned. + items: + properties: + headers: + description: |- + Headers specifies HTTP request header matchers. Multiple match values are + ANDed together, meaning, a request must match all the specified headers + to select the route. + items: + description: |- + HTTPHeaderMatch describes how to select a HTTP route by matching HTTP request + headers. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + + If multiple entries specify equivalent header names, only the first + entry with an equivalent name MUST be considered for a match. Subsequent + entries with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + + + When a header is repeated in an HTTP request, it is + implementation-specific behavior as to how this is represented. + Generally, proxies should follow the guidance from the RFC: + https://www.rfc-editor.org/rfc/rfc7230.html#section-3.2.2 regarding + processing a repeated header, with special handling for "Set-Cookie". + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + type: + default: Exact + description: |- + Type specifies how to match against the value of the header. + + + Support: Core (Exact) + + + Support: Implementation-specific (RegularExpression) + + + Since RegularExpression HeaderMatchType has implementation-specific + conformance, implementations can support POSIX, PCRE or any other dialects + of regular expressions. Please read the implementation's documentation to + determine the supported dialect. + enum: + - Exact + - RegularExpression + type: string + value: + description: Value is the value of HTTP Header to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + path: + description: Path specifies a HTTP request path matcher. + properties: + type: + default: PathPrefix + description: |- + Type specifies how to match against the path Value. + + + Support: Core (Exact, PathPrefix) + + + Support: Implementation-specific (RegularExpression) + enum: + - Exact + - PathPrefix + - RegularExpression + type: string + value: + default: / + description: Value of the HTTP path to match against. + maxLength: 1024 + type: string + type: object + queryParams: + description: |- + QueryParams specifies HTTP query parameter matchers. Multiple match + values are ANDed together, meaning, a request must match all the + specified query parameters to select the route. + + + Support: Extended + items: + description: |- + HTTPQueryParamMatch describes how to select a HTTP route by matching HTTP + query parameters. + properties: + name: + description: |- + Name is the name of the HTTP query param to be matched. This must be an + exact string match. (See + https://tools.ietf.org/html/rfc7230#section-2.7.3). + + + If multiple entries specify equivalent query param names, only the first + entry with an equivalent name MUST be considered for a match. Subsequent + entries with an equivalent query param name MUST be ignored. + + + If a query param is repeated in an HTTP request, the behavior is + purposely left undefined, since different data planes have different + capabilities. However, it is *recommended* that implementations should + match against the first value of the param if the data plane supports it, + as this behavior is expected in other load balancing contexts outside of + the Gateway API. + + + Users SHOULD NOT route traffic based on repeated query params to guard + themselves against potential differences in the implementations. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + type: + default: Exact + description: |- + Type specifies how to match against the value of the query parameter. + + + Support: Extended (Exact) + + + Support: Implementation-specific (RegularExpression) + + + Since RegularExpression QueryParamMatchType has Implementation-specific + conformance, implementations can support POSIX, PCRE or any other + dialects of regular expressions. Please read the implementation's + documentation to determine the supported dialect. + enum: + - Exact + - RegularExpression + type: string + value: + description: Value is the value of HTTP query param to be matched. + maxLength: 1024 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + type: object + maxItems: 8 + type: array + type: object + weight: + description: Weight indicate how many percentage of traffic the canary pods should receive + format: int32 + maximum: 100 + minimum: 0 + type: integer + type: object + type: object + required: + - replicas + type: object + canaryV2: + description: |- + CanaryV2 defines the canary strategy for upgrade and operation + Mutually exclusive with Canary. + If specified, Canary must be empty. + properties: + properties: + additionalProperties: + type: string + description: Properties contains additional information for step + type: object + targets: + description: rollout targets defines desired target replicas + items: + properties: + matchTargets: + description: Match defines condition used for matching resource cross clusterset + properties: + names: + description: Names is a list of workload name + items: + description: CrossClusterObjectNameReference contains cluster and name reference to a k8s object + properties: + cluster: + description: Cluster indicates the name of cluster + type: string + name: + description: Name is the resource name + type: string + required: + - name + type: object + type: array + selector: + description: Selector is a label query over a set of resources, in this case resource + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + type: object + replicaSlidingWindow: + anyOf: + - type: integer + - type: string + description: |- + ReplicaSlidingWindow used to control the number of pods that are allowed to be upgraded in + a sliding window for progressive rollout smoothly. + x-kubernetes-int-or-string: true + replicas: + anyOf: + - type: integer + - type: string + description: Replicas is the replicas of the rollout task, which represents the number of pods to be upgraded + x-kubernetes-int-or-string: true + required: + - replicas + type: object + type: array + templateMetadataPatch: + description: TemplateMetadataPatch defines a patch for workload template metadata. + properties: + annotations: + additionalProperties: + type: string + description: Annotations are additional metadata that can be included. + type: object + labels: + additionalProperties: + type: string + description: Labels are additional metadata that can be included. + type: object + type: object + traffic: + description: traffic strategy + properties: + http: + properties: + filters: + description: |- + Filters define the filters that are applied to requests that match + this rule. + + + The effects of ordering of multiple behaviors are currently unspecified. + This can change in the future based on feedback during the alpha stage. + + + Conformance-levels at this level are defined based on the type of filter: + + + - ALL core filters MUST be supported by all implementations. + - Implementers are encouraged to support extended filters. + - Implementation-specific custom filters have no API guarantees across + implementations. + + + Specifying the same filter multiple times is not supported unless explicitly + indicated in the filter. + + + All filters are expected to be compatible with each other except for the + URLRewrite and RequestRedirect filters, which may not be combined. If an + implementation can not support other combinations of filters, they must clearly + document that limitation. In cases where incompatible or unsupported + filters are specified and cause the `Accepted` condition to be set to status + `False`, implementations may use the `IncompatibleFilters` reason to specify + this configuration error. + + + Support: Core + items: + description: |- + HTTPRouteFilter defines processing steps that must be completed during the + request or response lifecycle. HTTPRouteFilters are meant as an extension + point to express processing that may be done in Gateway implementations. Some + examples include request or response modification, implementing + authentication strategies, rate-limiting, and traffic shaping. API + guarantee/conformance is defined based on the type of the filter. + properties: + extensionRef: + description: |- + ExtensionRef is an optional, implementation-specific extension to the + "filter" behavior. For example, resource "myroutefilter" in group + "networking.example.net"). ExtensionRef MUST NOT be used for core and + extended filters. + + + This filter can be used multiple times within the same rule. + + + Support: Implementation-specific + properties: + group: + description: |- + Group is the group of the referent. For example, "gateway.networking.k8s.io". + When unspecified or empty string, core API group is inferred. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + description: Kind is kind of the referent. For example "HTTPRoute" or "Service". + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: Name is the name of the referent. + maxLength: 253 + minLength: 1 + type: string + required: + - group + - kind + - name + type: object + requestHeaderModifier: + description: |- + RequestHeaderModifier defines a schema for a filter that modifies request + headers. + + + Support: Core + properties: + add: + description: |- + Add adds the given header(s) (name, value) to the request + before the action. It appends to any existing values associated + with the header name. + + + Input: + GET /foo HTTP/1.1 + my-header: foo + + + Config: + add: + - name: "my-header" + value: "bar,baz" + + + Output: + GET /foo HTTP/1.1 + my-header: foo,bar,baz + items: + description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + + If multiple entries specify equivalent header names, the first entry with + an equivalent name MUST be considered for a match. Subsequent entries + with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + description: Value is the value of HTTP Header to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + remove: + description: |- + Remove the given header(s) from the HTTP request before the action. The + value of Remove is a list of HTTP header names. Note that the header + names are case-insensitive (see + https://datatracker.ietf.org/doc/html/rfc2616#section-4.2). + + + Input: + GET /foo HTTP/1.1 + my-header1: foo + my-header2: bar + my-header3: baz + + + Config: + remove: ["my-header1", "my-header3"] + + + Output: + GET /foo HTTP/1.1 + my-header2: bar + items: + type: string + maxItems: 16 + type: array + x-kubernetes-list-type: set + set: + description: |- + Set overwrites the request with the given header (name, value) + before the action. + + + Input: + GET /foo HTTP/1.1 + my-header: foo + + + Config: + set: + - name: "my-header" + value: "bar" + + + Output: + GET /foo HTTP/1.1 + my-header: bar + items: + description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + + If multiple entries specify equivalent header names, the first entry with + an equivalent name MUST be considered for a match. Subsequent entries + with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + description: Value is the value of HTTP Header to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + type: object + requestMirror: + description: |- + RequestMirror defines a schema for a filter that mirrors requests. + Requests are sent to the specified destination, but responses from + that destination are ignored. + + + This filter can be used multiple times within the same rule. Note that + not all implementations will be able to support mirroring to multiple + backends. + + + Support: Extended + + + + properties: + backendRef: + description: |- + BackendRef references a resource where mirrored requests are sent. + + + Mirrored requests must be sent only to a single destination endpoint + within this BackendRef, irrespective of how many endpoints are present + within this BackendRef. + + + If the referent cannot be found, this BackendRef is invalid and must be + dropped from the Gateway. The controller must ensure the "ResolvedRefs" + condition on the Route status is set to `status: False` and not configure + this backend in the underlying implementation. + + + If there is a cross-namespace reference to an *existing* object + that is not allowed by a ReferenceGrant, the controller must ensure the + "ResolvedRefs" condition on the Route is set to `status: False`, + with the "RefNotPermitted" reason and not configure this backend in the + underlying implementation. + + + In either error case, the Message of the `ResolvedRefs` Condition + should be used to provide more detail about the problem. + + + Support: Extended for Kubernetes Service + + + Support: Implementation-specific for any other resource + properties: + group: + default: "" + description: |- + Group is the group of the referent. For example, "gateway.networking.k8s.io". + When unspecified or empty string, core API group is inferred. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + default: Service + description: |- + Kind is the Kubernetes resource kind of the referent. For example + "Service". + + + Defaults to "Service" when not specified. + + + ExternalName services can refer to CNAME DNS records that may live + outside of the cluster and as such are difficult to reason about in + terms of conformance. They also may not be safe to forward to (see + CVE-2021-25740 for more information). Implementations SHOULD NOT + support ExternalName Services. + + + Support: Core (Services with a type other than ExternalName) + + + Support: Implementation-specific (Services with type ExternalName) + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: Name is the name of the referent. + maxLength: 253 + minLength: 1 + type: string + namespace: + description: |- + Namespace is the namespace of the backend. When unspecified, the local + namespace is inferred. + + + Note that when a namespace different than the local namespace is specified, + a ReferenceGrant object is required in the referent namespace to allow that + namespace's owner to accept the reference. See the ReferenceGrant + documentation for details. + + + Support: Core + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + port: + description: |- + Port specifies the destination port number to use for this resource. + Port is required when the referent is a Kubernetes Service. In this + case, the port number is the service port number, not the target port. + For other resources, destination port might be derived from the referent + resource or this field. + format: int32 + maximum: 65535 + minimum: 1 + type: integer + required: + - name + type: object + fraction: + description: |- + Fraction represents the fraction of requests that should be + mirrored to BackendRef. + + + Only one of Fraction or Percent may be specified. If neither field + is specified, 100% of requests will be mirrored. + + + + properties: + denominator: + default: 100 + format: int32 + minimum: 1 + type: integer + numerator: + format: int32 + minimum: 0 + type: integer + required: + - numerator + type: object + percent: + description: |- + Percent represents the percentage of requests that should be + mirrored to BackendRef. Its minimum value is 0 (indicating 0% of + requests) and its maximum value is 100 (indicating 100% of requests). + + + Only one of Fraction or Percent may be specified. If neither field + is specified, 100% of requests will be mirrored. + + + + format: int32 + maximum: 100 + minimum: 0 + type: integer + required: + - backendRef + type: object + requestRedirect: + description: |- + RequestRedirect defines a schema for a filter that responds to the + request with an HTTP redirection. + + + Support: Core + properties: + hostname: + description: |- + Hostname is the hostname to be used in the value of the `Location` + header in the response. + When empty, the hostname in the `Host` header of the request is used. + + + Support: Core + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + path: + description: |- + Path defines parameters used to modify the path of the incoming request. + The modified path is then used to construct the `Location` header. When + empty, the request path is used as-is. + + + Support: Extended + properties: + replaceFullPath: + description: |- + ReplaceFullPath specifies the value with which to replace the full path + of a request during a rewrite or redirect. + maxLength: 1024 + type: string + replacePrefixMatch: + description: |- + ReplacePrefixMatch specifies the value with which to replace the prefix + match of a request during a rewrite or redirect. For example, a request + to "/foo/bar" with a prefix match of "/foo" and a ReplacePrefixMatch + of "/xyz" would be modified to "/xyz/bar". + + + Note that this matches the behavior of the PathPrefix match type. This + matches full path elements. A path element refers to the list of labels + in the path split by the `/` separator. When specified, a trailing `/` is + ignored. For example, the paths `/abc`, `/abc/`, and `/abc/def` would all + match the prefix `/abc`, but the path `/abcd` would not. + + + ReplacePrefixMatch is only compatible with a `PathPrefix` HTTPRouteMatch. + Using any other HTTPRouteMatch type on the same HTTPRouteRule will result in + the implementation setting the Accepted Condition for the Route to `status: False`. + + + Request Path | Prefix Match | Replace Prefix | Modified Path + -------------|--------------|----------------|---------- + /foo/bar | /foo | /xyz | /xyz/bar + /foo/bar | /foo | /xyz/ | /xyz/bar + /foo/bar | /foo/ | /xyz | /xyz/bar + /foo/bar | /foo/ | /xyz/ | /xyz/bar + /foo | /foo | /xyz | /xyz + /foo/ | /foo | /xyz | /xyz/ + /foo/bar | /foo | | /bar + /foo/ | /foo | | / + /foo | /foo | | / + /foo/ | /foo | / | / + /foo | /foo | / | / + maxLength: 1024 + type: string + type: + description: |- + Type defines the type of path modifier. Additional types may be + added in a future release of the API. + + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + enum: + - ReplaceFullPath + - ReplacePrefixMatch + type: string + required: + - type + type: object + port: + description: |- + Port is the port to be used in the value of the `Location` + header in the response. + + + If no port is specified, the redirect port MUST be derived using the + following rules: + + + * If redirect scheme is not-empty, the redirect port MUST be the well-known + port associated with the redirect scheme. Specifically "http" to port 80 + and "https" to port 443. If the redirect scheme does not have a + well-known port, the listener port of the Gateway SHOULD be used. + * If redirect scheme is empty, the redirect port MUST be the Gateway + Listener port. + + + Implementations SHOULD NOT add the port number in the 'Location' + header in the following cases: + + + * A Location header that will use HTTP (whether that is determined via + the Listener protocol or the Scheme field) _and_ use port 80. + * A Location header that will use HTTPS (whether that is determined via + the Listener protocol or the Scheme field) _and_ use port 443. + + + Support: Extended + format: int32 + maximum: 65535 + minimum: 1 + type: integer + scheme: + description: |- + Scheme is the scheme to be used in the value of the `Location` header in + the response. When empty, the scheme of the request is used. + + + Scheme redirects can affect the port of the redirect, for more information, + refer to the documentation for the port field of this filter. + + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + + + Support: Extended + enum: + - http + - https + type: string + statusCode: + default: 302 + description: |- + StatusCode is the HTTP status code to be used in response. + + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + + + Support: Core + enum: + - 301 + - 302 + type: integer + type: object + responseHeaderModifier: + description: |- + ResponseHeaderModifier defines a schema for a filter that modifies response + headers. + + + Support: Extended + properties: + add: + description: |- + Add adds the given header(s) (name, value) to the request + before the action. It appends to any existing values associated + with the header name. + + + Input: + GET /foo HTTP/1.1 + my-header: foo + + + Config: + add: + - name: "my-header" + value: "bar,baz" + + + Output: + GET /foo HTTP/1.1 + my-header: foo,bar,baz + items: + description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + + If multiple entries specify equivalent header names, the first entry with + an equivalent name MUST be considered for a match. Subsequent entries + with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + description: Value is the value of HTTP Header to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + remove: + description: |- + Remove the given header(s) from the HTTP request before the action. The + value of Remove is a list of HTTP header names. Note that the header + names are case-insensitive (see + https://datatracker.ietf.org/doc/html/rfc2616#section-4.2). + + + Input: + GET /foo HTTP/1.1 + my-header1: foo + my-header2: bar + my-header3: baz + + + Config: + remove: ["my-header1", "my-header3"] + + + Output: + GET /foo HTTP/1.1 + my-header2: bar + items: + type: string + maxItems: 16 + type: array + x-kubernetes-list-type: set + set: + description: |- + Set overwrites the request with the given header (name, value) + before the action. + + + Input: + GET /foo HTTP/1.1 + my-header: foo + + + Config: + set: + - name: "my-header" + value: "bar" + + + Output: + GET /foo HTTP/1.1 + my-header: bar + items: + description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + + If multiple entries specify equivalent header names, the first entry with + an equivalent name MUST be considered for a match. Subsequent entries + with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + description: Value is the value of HTTP Header to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + type: object + type: + description: |- + Type identifies the type of filter to apply. As with other API fields, + types are classified into three conformance levels: + + + - Core: Filter types and their corresponding configuration defined by + "Support: Core" in this package, e.g. "RequestHeaderModifier". All + implementations must support core filters. + + + - Extended: Filter types and their corresponding configuration defined by + "Support: Extended" in this package, e.g. "RequestMirror". Implementers + are encouraged to support extended filters. + + + - Implementation-specific: Filters that are defined and supported by + specific vendors. + In the future, filters showing convergence in behavior across multiple + implementations will be considered for inclusion in extended or core + conformance levels. Filter-specific configuration for such filters + is specified using the ExtensionRef field. `Type` should be set to + "ExtensionRef" for custom filters. + + + Implementers are encouraged to define custom implementation types to + extend the core API with implementation-specific behavior. + + + If a reference to a custom filter type cannot be resolved, the filter + MUST NOT be skipped. Instead, requests that would have been processed by + that filter MUST receive a HTTP error response. + + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + enum: + - RequestHeaderModifier + - ResponseHeaderModifier + - RequestMirror + - RequestRedirect + - URLRewrite + - ExtensionRef + type: string + urlRewrite: + description: |- + URLRewrite defines a schema for a filter that modifies a request during forwarding. + + + Support: Extended + properties: + hostname: + description: |- + Hostname is the value to be used to replace the Host header value during + forwarding. + + + Support: Extended + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + path: + description: |- + Path defines a path rewrite. + + + Support: Extended + properties: + replaceFullPath: + description: |- + ReplaceFullPath specifies the value with which to replace the full path + of a request during a rewrite or redirect. + maxLength: 1024 + type: string + replacePrefixMatch: + description: |- + ReplacePrefixMatch specifies the value with which to replace the prefix + match of a request during a rewrite or redirect. For example, a request + to "/foo/bar" with a prefix match of "/foo" and a ReplacePrefixMatch + of "/xyz" would be modified to "/xyz/bar". + + + Note that this matches the behavior of the PathPrefix match type. This + matches full path elements. A path element refers to the list of labels + in the path split by the `/` separator. When specified, a trailing `/` is + ignored. For example, the paths `/abc`, `/abc/`, and `/abc/def` would all + match the prefix `/abc`, but the path `/abcd` would not. + + + ReplacePrefixMatch is only compatible with a `PathPrefix` HTTPRouteMatch. + Using any other HTTPRouteMatch type on the same HTTPRouteRule will result in + the implementation setting the Accepted Condition for the Route to `status: False`. + + + Request Path | Prefix Match | Replace Prefix | Modified Path + -------------|--------------|----------------|---------- + /foo/bar | /foo | /xyz | /xyz/bar + /foo/bar | /foo | /xyz/ | /xyz/bar + /foo/bar | /foo/ | /xyz | /xyz/bar + /foo/bar | /foo/ | /xyz/ | /xyz/bar + /foo | /foo | /xyz | /xyz + /foo/ | /foo | /xyz | /xyz/ + /foo/bar | /foo | | /bar + /foo/ | /foo | | / + /foo | /foo | | / + /foo/ | /foo | / | / + /foo | /foo | / | / + maxLength: 1024 + type: string + type: + description: |- + Type defines the type of path modifier. Additional types may be + added in a future release of the API. + + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + enum: + - ReplaceFullPath + - ReplacePrefixMatch + type: string + required: + - type + type: object + type: object + required: + - type + type: object + maxItems: 16 + type: array + matches: + description: |- + Matches define conditions used for matching the rule against incoming + HTTP requests. Each match is independent, i.e. this rule will be matched + if **any** one of the matches is satisfied. + + + For example, take the following matches configuration: + + + ``` + matches: + - path: + value: "/foo" + headers: + - name: "version" + value: "v2" + - path: + value: "/v2/foo" + ``` + + + For a request to match against this rule, a request must satisfy + EITHER of the two conditions: + + + - path prefixed with `/foo` AND contains the header `version: v2` + - path prefix of `/v2/foo` + + + See the documentation for HTTPRouteMatch on how to specify multiple + match conditions that should be ANDed together. + + + If no matches are specified, the default is a prefix + path match on "/", which has the effect of matching every + HTTP request. + + + Proxy or Load Balancer routing configuration generated from HTTPRoutes + MUST prioritize matches based on the following criteria, continuing on + ties. Across all rules specified on applicable Routes, precedence must be + given to the match having: + + + * "Exact" path match. + * "Prefix" path match with largest number of characters. + * Method match. + * Largest number of header matches. + * Largest number of query param matches. + + + Note: The precedence of RegularExpression path matches are implementation-specific. + + + If ties still exist across multiple Routes, matching precedence MUST be + determined in order of the following criteria, continuing on ties: + + + * The oldest Route based on creation timestamp. + * The Route appearing first in alphabetical order by + "{namespace}/{name}". + + + If ties still exist within an HTTPRoute, matching precedence MUST be granted + to the FIRST matching rule (in list order) with a match meeting the above + criteria. + + + When no rules matching a request have been successfully attached to the + parent a request is coming from, a HTTP 404 status code MUST be returned. + items: + properties: + headers: + description: |- + Headers specifies HTTP request header matchers. Multiple match values are + ANDed together, meaning, a request must match all the specified headers + to select the route. + items: + description: |- + HTTPHeaderMatch describes how to select a HTTP route by matching HTTP request + headers. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + + If multiple entries specify equivalent header names, only the first + entry with an equivalent name MUST be considered for a match. Subsequent + entries with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + + + When a header is repeated in an HTTP request, it is + implementation-specific behavior as to how this is represented. + Generally, proxies should follow the guidance from the RFC: + https://www.rfc-editor.org/rfc/rfc7230.html#section-3.2.2 regarding + processing a repeated header, with special handling for "Set-Cookie". + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + type: + default: Exact + description: |- + Type specifies how to match against the value of the header. + + + Support: Core (Exact) + + + Support: Implementation-specific (RegularExpression) + + + Since RegularExpression HeaderMatchType has implementation-specific + conformance, implementations can support POSIX, PCRE or any other dialects + of regular expressions. Please read the implementation's documentation to + determine the supported dialect. + enum: + - Exact + - RegularExpression + type: string + value: + description: Value is the value of HTTP Header to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + path: + description: Path specifies a HTTP request path matcher. + properties: + type: + default: PathPrefix + description: |- + Type specifies how to match against the path Value. + + + Support: Core (Exact, PathPrefix) + + + Support: Implementation-specific (RegularExpression) + enum: + - Exact + - PathPrefix + - RegularExpression + type: string + value: + default: / + description: Value of the HTTP path to match against. + maxLength: 1024 + type: string + type: object + queryParams: + description: |- + QueryParams specifies HTTP query parameter matchers. Multiple match + values are ANDed together, meaning, a request must match all the + specified query parameters to select the route. + + + Support: Extended + items: + description: |- + HTTPQueryParamMatch describes how to select a HTTP route by matching HTTP + query parameters. + properties: + name: + description: |- + Name is the name of the HTTP query param to be matched. This must be an + exact string match. (See + https://tools.ietf.org/html/rfc7230#section-2.7.3). + + + If multiple entries specify equivalent query param names, only the first + entry with an equivalent name MUST be considered for a match. Subsequent + entries with an equivalent query param name MUST be ignored. + + + If a query param is repeated in an HTTP request, the behavior is + purposely left undefined, since different data planes have different + capabilities. However, it is *recommended* that implementations should + match against the first value of the param if the data plane supports it, + as this behavior is expected in other load balancing contexts outside of + the Gateway API. + + + Users SHOULD NOT route traffic based on repeated query params to guard + themselves against potential differences in the implementations. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + type: + default: Exact + description: |- + Type specifies how to match against the value of the query parameter. + + + Support: Extended (Exact) + + + Support: Implementation-specific (RegularExpression) + + + Since RegularExpression QueryParamMatchType has Implementation-specific + conformance, implementations can support POSIX, PCRE or any other + dialects of regular expressions. Please read the implementation's + documentation to determine the supported dialect. + enum: + - Exact + - RegularExpression + type: string + value: + description: Value is the value of HTTP query param to be matched. + maxLength: 1024 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + type: object + maxItems: 8 + type: array + stableTraffic: + description: StableTraffic indicate the base traffic rule + properties: + filters: + description: |- + Filters define the filters that are applied to requests that match + this rule. + + + The effects of ordering of multiple behaviors are currently unspecified. + This can change in the future based on feedback during the alpha stage. + + + Conformance-levels at this level are defined based on the type of filter: + + + - ALL core filters MUST be supported by all implementations. + - Implementers are encouraged to support extended filters. + - Implementation-specific custom filters have no API guarantees across + implementations. + + + Specifying the same filter multiple times is not supported unless explicitly + indicated in the filter. + + + All filters are expected to be compatible with each other except for the + URLRewrite and RequestRedirect filters, which may not be combined. If an + implementation can not support other combinations of filters, they must clearly + document that limitation. In cases where incompatible or unsupported + filters are specified and cause the `Accepted` condition to be set to status + `False`, implementations may use the `IncompatibleFilters` reason to specify + this configuration error. + + + Support: Core + items: + description: |- + HTTPRouteFilter defines processing steps that must be completed during the + request or response lifecycle. HTTPRouteFilters are meant as an extension + point to express processing that may be done in Gateway implementations. Some + examples include request or response modification, implementing + authentication strategies, rate-limiting, and traffic shaping. API + guarantee/conformance is defined based on the type of the filter. + properties: + extensionRef: + description: |- + ExtensionRef is an optional, implementation-specific extension to the + "filter" behavior. For example, resource "myroutefilter" in group + "networking.example.net"). ExtensionRef MUST NOT be used for core and + extended filters. + + + This filter can be used multiple times within the same rule. + + + Support: Implementation-specific + properties: + group: + description: |- + Group is the group of the referent. For example, "gateway.networking.k8s.io". + When unspecified or empty string, core API group is inferred. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + description: Kind is kind of the referent. For example "HTTPRoute" or "Service". + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: Name is the name of the referent. + maxLength: 253 + minLength: 1 + type: string + required: + - group + - kind + - name + type: object + requestHeaderModifier: + description: |- + RequestHeaderModifier defines a schema for a filter that modifies request + headers. + + + Support: Core + properties: + add: + description: |- + Add adds the given header(s) (name, value) to the request + before the action. It appends to any existing values associated + with the header name. + + + Input: + GET /foo HTTP/1.1 + my-header: foo + + + Config: + add: + - name: "my-header" + value: "bar,baz" + + + Output: + GET /foo HTTP/1.1 + my-header: foo,bar,baz + items: + description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + + If multiple entries specify equivalent header names, the first entry with + an equivalent name MUST be considered for a match. Subsequent entries + with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + description: Value is the value of HTTP Header to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + remove: + description: |- + Remove the given header(s) from the HTTP request before the action. The + value of Remove is a list of HTTP header names. Note that the header + names are case-insensitive (see + https://datatracker.ietf.org/doc/html/rfc2616#section-4.2). + + + Input: + GET /foo HTTP/1.1 + my-header1: foo + my-header2: bar + my-header3: baz + + + Config: + remove: ["my-header1", "my-header3"] + + + Output: + GET /foo HTTP/1.1 + my-header2: bar + items: + type: string + maxItems: 16 + type: array + x-kubernetes-list-type: set + set: + description: |- + Set overwrites the request with the given header (name, value) + before the action. + + + Input: + GET /foo HTTP/1.1 + my-header: foo + + + Config: + set: + - name: "my-header" + value: "bar" + + + Output: + GET /foo HTTP/1.1 + my-header: bar + items: + description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + + If multiple entries specify equivalent header names, the first entry with + an equivalent name MUST be considered for a match. Subsequent entries + with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + description: Value is the value of HTTP Header to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + type: object + requestMirror: + description: |- + RequestMirror defines a schema for a filter that mirrors requests. + Requests are sent to the specified destination, but responses from + that destination are ignored. + + + This filter can be used multiple times within the same rule. Note that + not all implementations will be able to support mirroring to multiple + backends. + + + Support: Extended + + + + properties: + backendRef: + description: |- + BackendRef references a resource where mirrored requests are sent. + + + Mirrored requests must be sent only to a single destination endpoint + within this BackendRef, irrespective of how many endpoints are present + within this BackendRef. + + + If the referent cannot be found, this BackendRef is invalid and must be + dropped from the Gateway. The controller must ensure the "ResolvedRefs" + condition on the Route status is set to `status: False` and not configure + this backend in the underlying implementation. + + + If there is a cross-namespace reference to an *existing* object + that is not allowed by a ReferenceGrant, the controller must ensure the + "ResolvedRefs" condition on the Route is set to `status: False`, + with the "RefNotPermitted" reason and not configure this backend in the + underlying implementation. + + + In either error case, the Message of the `ResolvedRefs` Condition + should be used to provide more detail about the problem. + + + Support: Extended for Kubernetes Service + + + Support: Implementation-specific for any other resource + properties: + group: + default: "" + description: |- + Group is the group of the referent. For example, "gateway.networking.k8s.io". + When unspecified or empty string, core API group is inferred. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ type: string - value: - description: Value is the value of HTTP Header to be matched. - maxLength: 4096 + kind: + default: Service + description: |- + Kind is the Kubernetes resource kind of the referent. For example + "Service". + + + Defaults to "Service" when not specified. + + + ExternalName services can refer to CNAME DNS records that may live + outside of the cluster and as such are difficult to reason about in + terms of conformance. They also may not be safe to forward to (see + CVE-2021-25740 for more information). Implementations SHOULD NOT + support ExternalName Services. + + + Support: Core (Services with a type other than ExternalName) + + + Support: Implementation-specific (Services with type ExternalName) + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: Name is the name of the referent. + maxLength: 253 minLength: 1 type: string + namespace: + description: |- + Namespace is the namespace of the backend. When unspecified, the local + namespace is inferred. + + + Note that when a namespace different than the local namespace is specified, + a ReferenceGrant object is required in the referent namespace to allow that + namespace's owner to accept the reference. See the ReferenceGrant + documentation for details. + + + Support: Core + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + port: + description: |- + Port specifies the destination port number to use for this resource. + Port is required when the referent is a Kubernetes Service. In this + case, the port number is the service port number, not the target port. + For other resources, destination port might be derived from the referent + resource or this field. + format: int32 + maximum: 65535 + minimum: 1 + type: integer required: - - name - - value + - name type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - remove: - description: |- - Remove the given header(s) from the HTTP request before the action. The - value of Remove is a list of HTTP header names. Note that the header - names are case-insensitive (see - https://datatracker.ietf.org/doc/html/rfc2616#section-4.2). - - - Input: - GET /foo HTTP/1.1 - my-header1: foo - my-header2: bar - my-header3: baz - - - Config: - remove: ["my-header1", "my-header3"] - - - Output: - GET /foo HTTP/1.1 - my-header2: bar - items: + fraction: + description: |- + Fraction represents the fraction of requests that should be + mirrored to BackendRef. + + + Only one of Fraction or Percent may be specified. If neither field + is specified, 100% of requests will be mirrored. + + + + properties: + denominator: + default: 100 + format: int32 + minimum: 1 + type: integer + numerator: + format: int32 + minimum: 0 + type: integer + required: + - numerator + type: object + percent: + description: |- + Percent represents the percentage of requests that should be + mirrored to BackendRef. Its minimum value is 0 (indicating 0% of + requests) and its maximum value is 100 (indicating 100% of requests). + + + Only one of Fraction or Percent may be specified. If neither field + is specified, 100% of requests will be mirrored. + + + + format: int32 + maximum: 100 + minimum: 0 + type: integer + required: + - backendRef + type: object + requestRedirect: + description: |- + RequestRedirect defines a schema for a filter that responds to the + request with an HTTP redirection. + + + Support: Core + properties: + hostname: + description: |- + Hostname is the hostname to be used in the value of the `Location` + header in the response. + When empty, the hostname in the `Host` header of the request is used. + + + Support: Core + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ type: string - maxItems: 16 - type: array - x-kubernetes-list-type: set - set: - description: |- - Set overwrites the request with the given header (name, value) - before the action. - - - Input: - GET /foo HTTP/1.1 - my-header: foo - - - Config: - set: - - name: "my-header" - value: "bar" - - - Output: - GET /foo HTTP/1.1 - my-header: bar - items: - description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. + path: + description: |- + Path defines parameters used to modify the path of the incoming request. + The modified path is then used to construct the `Location` header. When + empty, the request path is used as-is. + + + Support: Extended properties: - name: + replaceFullPath: description: |- - Name is the name of the HTTP Header to be matched. Name matching MUST be - case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). - - - If multiple entries specify equivalent header names, the first entry with - an equivalent name MUST be considered for a match. Subsequent entries - with an equivalent header name MUST be ignored. Due to the - case-insensitivity of header names, "foo" and "Foo" are considered - equivalent. - maxLength: 256 - minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + ReplaceFullPath specifies the value with which to replace the full path + of a request during a rewrite or redirect. + maxLength: 1024 + type: string + replacePrefixMatch: + description: |- + ReplacePrefixMatch specifies the value with which to replace the prefix + match of a request during a rewrite or redirect. For example, a request + to "/foo/bar" with a prefix match of "/foo" and a ReplacePrefixMatch + of "/xyz" would be modified to "/xyz/bar". + + + Note that this matches the behavior of the PathPrefix match type. This + matches full path elements. A path element refers to the list of labels + in the path split by the `/` separator. When specified, a trailing `/` is + ignored. For example, the paths `/abc`, `/abc/`, and `/abc/def` would all + match the prefix `/abc`, but the path `/abcd` would not. + + + ReplacePrefixMatch is only compatible with a `PathPrefix` HTTPRouteMatch. + Using any other HTTPRouteMatch type on the same HTTPRouteRule will result in + the implementation setting the Accepted Condition for the Route to `status: False`. + + + Request Path | Prefix Match | Replace Prefix | Modified Path + -------------|--------------|----------------|---------- + /foo/bar | /foo | /xyz | /xyz/bar + /foo/bar | /foo | /xyz/ | /xyz/bar + /foo/bar | /foo/ | /xyz | /xyz/bar + /foo/bar | /foo/ | /xyz/ | /xyz/bar + /foo | /foo | /xyz | /xyz + /foo/ | /foo | /xyz | /xyz/ + /foo/bar | /foo | | /bar + /foo/ | /foo | | / + /foo | /foo | | / + /foo/ | /foo | / | / + /foo | /foo | / | / + maxLength: 1024 type: string - value: - description: Value is the value of HTTP Header to be matched. - maxLength: 4096 - minLength: 1 + type: + description: |- + Type defines the type of path modifier. Additional types may be + added in a future release of the API. + + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + enum: + - ReplaceFullPath + - ReplacePrefixMatch type: string required: - - name - - value + - type type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - type: object - requestMirror: - description: |- - RequestMirror defines a schema for a filter that mirrors requests. - Requests are sent to the specified destination, but responses from - that destination are ignored. - - - This filter can be used multiple times within the same rule. Note that - not all implementations will be able to support mirroring to multiple - backends. - - - Support: Extended - - - - properties: - backendRef: - description: |- - BackendRef references a resource where mirrored requests are sent. - - - Mirrored requests must be sent only to a single destination endpoint - within this BackendRef, irrespective of how many endpoints are present - within this BackendRef. - - - If the referent cannot be found, this BackendRef is invalid and must be - dropped from the Gateway. The controller must ensure the "ResolvedRefs" - condition on the Route status is set to `status: False` and not configure - this backend in the underlying implementation. - - - If there is a cross-namespace reference to an *existing* object - that is not allowed by a ReferenceGrant, the controller must ensure the - "ResolvedRefs" condition on the Route is set to `status: False`, - with the "RefNotPermitted" reason and not configure this backend in the - underlying implementation. - - - In either error case, the Message of the `ResolvedRefs` Condition - should be used to provide more detail about the problem. - - - Support: Extended for Kubernetes Service - - - Support: Implementation-specific for any other resource - properties: - group: - default: "" - description: |- - Group is the group of the referent. For example, "gateway.networking.k8s.io". - When unspecified or empty string, core API group is inferred. - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - default: Service - description: |- - Kind is the Kubernetes resource kind of the referent. For example - "Service". - - - Defaults to "Service" when not specified. - - - ExternalName services can refer to CNAME DNS records that may live - outside of the cluster and as such are difficult to reason about in - terms of conformance. They also may not be safe to forward to (see - CVE-2021-25740 for more information). Implementations SHOULD NOT - support ExternalName Services. - - - Support: Core (Services with a type other than ExternalName) - - - Support: Implementation-specific (Services with type ExternalName) - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - type: string - name: - description: Name is the name of the referent. - maxLength: 253 - minLength: 1 - type: string - namespace: - description: |- - Namespace is the namespace of the backend. When unspecified, the local - namespace is inferred. - - - Note that when a namespace different than the local namespace is specified, - a ReferenceGrant object is required in the referent namespace to allow that - namespace's owner to accept the reference. See the ReferenceGrant - documentation for details. - - - Support: Core - maxLength: 63 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ - type: string - port: - description: |- - Port specifies the destination port number to use for this resource. - Port is required when the referent is a Kubernetes Service. In this - case, the port number is the service port number, not the target port. - For other resources, destination port might be derived from the referent - resource or this field. - format: int32 - maximum: 65535 - minimum: 1 - type: integer - required: - - name - type: object - fraction: - description: |- - Fraction represents the fraction of requests that should be - mirrored to BackendRef. - - - Only one of Fraction or Percent may be specified. If neither field - is specified, 100% of requests will be mirrored. - - - - properties: - denominator: - default: 100 - format: int32 - minimum: 1 - type: integer - numerator: - format: int32 - minimum: 0 - type: integer - required: - - numerator - type: object - percent: - description: |- - Percent represents the percentage of requests that should be - mirrored to BackendRef. Its minimum value is 0 (indicating 0% of - requests) and its maximum value is 100 (indicating 100% of requests). - - - Only one of Fraction or Percent may be specified. If neither field - is specified, 100% of requests will be mirrored. - - - - format: int32 - maximum: 100 - minimum: 0 - type: integer - required: - - backendRef - type: object - requestRedirect: - description: |- - RequestRedirect defines a schema for a filter that responds to the - request with an HTTP redirection. - - - Support: Core - properties: - hostname: - description: |- - Hostname is the hostname to be used in the value of the `Location` - header in the response. - When empty, the hostname in the `Host` header of the request is used. - - - Support: Core - maxLength: 253 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - path: - description: |- - Path defines parameters used to modify the path of the incoming request. - The modified path is then used to construct the `Location` header. When - empty, the request path is used as-is. - - - Support: Extended - properties: - replaceFullPath: - description: |- - ReplaceFullPath specifies the value with which to replace the full path - of a request during a rewrite or redirect. - maxLength: 1024 - type: string - replacePrefixMatch: - description: |- - ReplacePrefixMatch specifies the value with which to replace the prefix - match of a request during a rewrite or redirect. For example, a request - to "/foo/bar" with a prefix match of "/foo" and a ReplacePrefixMatch - of "/xyz" would be modified to "/xyz/bar". - - - Note that this matches the behavior of the PathPrefix match type. This - matches full path elements. A path element refers to the list of labels - in the path split by the `/` separator. When specified, a trailing `/` is - ignored. For example, the paths `/abc`, `/abc/`, and `/abc/def` would all - match the prefix `/abc`, but the path `/abcd` would not. - - - ReplacePrefixMatch is only compatible with a `PathPrefix` HTTPRouteMatch. - Using any other HTTPRouteMatch type on the same HTTPRouteRule will result in - the implementation setting the Accepted Condition for the Route to `status: False`. - - - Request Path | Prefix Match | Replace Prefix | Modified Path - -------------|--------------|----------------|---------- - /foo/bar | /foo | /xyz | /xyz/bar - /foo/bar | /foo | /xyz/ | /xyz/bar - /foo/bar | /foo/ | /xyz | /xyz/bar - /foo/bar | /foo/ | /xyz/ | /xyz/bar - /foo | /foo | /xyz | /xyz - /foo/ | /foo | /xyz | /xyz/ - /foo/bar | /foo | | /bar - /foo/ | /foo | | / - /foo | /foo | | / - /foo/ | /foo | / | / - /foo | /foo | / | / - maxLength: 1024 - type: string - type: - description: |- - Type defines the type of path modifier. Additional types may be - added in a future release of the API. - - - Note that values may be added to this enum, implementations - must ensure that unknown values will not cause a crash. - - - Unknown values here must result in the implementation setting the - Accepted Condition for the Route to `status: False`, with a - Reason of `UnsupportedValue`. - enum: - - ReplaceFullPath - - ReplacePrefixMatch - type: string - required: - - type - type: object - port: - description: |- - Port is the port to be used in the value of the `Location` - header in the response. - - - If no port is specified, the redirect port MUST be derived using the - following rules: - - - * If redirect scheme is not-empty, the redirect port MUST be the well-known - port associated with the redirect scheme. Specifically "http" to port 80 - and "https" to port 443. If the redirect scheme does not have a - well-known port, the listener port of the Gateway SHOULD be used. - * If redirect scheme is empty, the redirect port MUST be the Gateway - Listener port. - - - Implementations SHOULD NOT add the port number in the 'Location' - header in the following cases: - - - * A Location header that will use HTTP (whether that is determined via - the Listener protocol or the Scheme field) _and_ use port 80. - * A Location header that will use HTTPS (whether that is determined via - the Listener protocol or the Scheme field) _and_ use port 443. - - - Support: Extended - format: int32 - maximum: 65535 - minimum: 1 - type: integer - scheme: - description: |- - Scheme is the scheme to be used in the value of the `Location` header in - the response. When empty, the scheme of the request is used. - - - Scheme redirects can affect the port of the redirect, for more information, - refer to the documentation for the port field of this filter. - - - Note that values may be added to this enum, implementations - must ensure that unknown values will not cause a crash. - - - Unknown values here must result in the implementation setting the - Accepted Condition for the Route to `status: False`, with a - Reason of `UnsupportedValue`. - - - Support: Extended - enum: - - http - - https - type: string - statusCode: - default: 302 - description: |- - StatusCode is the HTTP status code to be used in response. - - - Note that values may be added to this enum, implementations - must ensure that unknown values will not cause a crash. - - - Unknown values here must result in the implementation setting the - Accepted Condition for the Route to `status: False`, with a - Reason of `UnsupportedValue`. - - - Support: Core - enum: - - 301 - - 302 - type: integer - type: object - responseHeaderModifier: - description: |- - ResponseHeaderModifier defines a schema for a filter that modifies response - headers. - - - Support: Extended - properties: - add: - description: |- - Add adds the given header(s) (name, value) to the request - before the action. It appends to any existing values associated - with the header name. - - - Input: - GET /foo HTTP/1.1 - my-header: foo - - - Config: - add: - - name: "my-header" - value: "bar,baz" - - - Output: - GET /foo HTTP/1.1 - my-header: foo,bar,baz - items: - description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. + port: + description: |- + Port is the port to be used in the value of the `Location` + header in the response. + + + If no port is specified, the redirect port MUST be derived using the + following rules: + + + * If redirect scheme is not-empty, the redirect port MUST be the well-known + port associated with the redirect scheme. Specifically "http" to port 80 + and "https" to port 443. If the redirect scheme does not have a + well-known port, the listener port of the Gateway SHOULD be used. + * If redirect scheme is empty, the redirect port MUST be the Gateway + Listener port. + + + Implementations SHOULD NOT add the port number in the 'Location' + header in the following cases: + + + * A Location header that will use HTTP (whether that is determined via + the Listener protocol or the Scheme field) _and_ use port 80. + * A Location header that will use HTTPS (whether that is determined via + the Listener protocol or the Scheme field) _and_ use port 443. + + + Support: Extended + format: int32 + maximum: 65535 + minimum: 1 + type: integer + scheme: + description: |- + Scheme is the scheme to be used in the value of the `Location` header in + the response. When empty, the scheme of the request is used. + + + Scheme redirects can affect the port of the redirect, for more information, + refer to the documentation for the port field of this filter. + + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + + + Support: Extended + enum: + - http + - https + type: string + statusCode: + default: 302 + description: |- + StatusCode is the HTTP status code to be used in response. + + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + + + Support: Core + enum: + - 301 + - 302 + type: integer + type: object + responseHeaderModifier: + description: |- + ResponseHeaderModifier defines a schema for a filter that modifies response + headers. + + + Support: Extended + properties: + add: + description: |- + Add adds the given header(s) (name, value) to the request + before the action. It appends to any existing values associated + with the header name. + + + Input: + GET /foo HTTP/1.1 + my-header: foo + + + Config: + add: + - name: "my-header" + value: "bar,baz" + + + Output: + GET /foo HTTP/1.1 + my-header: foo,bar,baz + items: + description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + + If multiple entries specify equivalent header names, the first entry with + an equivalent name MUST be considered for a match. Subsequent entries + with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + description: Value is the value of HTTP Header to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + remove: + description: |- + Remove the given header(s) from the HTTP request before the action. The + value of Remove is a list of HTTP header names. Note that the header + names are case-insensitive (see + https://datatracker.ietf.org/doc/html/rfc2616#section-4.2). + + + Input: + GET /foo HTTP/1.1 + my-header1: foo + my-header2: bar + my-header3: baz + + + Config: + remove: ["my-header1", "my-header3"] + + + Output: + GET /foo HTTP/1.1 + my-header2: bar + items: + type: string + maxItems: 16 + type: array + x-kubernetes-list-type: set + set: + description: |- + Set overwrites the request with the given header (name, value) + before the action. + + + Input: + GET /foo HTTP/1.1 + my-header: foo + + + Config: + set: + - name: "my-header" + value: "bar" + + + Output: + GET /foo HTTP/1.1 + my-header: bar + items: + description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + + If multiple entries specify equivalent header names, the first entry with + an equivalent name MUST be considered for a match. Subsequent entries + with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + description: Value is the value of HTTP Header to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + type: object + type: + description: |- + Type identifies the type of filter to apply. As with other API fields, + types are classified into three conformance levels: + + + - Core: Filter types and their corresponding configuration defined by + "Support: Core" in this package, e.g. "RequestHeaderModifier". All + implementations must support core filters. + + + - Extended: Filter types and their corresponding configuration defined by + "Support: Extended" in this package, e.g. "RequestMirror". Implementers + are encouraged to support extended filters. + + + - Implementation-specific: Filters that are defined and supported by + specific vendors. + In the future, filters showing convergence in behavior across multiple + implementations will be considered for inclusion in extended or core + conformance levels. Filter-specific configuration for such filters + is specified using the ExtensionRef field. `Type` should be set to + "ExtensionRef" for custom filters. + + + Implementers are encouraged to define custom implementation types to + extend the core API with implementation-specific behavior. + + + If a reference to a custom filter type cannot be resolved, the filter + MUST NOT be skipped. Instead, requests that would have been processed by + that filter MUST receive a HTTP error response. + + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + enum: + - RequestHeaderModifier + - ResponseHeaderModifier + - RequestMirror + - RequestRedirect + - URLRewrite + - ExtensionRef + type: string + urlRewrite: + description: |- + URLRewrite defines a schema for a filter that modifies a request during forwarding. + + + Support: Extended + properties: + hostname: + description: |- + Hostname is the value to be used to replace the Host header value during + forwarding. + + + Support: Extended + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + path: + description: |- + Path defines a path rewrite. + + + Support: Extended properties: - name: + replaceFullPath: description: |- - Name is the name of the HTTP Header to be matched. Name matching MUST be - case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). - - - If multiple entries specify equivalent header names, the first entry with - an equivalent name MUST be considered for a match. Subsequent entries - with an equivalent header name MUST be ignored. Due to the - case-insensitivity of header names, "foo" and "Foo" are considered - equivalent. - maxLength: 256 - minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ - type: string - value: - description: Value is the value of HTTP Header to be matched. - maxLength: 4096 - minLength: 1 + ReplaceFullPath specifies the value with which to replace the full path + of a request during a rewrite or redirect. + maxLength: 1024 type: string - required: - - name - - value - type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - remove: - description: |- - Remove the given header(s) from the HTTP request before the action. The - value of Remove is a list of HTTP header names. Note that the header - names are case-insensitive (see - https://datatracker.ietf.org/doc/html/rfc2616#section-4.2). - - - Input: - GET /foo HTTP/1.1 - my-header1: foo - my-header2: bar - my-header3: baz - - - Config: - remove: ["my-header1", "my-header3"] - - - Output: - GET /foo HTTP/1.1 - my-header2: bar - items: - type: string - maxItems: 16 - type: array - x-kubernetes-list-type: set - set: - description: |- - Set overwrites the request with the given header (name, value) - before the action. - - - Input: - GET /foo HTTP/1.1 - my-header: foo - - - Config: - set: - - name: "my-header" - value: "bar" - - - Output: - GET /foo HTTP/1.1 - my-header: bar - items: - description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. - properties: - name: + replacePrefixMatch: description: |- - Name is the name of the HTTP Header to be matched. Name matching MUST be - case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). - - - If multiple entries specify equivalent header names, the first entry with - an equivalent name MUST be considered for a match. Subsequent entries - with an equivalent header name MUST be ignored. Due to the - case-insensitivity of header names, "foo" and "Foo" are considered - equivalent. - maxLength: 256 - minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + ReplacePrefixMatch specifies the value with which to replace the prefix + match of a request during a rewrite or redirect. For example, a request + to "/foo/bar" with a prefix match of "/foo" and a ReplacePrefixMatch + of "/xyz" would be modified to "/xyz/bar". + + + Note that this matches the behavior of the PathPrefix match type. This + matches full path elements. A path element refers to the list of labels + in the path split by the `/` separator. When specified, a trailing `/` is + ignored. For example, the paths `/abc`, `/abc/`, and `/abc/def` would all + match the prefix `/abc`, but the path `/abcd` would not. + + + ReplacePrefixMatch is only compatible with a `PathPrefix` HTTPRouteMatch. + Using any other HTTPRouteMatch type on the same HTTPRouteRule will result in + the implementation setting the Accepted Condition for the Route to `status: False`. + + + Request Path | Prefix Match | Replace Prefix | Modified Path + -------------|--------------|----------------|---------- + /foo/bar | /foo | /xyz | /xyz/bar + /foo/bar | /foo | /xyz/ | /xyz/bar + /foo/bar | /foo/ | /xyz | /xyz/bar + /foo/bar | /foo/ | /xyz/ | /xyz/bar + /foo | /foo | /xyz | /xyz + /foo/ | /foo | /xyz | /xyz/ + /foo/bar | /foo | | /bar + /foo/ | /foo | | / + /foo | /foo | | / + /foo/ | /foo | / | / + /foo | /foo | / | / + maxLength: 1024 type: string - value: - description: Value is the value of HTTP Header to be matched. - maxLength: 4096 - minLength: 1 + type: + description: |- + Type defines the type of path modifier. Additional types may be + added in a future release of the API. + + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + enum: + - ReplaceFullPath + - ReplacePrefixMatch type: string required: - - name - - value + - type type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - type: object - type: - description: |- - Type identifies the type of filter to apply. As with other API fields, - types are classified into three conformance levels: - - - - Core: Filter types and their corresponding configuration defined by - "Support: Core" in this package, e.g. "RequestHeaderModifier". All - implementations must support core filters. - - - - Extended: Filter types and their corresponding configuration defined by - "Support: Extended" in this package, e.g. "RequestMirror". Implementers - are encouraged to support extended filters. - - - - Implementation-specific: Filters that are defined and supported by - specific vendors. - In the future, filters showing convergence in behavior across multiple - implementations will be considered for inclusion in extended or core - conformance levels. Filter-specific configuration for such filters - is specified using the ExtensionRef field. `Type` should be set to - "ExtensionRef" for custom filters. - - - Implementers are encouraged to define custom implementation types to - extend the core API with implementation-specific behavior. - - - If a reference to a custom filter type cannot be resolved, the filter - MUST NOT be skipped. Instead, requests that would have been processed by - that filter MUST receive a HTTP error response. - - - Note that values may be added to this enum, implementations - must ensure that unknown values will not cause a crash. - - - Unknown values here must result in the implementation setting the - Accepted Condition for the Route to `status: False`, with a - Reason of `UnsupportedValue`. - enum: - - RequestHeaderModifier - - ResponseHeaderModifier - - RequestMirror - - RequestRedirect - - URLRewrite - - ExtensionRef - type: string - urlRewrite: - description: |- - URLRewrite defines a schema for a filter that modifies a request during forwarding. - - - Support: Extended - properties: - hostname: - description: |- - Hostname is the value to be used to replace the Host header value during - forwarding. - - - Support: Extended - maxLength: 253 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - path: + type: object + required: + - type + type: object + maxItems: 16 + type: array + matches: + description: |- + Matches define conditions used for matching the rule against incoming + HTTP requests. Each match is independent, i.e. this rule will be matched + if **any** one of the matches is satisfied. + + + For example, take the following matches configuration: + + + ``` + matches: + - path: + value: "/foo" + headers: + - name: "version" + value: "v2" + - path: + value: "/v2/foo" + ``` + + + For a request to match against this rule, a request must satisfy + EITHER of the two conditions: + + + - path prefixed with `/foo` AND contains the header `version: v2` + - path prefix of `/v2/foo` + + + See the documentation for HTTPRouteMatch on how to specify multiple + match conditions that should be ANDed together. + + + If no matches are specified, the default is a prefix + path match on "/", which has the effect of matching every + HTTP request. + + + Proxy or Load Balancer routing configuration generated from HTTPRoutes + MUST prioritize matches based on the following criteria, continuing on + ties. Across all rules specified on applicable Routes, precedence must be + given to the match having: + + + * "Exact" path match. + * "Prefix" path match with largest number of characters. + * Method match. + * Largest number of header matches. + * Largest number of query param matches. + + + Note: The precedence of RegularExpression path matches are implementation-specific. + + + If ties still exist across multiple Routes, matching precedence MUST be + determined in order of the following criteria, continuing on ties: + + + * The oldest Route based on creation timestamp. + * The Route appearing first in alphabetical order by + "{namespace}/{name}". + + + If ties still exist within an HTTPRoute, matching precedence MUST be granted + to the FIRST matching rule (in list order) with a match meeting the above + criteria. + + + When no rules matching a request have been successfully attached to the + parent a request is coming from, a HTTP 404 status code MUST be returned. + items: + properties: + headers: + description: |- + Headers specifies HTTP request header matchers. Multiple match values are + ANDed together, meaning, a request must match all the specified headers + to select the route. + items: description: |- - Path defines a path rewrite. - - - Support: Extended + HTTPHeaderMatch describes how to select a HTTP route by matching HTTP request + headers. properties: - replaceFullPath: - description: |- - ReplaceFullPath specifies the value with which to replace the full path - of a request during a rewrite or redirect. - maxLength: 1024 - type: string - replacePrefixMatch: + name: description: |- - ReplacePrefixMatch specifies the value with which to replace the prefix - match of a request during a rewrite or redirect. For example, a request - to "/foo/bar" with a prefix match of "/foo" and a ReplacePrefixMatch - of "/xyz" would be modified to "/xyz/bar". - - - Note that this matches the behavior of the PathPrefix match type. This - matches full path elements. A path element refers to the list of labels - in the path split by the `/` separator. When specified, a trailing `/` is - ignored. For example, the paths `/abc`, `/abc/`, and `/abc/def` would all - match the prefix `/abc`, but the path `/abcd` would not. - - - ReplacePrefixMatch is only compatible with a `PathPrefix` HTTPRouteMatch. - Using any other HTTPRouteMatch type on the same HTTPRouteRule will result in - the implementation setting the Accepted Condition for the Route to `status: False`. - - - Request Path | Prefix Match | Replace Prefix | Modified Path - -------------|--------------|----------------|---------- - /foo/bar | /foo | /xyz | /xyz/bar - /foo/bar | /foo | /xyz/ | /xyz/bar - /foo/bar | /foo/ | /xyz | /xyz/bar - /foo/bar | /foo/ | /xyz/ | /xyz/bar - /foo | /foo | /xyz | /xyz - /foo/ | /foo | /xyz | /xyz/ - /foo/bar | /foo | | /bar - /foo/ | /foo | | / - /foo | /foo | | / - /foo/ | /foo | / | / - /foo | /foo | / | / - maxLength: 1024 + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + + If multiple entries specify equivalent header names, only the first + entry with an equivalent name MUST be considered for a match. Subsequent + entries with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + + + When a header is repeated in an HTTP request, it is + implementation-specific behavior as to how this is represented. + Generally, proxies should follow the guidance from the RFC: + https://www.rfc-editor.org/rfc/rfc7230.html#section-3.2.2 regarding + processing a repeated header, with special handling for "Set-Cookie". + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ type: string type: + default: Exact description: |- - Type defines the type of path modifier. Additional types may be - added in a future release of the API. - - - Note that values may be added to this enum, implementations - must ensure that unknown values will not cause a crash. - - - Unknown values here must result in the implementation setting the - Accepted Condition for the Route to `status: False`, with a - Reason of `UnsupportedValue`. + Type specifies how to match against the value of the header. + + + Support: Core (Exact) + + + Support: Implementation-specific (RegularExpression) + + + Since RegularExpression HeaderMatchType has implementation-specific + conformance, implementations can support POSIX, PCRE or any other dialects + of regular expressions. Please read the implementation's documentation to + determine the supported dialect. enum: - - ReplaceFullPath - - ReplacePrefixMatch + - Exact + - RegularExpression + type: string + value: + description: Value is the value of HTTP Header to be matched. + maxLength: 4096 + minLength: 1 type: string required: - - type + - name + - value type: object - type: object - required: - - type - type: object - maxItems: 16 - type: array - matches: - description: |- - Matches define conditions used for matching the rule against incoming - HTTP requests. Each match is independent, i.e. this rule will be matched - if **any** one of the matches is satisfied. - - - For example, take the following matches configuration: - - - ``` - matches: - - path: - value: "/foo" - headers: - - name: "version" - value: "v2" - - path: - value: "/v2/foo" - ``` - - - For a request to match against this rule, a request must satisfy - EITHER of the two conditions: - - - - path prefixed with `/foo` AND contains the header `version: v2` - - path prefix of `/v2/foo` - - - See the documentation for HTTPRouteMatch on how to specify multiple - match conditions that should be ANDed together. - - - If no matches are specified, the default is a prefix - path match on "/", which has the effect of matching every - HTTP request. - - - Proxy or Load Balancer routing configuration generated from HTTPRoutes - MUST prioritize matches based on the following criteria, continuing on - ties. Across all rules specified on applicable Routes, precedence must be - given to the match having: - - - * "Exact" path match. - * "Prefix" path match with largest number of characters. - * Method match. - * Largest number of header matches. - * Largest number of query param matches. - - - Note: The precedence of RegularExpression path matches are implementation-specific. - - - If ties still exist across multiple Routes, matching precedence MUST be - determined in order of the following criteria, continuing on ties: - - - * The oldest Route based on creation timestamp. - * The Route appearing first in alphabetical order by - "{namespace}/{name}". - - - If ties still exist within an HTTPRoute, matching precedence MUST be granted - to the FIRST matching rule (in list order) with a match meeting the above - criteria. - - - When no rules matching a request have been successfully attached to the - parent a request is coming from, a HTTP 404 status code MUST be returned. - items: - properties: - headers: - description: |- - Headers specifies HTTP request header matchers. Multiple match values are - ANDed together, meaning, a request must match all the specified headers - to select the route. - items: - description: |- - HTTPHeaderMatch describes how to select a HTTP route by matching HTTP request - headers. - properties: - name: - description: |- - Name is the name of the HTTP Header to be matched. Name matching MUST be - case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). - - - If multiple entries specify equivalent header names, only the first - entry with an equivalent name MUST be considered for a match. Subsequent - entries with an equivalent header name MUST be ignored. Due to the - case-insensitivity of header names, "foo" and "Foo" are considered - equivalent. - - - When a header is repeated in an HTTP request, it is - implementation-specific behavior as to how this is represented. - Generally, proxies should follow the guidance from the RFC: - https://www.rfc-editor.org/rfc/rfc7230.html#section-3.2.2 regarding - processing a repeated header, with special handling for "Set-Cookie". - maxLength: 256 - minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ - type: string - type: - default: Exact - description: |- - Type specifies how to match against the value of the header. - - - Support: Core (Exact) - - - Support: Implementation-specific (RegularExpression) - - - Since RegularExpression HeaderMatchType has implementation-specific - conformance, implementations can support POSIX, PCRE or any other dialects - of regular expressions. Please read the implementation's documentation to - determine the supported dialect. - enum: - - Exact - - RegularExpression - type: string - value: - description: Value is the value of HTTP Header to be matched. - maxLength: 4096 - minLength: 1 - type: string - required: - - name - - value - type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - path: - description: Path specifies a HTTP request path matcher. - properties: - type: - default: PathPrefix - description: |- - Type specifies how to match against the path Value. - - - Support: Core (Exact, PathPrefix) - - - Support: Implementation-specific (RegularExpression) - enum: - - Exact - - PathPrefix - - RegularExpression - type: string - value: - default: / - description: Value of the HTTP path to match against. - maxLength: 1024 - type: string - type: object - queryParams: - description: |- - QueryParams specifies HTTP query parameter matchers. Multiple match - values are ANDed together, meaning, a request must match all the - specified query parameters to select the route. - - - Support: Extended - items: - description: |- - HTTPQueryParamMatch describes how to select a HTTP route by matching HTTP - query parameters. + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + path: + description: Path specifies a HTTP request path matcher. properties: - name: - description: |- - Name is the name of the HTTP query param to be matched. This must be an - exact string match. (See - https://tools.ietf.org/html/rfc7230#section-2.7.3). - - - If multiple entries specify equivalent query param names, only the first - entry with an equivalent name MUST be considered for a match. Subsequent - entries with an equivalent query param name MUST be ignored. - - - If a query param is repeated in an HTTP request, the behavior is - purposely left undefined, since different data planes have different - capabilities. However, it is *recommended* that implementations should - match against the first value of the param if the data plane supports it, - as this behavior is expected in other load balancing contexts outside of - the Gateway API. - - - Users SHOULD NOT route traffic based on repeated query params to guard - themselves against potential differences in the implementations. - maxLength: 256 - minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ - type: string type: - default: Exact + default: PathPrefix description: |- - Type specifies how to match against the value of the query parameter. - - - Support: Extended (Exact) - - + Type specifies how to match against the path Value. + + + Support: Core (Exact, PathPrefix) + + Support: Implementation-specific (RegularExpression) - - - Since RegularExpression QueryParamMatchType has Implementation-specific - conformance, implementations can support POSIX, PCRE or any other - dialects of regular expressions. Please read the implementation's - documentation to determine the supported dialect. enum: - - Exact - - RegularExpression + - Exact + - PathPrefix + - RegularExpression type: string value: - description: Value is the value of HTTP query param to be matched. + default: / + description: Value of the HTTP path to match against. maxLength: 1024 - minLength: 1 type: string - required: - - name - - value type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - type: object - maxItems: 8 - type: array - type: object - weight: - description: Weight indicate how many percentage of traffic the canary pods should receive + queryParams: + description: |- + QueryParams specifies HTTP query parameter matchers. Multiple match + values are ANDed together, meaning, a request must match all the + specified query parameters to select the route. + + + Support: Extended + items: + description: |- + HTTPQueryParamMatch describes how to select a HTTP route by matching HTTP + query parameters. + properties: + name: + description: |- + Name is the name of the HTTP query param to be matched. This must be an + exact string match. (See + https://tools.ietf.org/html/rfc7230#section-2.7.3). + + + If multiple entries specify equivalent query param names, only the first + entry with an equivalent name MUST be considered for a match. Subsequent + entries with an equivalent query param name MUST be ignored. + + + If a query param is repeated in an HTTP request, the behavior is + purposely left undefined, since different data planes have different + capabilities. However, it is *recommended* that implementations should + match against the first value of the param if the data plane supports it, + as this behavior is expected in other load balancing contexts outside of + the Gateway API. + + + Users SHOULD NOT route traffic based on repeated query params to guard + themselves against potential differences in the implementations. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + type: + default: Exact + description: |- + Type specifies how to match against the value of the query parameter. + + + Support: Extended (Exact) + + + Support: Implementation-specific (RegularExpression) + + + Since RegularExpression QueryParamMatchType has Implementation-specific + conformance, implementations can support POSIX, PCRE or any other + dialects of regular expressions. Please read the implementation's + documentation to determine the supported dialect. + enum: + - Exact + - RegularExpression + type: string + value: + description: Value is the value of HTTP query param to be matched. + maxLength: 1024 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + type: object + maxItems: 8 + type: array + type: object + weight: + description: Weight indicate how many percentage of traffic the canary pods should receive + format: int32 + maximum: 100 + minimum: 0 + type: integer + type: object + type: object + required: + - targets + type: object + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + webhooks: + description: Webhooks defines + items: + properties: + clientConfig: + description: |- + ClientConfig defines how to communicate with the hook. + Required + properties: + caBundle: + description: |- + `caBundle` is a PEM encoded CA bundle which will be used to validate the webhook's server certificate. + If unspecified, system trust roots' CA on the node. + format: byte + type: string + periodSeconds: + default: 10 + description: |- + How often (in seconds) to perform the probe. + Default to 10 seconds. Minimum value is 1. + format: int32 + minimum: 1 + type: integer + timeoutSeconds: + default: 10 + description: |- + TimeoutSeconds specifies the timeout for this webhook. After the timeout passes, + the webhook call will be ignored or the API call will fail based on the + failure policy. format: int32 - maximum: 100 - minimum: 0 type: integer + url: + description: |- + `url` gives the location of the webhook, in standard URL form + (`scheme://host:port/path`). Exactly one of `url` or `service` + must be specified. + + + The `host` should not refer to a service running in the cluster; use + the `service` field instead. The host might be resolved via external + DNS in some apiservers (e.g., `kube-apiserver` cannot resolve + in-cluster DNS as that would be a layering violation). `host` may + also be an IP address. + + + Please note that using `localhost` or `127.0.0.1` as a `host` is + risky unless you take great care to run this webhook on all hosts + which run an apiserver which might need to make calls to this + webhook. Such installs are likely to be non-portable, i.e., not easy + to turn up in a new cluster. + + + The scheme must be "https"; the URL must begin with "https://". + + + A path is optional, and if present may be any string permissible in + a URL. You may use the path to pass an arbitrary string to the + webhook, for example, a cluster identifier. + + + Attempting to use a user or basic auth e.g. "user:password@" is not + allowed. Fragments ("#...") and query parameters ("?...") are not + allowed, either. + type: string type: object - type: object - required: - - replicas - type: object - kind: - description: |- - Kind is a string value representing the REST resource this object represents. - Servers may infer this from the endpoint the client submits requests to. - Cannot be updated. - In CamelCase. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - type: string - metadata: - type: object - webhooks: - description: Webhooks defines - items: - properties: - clientConfig: - description: |- - ClientConfig defines how to communicate with the hook. - Required - properties: - caBundle: - description: |- - `caBundle` is a PEM encoded CA bundle which will be used to validate the webhook's server certificate. - If unspecified, system trust roots' CA on the node. - format: byte - type: string - periodSeconds: - default: 10 - description: |- - How often (in seconds) to perform the probe. - Default to 10 seconds. Minimum value is 1. - format: int32 - minimum: 1 - type: integer - timeoutSeconds: - default: 10 - description: |- - TimeoutSeconds specifies the timeout for this webhook. After the timeout passes, - the webhook call will be ignored or the API call will fail based on the - failure policy. - format: int32 - type: integer - url: - description: |- - `url` gives the location of the webhook, in standard URL form - (`scheme://host:port/path`). Exactly one of `url` or `service` - must be specified. - - - The `host` should not refer to a service running in the cluster; use - the `service` field instead. The host might be resolved via external - DNS in some apiservers (e.g., `kube-apiserver` cannot resolve - in-cluster DNS as that would be a layering violation). `host` may - also be an IP address. - - - Please note that using `localhost` or `127.0.0.1` as a `host` is - risky unless you take great care to run this webhook on all hosts - which run an apiserver which might need to make calls to this - webhook. Such installs are likely to be non-portable, i.e., not easy - to turn up in a new cluster. - - - The scheme must be "https"; the URL must begin with "https://". - - - A path is optional, and if present may be any string permissible in - a URL. You may use the path to pass an arbitrary string to the - webhook, for example, a cluster identifier. - - - Attempting to use a user or basic auth e.g. "user:password@" is not - allowed. Fragments ("#...") and query parameters ("?...") are not - allowed, either. + failurePolicy: + description: |- + FailurePolicy defines how unrecognized errors from the admission endpoint are handled - + allowed values are Ignore or Fail. Defaults to Ignore. + type: string + failureThreshold: + default: 3 + description: |- + Minimum consecutive failures for the probe to be considered failed after having succeeded. + Defaults to 3. Minimum value is 1. + format: int32 + minimum: 1 + type: integer + hookTypes: + description: |- + HookTypes defines when to communicate with the hook, specifies the types of events + that trigger the webhook. + Required + items: + description: Webhook type type: string - type: object - failurePolicy: - description: |- - FailurePolicy defines how unrecognized errors from the admission endpoint are handled - - allowed values are Ignore or Fail. Defaults to Ignore. - type: string - failureThreshold: - default: 3 - description: |- - Minimum consecutive failures for the probe to be considered failed after having succeeded. - Defaults to 3. Minimum value is 1. - format: int32 - minimum: 1 - type: integer - hookTypes: - description: |- - HookTypes defines when to communicate with the hook, specifies the types of events - that trigger the webhook. - Required - items: - description: Webhook type + type: array + name: + description: Name is the identity of webhook type: string - type: array - name: - description: Name is the identity of webhook - type: string - properties: - additionalProperties: + properties: + additionalProperties: + type: string + description: Properties provide additional data for webhook. + type: object + provider: + description: |- + By default, rollout communicates with the webhook through the structure RolloutWebhookReview. + If provider is set, then the protocol of the interaction will be determined by the provider type: string - description: Properties provide additional data for webhook. - type: object - provider: - description: |- - By default, rollout communicates with the webhook through the structure RolloutWebhookReview. - If provider is set, then the protocol of the interaction will be determined by the provider - type: string - type: object - type: array - type: object - served: true - storage: true + type: object + type: array + type: object + served: true + storage: true diff --git a/config/kind/workload/bases/rollout.yaml b/config/kind/workload/bases/rollout.yaml index e75a64a..3fb3da0 100644 --- a/config/kind/workload/bases/rollout.yaml +++ b/config/kind/workload/bases/rollout.yaml @@ -1,4 +1,3 @@ - apiVersion: rollout.kusionstack.io/v1alpha1 kind: Rollout metadata: @@ -24,28 +23,33 @@ apiVersion: rollout.kusionstack.io/v1alpha1 kind: RolloutStrategy metadata: name: rollout-demo -canary: - replicas: 2 - templateMetadataPatch: - labels: - service.tag: "canary" - traffic: - http: - filters: - - requestHeaderModifier: - set: - - name: x-mse-tag +spec: + canaryV2: + targets: + - replicas: 2 + templateMetadataPatch: + labels: + service.tag: "canary" + traffic: + http: + filters: + - requestHeaderModifier: + set: + - name: x-mse-tag + value: canary + type: RequestHeaderModifier + matches: + - headers: + - type: Exact + name: env value: canary - type: RequestHeaderModifier - matches: - - headers: - - type: Exact - name: env - value: canary -batch: - batches: - - replicas: 1 - - replicas: 3 - replicaSlidingWindow: 1 - breakpoint: true - - replicas: 100% + batchV2: + batches: + - targets: + - replicas: 1 + - targets: + - replicas: 3 + replicaSlidingWindow: 1 + breakpoint: true + - targets: + - replicas: "100%" \ No newline at end of file diff --git a/config/rbac/role.yaml b/config/rbac/role.yaml index d89efb0..ed015e5 100644 --- a/config/rbac/role.yaml +++ b/config/rbac/role.yaml @@ -119,6 +119,32 @@ rules: - patch - update - watch +- apiGroups: + - rollout.kusionstack.io + resources: + - scaleruns + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - rollout.kusionstack.io + resources: + - scaleruns/finalizers + verbs: + - update +- apiGroups: + - rollout.kusionstack.io + resources: + - scaleruns/status + verbs: + - get + - patch + - update - apiGroups: - rollout.kusionstack.io resources: diff --git a/config/samples/rollout_v1alpha1_rollout.yaml b/config/samples/rollout_v1alpha1_rollout.yaml index 31f8663..057d7e6 100644 --- a/config/samples/rollout_v1alpha1_rollout.yaml +++ b/config/samples/rollout_v1alpha1_rollout.yaml @@ -9,4 +9,11 @@ metadata: app.kubernetes.io/created-by: rollout name: rollout-sample spec: - + strategyRef: rolloutstrategy-sample + triggerPolicy: Auto + workloadRef: + apiVersion: apps/v1 + kind: Deployment + match: + names: + - name: demo \ No newline at end of file diff --git a/config/samples/rollout_v1alpha1_rolloutstrategy.yaml b/config/samples/rollout_v1alpha1_rolloutstrategy.yaml index 47037ce..e7c2c56 100644 --- a/config/samples/rollout_v1alpha1_rolloutstrategy.yaml +++ b/config/samples/rollout_v1alpha1_rolloutstrategy.yaml @@ -9,4 +9,10 @@ metadata: app.kubernetes.io/created-by: rollout name: rolloutstrategy-sample spec: - # TODO(user): Add fields here + batchV2: + batches: + - targets: + - replicas: "30%" + - breakpoint: true + targets: + - replicas: "100%" \ No newline at end of file diff --git a/go.mod b/go.mod index d98a48c..bab9de1 100644 --- a/go.mod +++ b/go.mod @@ -23,7 +23,7 @@ require ( k8s.io/klog/v2 v2.130.1 k8s.io/kubernetes v1.22.2 k8s.io/utils v0.0.0-20241210054802-24370beab758 - kusionstack.io/kube-api v0.7.5-0.20260413084915-e038d5ff4fea + kusionstack.io/kube-api v0.7.5-0.20260506033526-9dc0f832c099 kusionstack.io/kube-utils v0.2.1-0.20251125083928-1134a582b341 kusionstack.io/resourceconsist v0.0.4 sigs.k8s.io/controller-runtime v0.21.0 diff --git a/go.sum b/go.sum index bc4c1f3..df7a930 100644 --- a/go.sum +++ b/go.sum @@ -1021,8 +1021,8 @@ k8s.io/sample-apiserver v0.22.2/go.mod h1:h+/DIV5EmuNq4vfPr5TSXy9mIBVXXlPAKQMPbj k8s.io/system-validators v1.5.0/go.mod h1:bPldcLgkIUK22ALflnsXk8pvkTEndYdNuaHH6gRrl0Q= k8s.io/utils v0.0.0-20240102154912-e7106e64919e h1:eQ/4ljkx21sObifjzXwlPKpdGLrCfRziVtos3ofG/sQ= k8s.io/utils v0.0.0-20240102154912-e7106e64919e/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= -kusionstack.io/kube-api v0.7.5-0.20260413084915-e038d5ff4fea h1:fQ6jQ5QDOPBthYBcz2ibu0F6QbCGMOzcWZLGO2mGZhY= -kusionstack.io/kube-api v0.7.5-0.20260413084915-e038d5ff4fea/go.mod h1:e1jtrQH2LK5fD2nTyfIXG6nYrYbU8VXShRxTRwVPaLk= +kusionstack.io/kube-api v0.7.5-0.20260506033526-9dc0f832c099 h1:FjR10d3zDRX4F+3Q1LCS84l638G6ejSu18Nz0zUt/zQ= +kusionstack.io/kube-api v0.7.5-0.20260506033526-9dc0f832c099/go.mod h1:e1jtrQH2LK5fD2nTyfIXG6nYrYbU8VXShRxTRwVPaLk= kusionstack.io/kube-utils v0.2.1-0.20251125083928-1134a582b341 h1:dnMtHJvIpU3338WpqGiNN2qXWZFiXaoiuzR9jwhvWpg= kusionstack.io/kube-utils v0.2.1-0.20251125083928-1134a582b341/go.mod h1:Lz5SBYWg9+jw+kP0CAyf/b62D5DeUPf6+jE1d0WC4cI= kusionstack.io/resourceconsist v0.0.4 h1:wRqLJuNh8O4TT6p0uOklFpHUKiRdRxcAH71Sw/q9LhE= diff --git a/pkg/controllers/rollout/inline_strategy.go b/pkg/controllers/rollout/inline_strategy.go deleted file mode 100644 index c519d08..0000000 --- a/pkg/controllers/rollout/inline_strategy.go +++ /dev/null @@ -1,192 +0,0 @@ -// Copyright 2025 The KusionStack Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package rollout - -import ( - "fmt" - - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - rolloutapi "kusionstack.io/kube-api/rollout" - rolloutv1alpha1 "kusionstack.io/kube-api/rollout/v1alpha1" - - "kusionstack.io/rollout/pkg/features" - "kusionstack.io/rollout/pkg/features/ontimestrategy" - "kusionstack.io/rollout/pkg/workload" -) - -// constructRolloutRunFromInlineStrategy constructs RolloutRun from inline strategy -// Returns the constructed RolloutRun, a boolean indicating if inline strategy was used, and an error if validation fails -func constructRolloutRunFromInlineStrategy( - obj *rolloutv1alpha1.Rollout, - workloadWrappers []*workload.Info, - rolloutId string, -) (*rolloutv1alpha1.RolloutRun, bool, error) { - if obj.Spec.BatchStrategy == nil { - return nil, false, nil - } - - // Build workload map for validation - workloadMap := buildWorkloadMap(workloadWrappers) - - owner := metav1.NewControllerRef(obj, rolloutv1alpha1.SchemeGroupVersion.WithKind("Rollout")) - run := &rolloutv1alpha1.RolloutRun{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: obj.Namespace, - Name: rolloutId, - Labels: map[string]string{}, - Annotations: map[string]string{}, - OwnerReferences: []metav1.OwnerReference{*owner}, - Finalizers: []string{rolloutapi.FinalizerRolloutProtection}, - }, - Spec: rolloutv1alpha1.RolloutRunSpec{ - TargetType: rolloutv1alpha1.ObjectTypeRef{ - APIVersion: obj.Spec.WorkloadRef.APIVersion, - Kind: obj.Spec.WorkloadRef.Kind, - }, - TrafficTopologyRefs: obj.Spec.TrafficTopologyRefs, - Webhooks: obj.Spec.Webhooks, - }, - } - - if obj.Spec.CanaryStrategy != nil { - canary, err := validateAndCopyCanaryStrategy(obj.Spec.CanaryStrategy, workloadMap) - if err != nil { - return nil, true, err - } - run.Spec.Canary = canary - } - - batch, err := validateAndCopyBatchStrategy(obj.Spec.BatchStrategy, workloadMap) - if err != nil { - return nil, true, err - } - run.Spec.Batch = batch - - // Set OneTimeStrategy annotation for inline batch strategy - if features.DefaultFeatureGate.Enabled(features.OneTimeStrategy) { - onetime := ontimestrategy.ConvertFromInline(run.Spec.Batch) - data := onetime.JSONData() - run.Annotations[ontimestrategy.AnnoOneTimeStrategy] = string(data) - } - - if features.DefaultFeatureGate.Enabled(features.RolloutClassPredicate) { - class, ok := obj.Labels[rolloutapi.LabelRolloutClass] - if ok { - run.Labels[rolloutapi.LabelRolloutClass] = class - } - } - - return run, true, nil -} - -// validateAndCopyCanaryStrategy validates targets and creates a copy for RolloutRun -// For inline strategy, targets are already pre-resolved by user -// Returns error if any target is not found in workloadMap -func validateAndCopyCanaryStrategy( - canary *rolloutv1alpha1.RolloutRunCanaryStrategy, - workloadMap map[string]*workload.Info, -) (*rolloutv1alpha1.RolloutRunCanaryStrategy, error) { - if canary == nil { - return nil, nil - } - - // Validate all targets exist - validatedTargets := make([]rolloutv1alpha1.RolloutRunStepTarget, 0, len(canary.Targets)) - for _, target := range canary.Targets { - key := workloadKey(target.Cluster, target.Name) - if _, exists := workloadMap[key]; !exists { - return nil, fmt.Errorf("canary target cluster=%s name=%s not found in workloads", target.Cluster, target.Name) - } - // Direct copy - targets are already in correct format - validatedTargets = append(validatedTargets, target) - } - - return &rolloutv1alpha1.RolloutRunCanaryStrategy{ - Targets: validatedTargets, - Traffic: canary.Traffic, - Properties: canary.Properties, - TemplateMetadataPatch: canary.TemplateMetadataPatch, - }, nil -} - -// validateAndCopyBatchStrategy validates and creates a copy for RolloutRun -// For inline strategy, targets are already pre-resolved by user -// Returns error if any target is not found in workloadMap -func validateAndCopyBatchStrategy( - batch *rolloutv1alpha1.RolloutRunBatchStrategy, - workloadMap map[string]*workload.Info, -) (*rolloutv1alpha1.RolloutRunBatchStrategy, error) { - if batch == nil { - return nil, nil - } - - if len(batch.Batches) == 0 { - // Return as-is if no batches defined - return &rolloutv1alpha1.RolloutRunBatchStrategy{ - Toleration: batch.Toleration, - Batches: []rolloutv1alpha1.RolloutRunStep{}, - }, nil - } - - validatedBatches := make([]rolloutv1alpha1.RolloutRunStep, 0, len(batch.Batches)) - - for batchIdx, step := range batch.Batches { - if len(step.Targets) == 0 { - // Skip steps without targets - continue - } - - // Validate all targets exist - validatedTargets := make([]rolloutv1alpha1.RolloutRunStepTarget, 0, len(step.Targets)) - for _, target := range step.Targets { - key := workloadKey(target.Cluster, target.Name) - if _, exists := workloadMap[key]; !exists { - return nil, fmt.Errorf("batch[%d] target cluster=%s name=%s not found in workloads", batchIdx, target.Cluster, target.Name) - } - // Direct copy - targets are already in correct format - validatedTargets = append(validatedTargets, target) - } - - if len(validatedTargets) > 0 { - validatedStep := rolloutv1alpha1.RolloutRunStep{ - Targets: validatedTargets, - Traffic: step.Traffic, - Breakpoint: step.Breakpoint, - Properties: step.Properties, - } - validatedBatches = append(validatedBatches, validatedStep) - } - } - - return &rolloutv1alpha1.RolloutRunBatchStrategy{ - Toleration: batch.Toleration, - Batches: validatedBatches, - }, nil -} - -// Helper functions - -func buildWorkloadMap(workloads []*workload.Info) map[string]*workload.Info { - m := make(map[string]*workload.Info) - for _, wl := range workloads { - key := workloadKey(wl.ClusterName, wl.Name) - m[key] = wl - } - return m -} - -func workloadKey(cluster, name string) string { - return cluster + "/" + name -} diff --git a/pkg/controllers/rollout/inline_strategy_test.go b/pkg/controllers/rollout/inline_strategy_test.go deleted file mode 100644 index 8d46673..0000000 --- a/pkg/controllers/rollout/inline_strategy_test.go +++ /dev/null @@ -1,645 +0,0 @@ -// Copyright 2025 The KusionStack Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package rollout - -import ( - "reflect" - "strings" - "testing" - - "github.com/davecgh/go-spew/spew" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/util/intstr" - "k8s.io/utils/ptr" - rolloutv1alpha1 "kusionstack.io/kube-api/rollout/v1alpha1" - - "kusionstack.io/rollout/pkg/workload" -) - -func Test_constructRolloutRunFromInlineStrategy(t *testing.T) { - tests := []struct { - name string - obj *rolloutv1alpha1.Rollout - workloadWrappers []*workload.Info - rolloutId string - wantRun bool - wantCanary bool - wantBatch bool - wantErr bool - errContains string - }{ - { - name: "no inline strategy - return nil, false", - obj: &rolloutv1alpha1.Rollout{ - Spec: rolloutv1alpha1.RolloutSpec{ - StrategyRef: "default-strategy", - WorkloadRef: rolloutv1alpha1.WorkloadRef{ - APIVersion: "apps/v1", - Kind: "Deployment", - }, - }, - }, - workloadWrappers: []*workload.Info{ - newTestInfo("cluster-a", "test", "test-1"), - }, - rolloutId: "test-rollout-1", - wantRun: false, - }, - { - name: "only canary strategy - should return nil (batch strategy required)", - obj: &rolloutv1alpha1.Rollout{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: "test", - Name: "test-rollout", - }, - Spec: rolloutv1alpha1.RolloutSpec{ - WorkloadRef: rolloutv1alpha1.WorkloadRef{ - APIVersion: "apps/v1", - Kind: "Deployment", - }, - CanaryStrategy: &rolloutv1alpha1.RolloutRunCanaryStrategy{ - Targets: []rolloutv1alpha1.RolloutRunStepTarget{ - { - CrossClusterObjectNameReference: rolloutv1alpha1.CrossClusterObjectNameReference{ - Cluster: "cluster-a", - Name: "test-1", - }, - Replicas: intstr.FromString("10%"), - }, - }, - }, - }, - }, - workloadWrappers: []*workload.Info{ - newTestInfo("cluster-a", "test", "test-1"), - }, - rolloutId: "test-rollout-1", - wantRun: false, // Canary alone is not supported, need BatchStrategy - wantCanary: false, - wantBatch: false, - }, - { - name: "only batch strategy", - obj: &rolloutv1alpha1.Rollout{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: "test", - Name: "test-rollout", - }, - Spec: rolloutv1alpha1.RolloutSpec{ - WorkloadRef: rolloutv1alpha1.WorkloadRef{ - APIVersion: "apps/v1", - Kind: "Deployment", - }, - BatchStrategy: &rolloutv1alpha1.RolloutRunBatchStrategy{ - Batches: []rolloutv1alpha1.RolloutRunStep{ - { - Breakpoint: true, - Targets: []rolloutv1alpha1.RolloutRunStepTarget{ - { - CrossClusterObjectNameReference: rolloutv1alpha1.CrossClusterObjectNameReference{ - Cluster: "cluster-a", - Name: "test-1", - }, - Replicas: intstr.FromString("20%"), - }, - }, - }, - { - Targets: []rolloutv1alpha1.RolloutRunStepTarget{ - { - CrossClusterObjectNameReference: rolloutv1alpha1.CrossClusterObjectNameReference{ - Cluster: "cluster-a", - Name: "test-1", - }, - Replicas: intstr.FromString("100%"), - }, - }, - }, - }, - }, - }, - }, - workloadWrappers: []*workload.Info{ - newTestInfo("cluster-a", "test", "test-1"), - }, - rolloutId: "test-rollout-1", - wantRun: true, - wantCanary: false, - wantBatch: true, - }, - { - name: "canary + batch strategy together", - obj: &rolloutv1alpha1.Rollout{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: "test", - Name: "test-rollout", - }, - Spec: rolloutv1alpha1.RolloutSpec{ - WorkloadRef: rolloutv1alpha1.WorkloadRef{ - APIVersion: "apps/v1", - Kind: "Deployment", - }, - CanaryStrategy: &rolloutv1alpha1.RolloutRunCanaryStrategy{ - Targets: []rolloutv1alpha1.RolloutRunStepTarget{ - { - CrossClusterObjectNameReference: rolloutv1alpha1.CrossClusterObjectNameReference{ - Cluster: "cluster-a", - Name: "test-1", - }, - Replicas: intstr.FromString("5%"), - }, - }, - }, - BatchStrategy: &rolloutv1alpha1.RolloutRunBatchStrategy{ - Batches: []rolloutv1alpha1.RolloutRunStep{ - { - Breakpoint: true, - Targets: []rolloutv1alpha1.RolloutRunStepTarget{ - { - CrossClusterObjectNameReference: rolloutv1alpha1.CrossClusterObjectNameReference{ - Cluster: "cluster-a", - Name: "test-1", - }, - Replicas: intstr.FromString("25%"), - }, - }, - }, - }, - }, - }, - }, - workloadWrappers: []*workload.Info{ - newTestInfo("cluster-a", "test", "test-1"), - }, - rolloutId: "test-rollout-1", - wantRun: true, - wantCanary: true, - wantBatch: true, - }, - { - name: "non-existent workload should error", - obj: &rolloutv1alpha1.Rollout{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: "test", - Name: "test-rollout", - }, - Spec: rolloutv1alpha1.RolloutSpec{ - WorkloadRef: rolloutv1alpha1.WorkloadRef{ - APIVersion: "apps/v1", - Kind: "Deployment", - }, - BatchStrategy: &rolloutv1alpha1.RolloutRunBatchStrategy{ - Batches: []rolloutv1alpha1.RolloutRunStep{ - { - Targets: []rolloutv1alpha1.RolloutRunStepTarget{ - { - CrossClusterObjectNameReference: rolloutv1alpha1.CrossClusterObjectNameReference{ - Cluster: "cluster-a", - Name: "test-1", - }, - Replicas: intstr.FromString("20%"), - }, - { - CrossClusterObjectNameReference: rolloutv1alpha1.CrossClusterObjectNameReference{ - Cluster: "cluster-b", // This workload doesn't exist - Name: "test-1", - }, - Replicas: intstr.FromString("30%"), - }, - }, - }, - }, - }, - }, - }, - workloadWrappers: []*workload.Info{ - newTestInfo("cluster-a", "test", "test-1"), - // cluster-b/test-1 is not in workloads - }, - rolloutId: "test-rollout-1", - wantRun: true, - wantErr: true, - errContains: "batch[0] target cluster=cluster-b name=test-1 not found in workloads", - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - run, gotInline, err := constructRolloutRunFromInlineStrategy(tt.obj, tt.workloadWrappers, tt.rolloutId) - if gotInline != tt.wantRun { - t.Errorf("constructRolloutRunFromInlineStrategy() gotInline = %v, want %v", gotInline, tt.wantRun) - return - } - if tt.wantErr { - if err == nil { - t.Errorf("constructRolloutRunFromInlineStrategy() expected error, got nil") - return - } - if tt.errContains != "" && !strings.Contains(err.Error(), tt.errContains) { - t.Errorf("constructRolloutRunFromInlineStrategy() error = %v, want containing %v", err, tt.errContains) - } - return - } - if err != nil { - t.Errorf("constructRolloutRunFromInlineStrategy() unexpected error: %v", err) - return - } - - if !tt.wantRun { - if run != nil { - t.Errorf("constructRolloutRunFromInlineStrategy() expected nil run, got %v", run) - } - return - } - - if run == nil { - t.Errorf("constructRolloutRunFromInlineStrategy() expected non-nil run, got nil") - return - } - - // Verify basic fields - if run.Name != tt.rolloutId { - t.Errorf("run.Name = %v, want %v", run.Name, tt.rolloutId) - } - if run.Namespace != tt.obj.Namespace { - t.Errorf("run.Namespace = %v, want %v", run.Namespace, tt.obj.Namespace) - } - - // Verify Canary - if tt.wantCanary { - if run.Spec.Canary == nil { - t.Errorf("run.Spec.Canary = nil, want non-nil") - } else if len(run.Spec.Canary.Targets) == 0 { - t.Errorf("run.Spec.Canary.Targets is empty") - } - } - - // Verify Batch - if tt.wantBatch { - if run.Spec.Batch == nil { - t.Errorf("run.Spec.Batch = nil, want non-nil") - } else if len(run.Spec.Batch.Batches) == 0 { - t.Errorf("run.Spec.Batch.Batches is empty") - } - } - - // Verify owner reference - if len(run.OwnerReferences) != 1 { - t.Errorf("len(run.OwnerReferences) = %v, want 1", len(run.OwnerReferences)) - } - }) - } -} - -func Test_validateAndCopyBatchStrategy(t *testing.T) { - tests := []struct { - name string - batch *rolloutv1alpha1.RolloutRunBatchStrategy - workloadMap map[string]*workload.Info - want *rolloutv1alpha1.RolloutRunBatchStrategy - wantErr bool - errContains string - }{ - { - name: "nil batch", - batch: nil, - workloadMap: map[string]*workload.Info{}, - want: nil, - }, - { - name: "empty batches", - batch: &rolloutv1alpha1.RolloutRunBatchStrategy{}, - workloadMap: map[string]*workload.Info{ - "cluster-a/test-1": newTestInfo("cluster-a", "test", "test-1"), - }, - want: &rolloutv1alpha1.RolloutRunBatchStrategy{ - Batches: []rolloutv1alpha1.RolloutRunStep{}, - }, - }, - { - name: "batch with targets - all exist", - batch: &rolloutv1alpha1.RolloutRunBatchStrategy{ - Batches: []rolloutv1alpha1.RolloutRunStep{ - { - Breakpoint: true, - Targets: []rolloutv1alpha1.RolloutRunStepTarget{ - { - CrossClusterObjectNameReference: rolloutv1alpha1.CrossClusterObjectNameReference{ - Cluster: "cluster-a", - Name: "test-1", - }, - Replicas: intstr.FromString("20%"), - }, - { - CrossClusterObjectNameReference: rolloutv1alpha1.CrossClusterObjectNameReference{ - Cluster: "cluster-b", - Name: "test-1", - }, - Replicas: intstr.FromString("30%"), - ReplicaSlidingWindow: ptr.To(intstr.FromString("10%")), - }, - }, - }, - }, - }, - workloadMap: map[string]*workload.Info{ - "cluster-a/test-1": newTestInfo("cluster-a", "test", "test-1"), - "cluster-b/test-1": newTestInfo("cluster-b", "test", "test-1"), - }, - want: &rolloutv1alpha1.RolloutRunBatchStrategy{ - Batches: []rolloutv1alpha1.RolloutRunStep{ - { - Breakpoint: true, - Targets: []rolloutv1alpha1.RolloutRunStepTarget{ - { - CrossClusterObjectNameReference: rolloutv1alpha1.CrossClusterObjectNameReference{ - Cluster: "cluster-a", - Name: "test-1", - }, - Replicas: intstr.FromString("20%"), - }, - { - CrossClusterObjectNameReference: rolloutv1alpha1.CrossClusterObjectNameReference{ - Cluster: "cluster-b", - Name: "test-1", - }, - Replicas: intstr.FromString("30%"), - ReplicaSlidingWindow: ptr.To(intstr.FromString("10%")), - }, - }, - }, - }, - }, - }, - { - name: "batch with non-existent target - should error", - batch: &rolloutv1alpha1.RolloutRunBatchStrategy{ - Batches: []rolloutv1alpha1.RolloutRunStep{ - { - Targets: []rolloutv1alpha1.RolloutRunStepTarget{ - { - CrossClusterObjectNameReference: rolloutv1alpha1.CrossClusterObjectNameReference{ - Cluster: "cluster-a", - Name: "test-1", - }, - Replicas: intstr.FromString("20%"), - }, - { - CrossClusterObjectNameReference: rolloutv1alpha1.CrossClusterObjectNameReference{ - Cluster: "cluster-b", // Doesn't exist - Name: "test-1", - }, - Replicas: intstr.FromString("30%"), - }, - }, - }, - }, - }, - workloadMap: map[string]*workload.Info{ - "cluster-a/test-1": newTestInfo("cluster-a", "test", "test-1"), - // cluster-b/test-1 is missing - }, - wantErr: true, - errContains: "batch[0] target cluster=cluster-b name=test-1 not found in workloads", - }, - { - name: "batch with toleration preserved", - batch: &rolloutv1alpha1.RolloutRunBatchStrategy{ - Toleration: &rolloutv1alpha1.TolerationStrategy{ - WorkloadFailureThreshold: &intstr.IntOrString{Type: intstr.String, StrVal: "25%"}, - }, - Batches: []rolloutv1alpha1.RolloutRunStep{ - { - Targets: []rolloutv1alpha1.RolloutRunStepTarget{ - { - CrossClusterObjectNameReference: rolloutv1alpha1.CrossClusterObjectNameReference{ - Cluster: "cluster-a", - Name: "test-1", - }, - Replicas: intstr.FromString("50%"), - }, - }, - }, - }, - }, - workloadMap: map[string]*workload.Info{ - "cluster-a/test-1": newTestInfo("cluster-a", "test", "test-1"), - }, - want: &rolloutv1alpha1.RolloutRunBatchStrategy{ - Toleration: &rolloutv1alpha1.TolerationStrategy{ - WorkloadFailureThreshold: &intstr.IntOrString{Type: intstr.String, StrVal: "25%"}, - }, - Batches: []rolloutv1alpha1.RolloutRunStep{ - { - Targets: []rolloutv1alpha1.RolloutRunStepTarget{ - { - CrossClusterObjectNameReference: rolloutv1alpha1.CrossClusterObjectNameReference{ - Cluster: "cluster-a", - Name: "test-1", - }, - Replicas: intstr.FromString("50%"), - }, - }, - }, - }, - }, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - got, err := validateAndCopyBatchStrategy(tt.batch, tt.workloadMap) - if tt.wantErr { - if err == nil { - t.Errorf("validateAndCopyBatchStrategy() expected error, got nil") - return - } - if tt.errContains != "" && !strings.Contains(err.Error(), tt.errContains) { - t.Errorf("validateAndCopyBatchStrategy() error = %v, want containing %v", err, tt.errContains) - } - return - } - if err != nil { - t.Errorf("validateAndCopyBatchStrategy() unexpected error: %v", err) - return - } - if !reflect.DeepEqual(got, tt.want) { - t.Errorf("validateAndCopyBatchStrategy() = %v, want %v", spew.Sdump(got), spew.Sdump(tt.want)) - } - }) - } -} - -func Test_validateAndCopyCanaryStrategy(t *testing.T) { - tests := []struct { - name string - canary *rolloutv1alpha1.RolloutRunCanaryStrategy - workloadMap map[string]*workload.Info - want *rolloutv1alpha1.RolloutRunCanaryStrategy - wantErr bool - errContains string - }{ - { - name: "nil canary", - canary: nil, - workloadMap: map[string]*workload.Info{}, - want: nil, - }, - { - name: "canary with all targets existing", - canary: &rolloutv1alpha1.RolloutRunCanaryStrategy{ - Targets: []rolloutv1alpha1.RolloutRunStepTarget{ - { - CrossClusterObjectNameReference: rolloutv1alpha1.CrossClusterObjectNameReference{ - Cluster: "cluster-a", - Name: "test-1", - }, - Replicas: intstr.FromString("10%"), - }, - }, - }, - workloadMap: map[string]*workload.Info{ - "cluster-a/test-1": newTestInfo("cluster-a", "test", "test-1"), - }, - want: &rolloutv1alpha1.RolloutRunCanaryStrategy{ - Targets: []rolloutv1alpha1.RolloutRunStepTarget{ - { - CrossClusterObjectNameReference: rolloutv1alpha1.CrossClusterObjectNameReference{ - Cluster: "cluster-a", - Name: "test-1", - }, - Replicas: intstr.FromString("10%"), - }, - }, - }, - }, - { - name: "canary with non-existent target - should error", - canary: &rolloutv1alpha1.RolloutRunCanaryStrategy{ - Targets: []rolloutv1alpha1.RolloutRunStepTarget{ - { - CrossClusterObjectNameReference: rolloutv1alpha1.CrossClusterObjectNameReference{ - Cluster: "cluster-a", - Name: "test-1", - }, - Replicas: intstr.FromString("10%"), - }, - { - CrossClusterObjectNameReference: rolloutv1alpha1.CrossClusterObjectNameReference{ - Cluster: "cluster-b", // Doesn't exist - Name: "test-1", - }, - Replicas: intstr.FromString("20%"), - }, - }, - }, - workloadMap: map[string]*workload.Info{ - "cluster-a/test-1": newTestInfo("cluster-a", "test", "test-1"), - // cluster-b/test-1 is missing - }, - wantErr: true, - errContains: "canary target cluster=cluster-b name=test-1 not found in workloads", - }, - { - name: "canary with all non-existent targets - should error", - canary: &rolloutv1alpha1.RolloutRunCanaryStrategy{ - Targets: []rolloutv1alpha1.RolloutRunStepTarget{ - { - CrossClusterObjectNameReference: rolloutv1alpha1.CrossClusterObjectNameReference{ - Cluster: "cluster-b", - Name: "test-1", - }, - Replicas: intstr.FromString("10%"), - }, - }, - }, - workloadMap: map[string]*workload.Info{ - "cluster-a/test-1": newTestInfo("cluster-a", "test", "test-1"), - // cluster-b/test-1 is missing - }, - wantErr: true, - errContains: "canary target cluster=cluster-b name=test-1 not found in workloads", - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - got, err := validateAndCopyCanaryStrategy(tt.canary, tt.workloadMap) - if tt.wantErr { - if err == nil { - t.Errorf("validateAndCopyCanaryStrategy() expected error, got nil") - return - } - if tt.errContains != "" && !strings.Contains(err.Error(), tt.errContains) { - t.Errorf("validateAndCopyCanaryStrategy() error = %v, want containing %v", err, tt.errContains) - } - return - } - if err != nil { - t.Errorf("validateAndCopyCanaryStrategy() unexpected error: %v", err) - return - } - if !reflect.DeepEqual(got, tt.want) { - t.Errorf("validateAndCopyCanaryStrategy() = %v, want %v", spew.Sdump(got), spew.Sdump(tt.want)) - } - }) - } -} - -func Test_buildWorkloadMap(t *testing.T) { - workloads := []*workload.Info{ - newTestInfo("cluster-a", "test", "test-1"), - newTestInfo("cluster-b", "test", "test-2"), - } - - m := buildWorkloadMap(workloads) - - if len(m) != 2 { - t.Errorf("len(m) = %v, want 2", len(m)) - } - - if _, ok := m["cluster-a/test-1"]; !ok { - t.Errorf("m['cluster-a/test-1'] not found") - } - - if _, ok := m["cluster-b/test-2"]; !ok { - t.Errorf("m['cluster-b/test-2'] not found") - } - - if _, ok := m["cluster-a/test-2"]; ok { - t.Errorf("m['cluster-a/test-2'] should not exist") - } -} - -func Test_workloadKey(t *testing.T) { - tests := []struct { - cluster string - name string - want string - }{ - {"cluster-a", "test-1", "cluster-a/test-1"}, - {"cluster-b", "test-2", "cluster-b/test-2"}, - {"cluster-a", "", "cluster-a/"}, - } - - for _, tt := range tests { - t.Run(tt.want, func(t *testing.T) { - got := workloadKey(tt.cluster, tt.name) - if got != tt.want { - t.Errorf("workloadKey() = %v, want %v", got, tt.want) - } - }) - } -} diff --git a/pkg/controllers/rollout/rollout_controller.go b/pkg/controllers/rollout/rollout_controller.go index ad78123..a02c1cd 100644 --- a/pkg/controllers/rollout/rollout_controller.go +++ b/pkg/controllers/rollout/rollout_controller.go @@ -328,10 +328,8 @@ func (r *RolloutReconciler) handleProgressing(ctx context.Context, obj *rolloutv func (r *RolloutReconciler) getDependentResources(ctx context.Context, obj *rolloutv1alpha1.Rollout) (ros *rolloutv1alpha1.RolloutStrategy, ttopos []*rolloutv1alpha1.TrafficTopology, errs []error) { ctx = clusterinfo.WithCluster(ctx, clusterinfo.Fed) - // Check if using inline strategy (BatchStrategy) - // If using inline strategy, we don't need to fetch RolloutStrategy - if obj.Spec.BatchStrategy == nil && len(obj.Spec.StrategyRef) > 0 { - // Only fetch RolloutStrategy if using StrategyRef (not inline strategy) + // Always fetch RolloutStrategy (StrategyRef is required) + if len(obj.Spec.StrategyRef) > 0 { var strategy rolloutv1alpha1.RolloutStrategy err := r.Client.Get( ctx, @@ -439,12 +437,7 @@ func (r *RolloutReconciler) syncRun( } // 4. trigger a new rollout progress - var constructErr error - curRun, constructErr = constructRolloutRun(obj, ros, workloads, rolloutID) - if constructErr != nil { - r.recordCondition(obj, newStatus, rolloutv1alpha1.RolloutConditionTrigger, metav1.ConditionFalse, "FailedConstruct", fmt.Sprintf("failed to construct a new rolloutRun: %v", constructErr)) - return constructErr - } + curRun = constructRolloutRun(obj, ros, workloads, rolloutID) r.recordCondition(obj, newStatus, rolloutv1alpha1.RolloutConditionTrigger, metav1.ConditionTrue, "Create", fmt.Sprintf("construct a new rolloutRun %s", curRun.Name)) // NOTO: we have to set expectation before we create the rolloutRun to avoid @@ -683,17 +676,14 @@ func (r *RolloutReconciler) applyOneTimeStrategy(ctx context.Context, obj *rollo var batch *rolloutv1alpha1.RolloutRunBatchStrategy - // Check if using InlineBatch (for inline batch strategy scenario) - if strategy.InlineBatch != nil { - workloadMap := buildWorkloadMap(workloads) - var validateErr error - batch, validateErr = validateAndCopyBatchStrategy(strategy.InlineBatch, workloadMap) - if validateErr != nil { - r.recordCondition(obj, newStatus, rolloutv1alpha1.RolloutConditionTrigger, metav1.ConditionFalse, "InvalidStrategy", fmt.Sprintf("failed to validate inline batch strategy: %v", validateErr)) - return nil + // Check if using BatchV2 (V2 strategy scenario) + if strategy.BatchV2 != nil { + batch = &rolloutv1alpha1.RolloutRunBatchStrategy{ + Batches: constructRolloutRunBatchesV2(strategy.BatchV2, workloads), + Toleration: strategy.BatchV2.Toleration, } } else { - // Use original Batch field (for StrategyRef scenario) + // Use original Batch field (V1 scenario) batch = &rolloutv1alpha1.RolloutRunBatchStrategy{ Batches: constructRolloutRunBatches(&strategy.Batch, workloads), Toleration: strategy.Batch.Toleration, diff --git a/pkg/controllers/rollout/rollout_controller_test.go b/pkg/controllers/rollout/rollout_controller_test.go index d6dc2d3..87f6c13 100644 --- a/pkg/controllers/rollout/rollout_controller_test.go +++ b/pkg/controllers/rollout/rollout_controller_test.go @@ -270,26 +270,35 @@ func (s *RolloutInitializationTestSuite) Test_CreateRolloutWithStrategyRef() { }, 30*time.Second, 2*time.Second) } -func (s *RolloutInitializationTestSuite) Test_CreateRolloutWithInlineBatchStrategy() { - // create rollout with inline batch strategy - s.rollout.Name = "test-rollout-inline-batch" - s.rollout.Spec.BatchStrategy = &rolloutv1alpha1.RolloutRunBatchStrategy{ - Batches: []rolloutv1alpha1.RolloutRunStep{ - { - Breakpoint: true, - Targets: []rolloutv1alpha1.RolloutRunStepTarget{ - { - CrossClusterObjectNameReference: rolloutv1alpha1.CrossClusterObjectNameReference{ - Cluster: "cluster1", - Name: "test-workload", - }, - Replicas: intstr.FromString("100%"), +func (s *RolloutInitializationTestSuite) Test_CreateRolloutWithV2BatchStrategy() { + // create RolloutStrategy with V2 batch strategy + strategy := &rolloutv1alpha1.RolloutStrategy{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-strategy-v2-batch", + Namespace: s.rollout.Namespace, + }, + BatchV2: &rolloutv1alpha1.BatchStrategyV2{ + Batches: []rolloutv1alpha1.RolloutBatchStep{ + { + Breakpoint: true, + Targets: []rolloutv1alpha1.RolloutTargets{ + {Replicas: intstr.FromString("100%")}, }, }, }, }, } - err := s.fedClient.Create(context.Background(), s.rollout) + err := s.fedClient.Create(context.Background(), strategy) + s.Require().NoError(err) + + defer func() { + _ = s.fedClient.Delete(context.Background(), strategy) + }() + + // create rollout referencing the V2 strategy + s.rollout.Name = "test-rollout-v2-batch" + s.rollout.Spec.StrategyRef = strategy.Name + err = s.fedClient.Create(context.Background(), s.rollout) s.Require().NoError(err) s.Require().Eventually(func() bool { @@ -307,37 +316,40 @@ func (s *RolloutInitializationTestSuite) Test_CreateRolloutWithInlineBatchStrate }, 30*time.Second, 2*time.Second) } -func (s *RolloutInitializationTestSuite) Test_CreateRolloutWithInlineCanaryStrategy() { - // create rollout with inline canary strategy - s.rollout.Name = "test-rollout-inline-canary" - s.rollout.Spec.BatchStrategy = &rolloutv1alpha1.RolloutRunBatchStrategy{ - Batches: []rolloutv1alpha1.RolloutRunStep{ - { - Breakpoint: true, - Targets: []rolloutv1alpha1.RolloutRunStepTarget{ - { - CrossClusterObjectNameReference: rolloutv1alpha1.CrossClusterObjectNameReference{ - Cluster: "cluster1", - Name: "test-workload", - }, - Replicas: intstr.FromString("100%"), - }, - }, +func (s *RolloutInitializationTestSuite) Test_CreateRolloutWithV2CanaryStrategy() { + // create RolloutStrategy with V2 canary + batch strategy + strategy := &rolloutv1alpha1.RolloutStrategy{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-strategy-v2-canary", + Namespace: s.rollout.Namespace, + }, + CanaryV2: &rolloutv1alpha1.CanaryStrategyV2{ + Targets: []rolloutv1alpha1.RolloutTargets{ + {Replicas: intstr.FromString("10%")}, }, }, - } - s.rollout.Spec.CanaryStrategy = &rolloutv1alpha1.RolloutRunCanaryStrategy{ - Targets: []rolloutv1alpha1.RolloutRunStepTarget{ - { - CrossClusterObjectNameReference: rolloutv1alpha1.CrossClusterObjectNameReference{ - Cluster: "cluster1", - Name: "test-workload", + BatchV2: &rolloutv1alpha1.BatchStrategyV2{ + Batches: []rolloutv1alpha1.RolloutBatchStep{ + { + Breakpoint: true, + Targets: []rolloutv1alpha1.RolloutTargets{ + {Replicas: intstr.FromString("100%")}, + }, }, - Replicas: intstr.FromString("10%"), }, }, } - err := s.fedClient.Create(context.Background(), s.rollout) + err := s.fedClient.Create(context.Background(), strategy) + s.Require().NoError(err) + + defer func() { + _ = s.fedClient.Delete(context.Background(), strategy) + }() + + // create rollout referencing the V2 canary+batch strategy + s.rollout.Name = "test-rollout-v2-canary" + s.rollout.Spec.StrategyRef = strategy.Name + err = s.fedClient.Create(context.Background(), s.rollout) s.Require().NoError(err) s.Require().Eventually(func() bool { @@ -506,10 +518,10 @@ func (s *RolloutControllerTestSuite) Test_TriggerRolloutRunWithStrategyRef() { s.Require().Equal(stsName, run.Spec.Batch.Batches[0].Targets[0].Name) } -func (s *RolloutControllerTestSuite) Test_TriggerRolloutRunWithInlineBatchStrategy() { +func (s *RolloutControllerTestSuite) Test_TriggerRolloutRunWithV2BatchStrategy() { ctx := context.Background() namespace := "default" - stsName := "test-sts-inline-batch" + stsName := "test-sts-v2-batch" // 1. Create StatefulSet as workload sts := newTestStatefulSet(stsName, namespace) @@ -521,45 +533,49 @@ func (s *RolloutControllerTestSuite) Test_TriggerRolloutRunWithInlineBatchStrate _ = s.cluster1Client.Delete(ctx, sts) }() - // 2. Create Rollout with InlineBatchStrategy and trigger annotation - rollout := newTestRollout("test-rollout-inline-batch-run", namespace) - rollout.Spec.WorkloadRef.Match = rolloutv1alpha1.ResourceMatch{ - Names: []rolloutv1alpha1.CrossClusterObjectNameReference{ - { - Cluster: "cluster1", - Name: stsName, - }, + // 2. Create RolloutStrategy with BatchV2 + strategy := &rolloutv1alpha1.RolloutStrategy{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-strategy-v2-batch-run", + Namespace: namespace, }, - } - rollout.Spec.BatchStrategy = &rolloutv1alpha1.RolloutRunBatchStrategy{ - Batches: []rolloutv1alpha1.RolloutRunStep{ - { - Targets: []rolloutv1alpha1.RolloutRunStepTarget{ - { - CrossClusterObjectNameReference: rolloutv1alpha1.CrossClusterObjectNameReference{ - Cluster: "cluster1", - Name: stsName, - }, - Replicas: intstr.FromString("30%"), + BatchV2: &rolloutv1alpha1.BatchStrategyV2{ + Batches: []rolloutv1alpha1.RolloutBatchStep{ + { + Targets: []rolloutv1alpha1.RolloutTargets{ + {Replicas: intstr.FromString("30%")}, }, }, - }, - { - Breakpoint: true, - Targets: []rolloutv1alpha1.RolloutRunStepTarget{ - { - CrossClusterObjectNameReference: rolloutv1alpha1.CrossClusterObjectNameReference{ - Cluster: "cluster1", - Name: stsName, - }, - Replicas: intstr.FromString("100%"), + { + Breakpoint: true, + Targets: []rolloutv1alpha1.RolloutTargets{ + {Replicas: intstr.FromString("100%")}, }, }, }, }, } + err = s.fedClient.Create(ctx, strategy) + s.Require().NoError(err) + + // Cleanup + defer func() { + _ = s.fedClient.Delete(ctx, strategy) + }() + + // 3. Create Rollout with StrategyRef (V2) and trigger annotation + rollout := newTestRollout("test-rollout-v2-batch-run", namespace) + rollout.Spec.StrategyRef = strategy.Name + rollout.Spec.WorkloadRef.Match = rolloutv1alpha1.ResourceMatch{ + Names: []rolloutv1alpha1.CrossClusterObjectNameReference{ + { + Cluster: "cluster1", + Name: stsName, + }, + }, + } rollout.Annotations = map[string]string{ - rolloutapi.AnnoRolloutTrigger: "trigger-inline-batch-run", + rolloutapi.AnnoRolloutTrigger: "trigger-v2-batch-run", } err = s.fedClient.Create(ctx, rollout) s.Require().NoError(err) @@ -591,7 +607,7 @@ func (s *RolloutControllerTestSuite) Test_TriggerRolloutRunWithInlineBatchStrate for i := range runList.Items { r := &runList.Items[i] owner := metav1.GetControllerOf(r) - if owner != nil && owner.Name == rollout.Name && r.Name == "trigger-inline-batch-run" { + if owner != nil && owner.Name == rollout.Name && r.Name == "trigger-v2-batch-run" { run = r return true } @@ -619,10 +635,10 @@ func (s *RolloutControllerTestSuite) Test_TriggerRolloutRunWithInlineBatchStrate s.Require().Equal("100%", run.Spec.Batch.Batches[1].Targets[0].Replicas.String()) } -func (s *RolloutControllerTestSuite) Test_ApplyOneTimeStrategyWithInlineBatch() { +func (s *RolloutControllerTestSuite) Test_ApplyOneTimeStrategyWithV2Batch() { ctx := context.Background() namespace := "default" - stsName := "test-sts-onetime-inline" + stsName := "test-sts-onetime-v2" // 1. Create StatefulSet as workload sts := newTestStatefulSet(stsName, namespace) @@ -634,8 +650,34 @@ func (s *RolloutControllerTestSuite) Test_ApplyOneTimeStrategyWithInlineBatch() _ = s.cluster1Client.Delete(ctx, sts) }() - // 2. Create Rollout with InlineBatchStrategy and trigger annotation - rollout := newTestRollout("test-rollout-onetime-inline", namespace) + // 2. Create RolloutStrategy with BatchV2 + strategy := &rolloutv1alpha1.RolloutStrategy{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-strategy-onetime-v2", + Namespace: namespace, + }, + BatchV2: &rolloutv1alpha1.BatchStrategyV2{ + Batches: []rolloutv1alpha1.RolloutBatchStep{ + { + Breakpoint: true, + Targets: []rolloutv1alpha1.RolloutTargets{ + {Replicas: intstr.FromString("50%")}, + }, + }, + }, + }, + } + err = s.fedClient.Create(ctx, strategy) + s.Require().NoError(err) + + // Cleanup + defer func() { + _ = s.fedClient.Delete(ctx, strategy) + }() + + // 3. Create Rollout with StrategyRef (V2) and trigger annotation + rollout := newTestRollout("test-rollout-onetime-v2", namespace) + rollout.Spec.StrategyRef = strategy.Name rollout.Spec.WorkloadRef.Match = rolloutv1alpha1.ResourceMatch{ Names: []rolloutv1alpha1.CrossClusterObjectNameReference{ { @@ -644,24 +686,8 @@ func (s *RolloutControllerTestSuite) Test_ApplyOneTimeStrategyWithInlineBatch() }, }, } - rollout.Spec.BatchStrategy = &rolloutv1alpha1.RolloutRunBatchStrategy{ - Batches: []rolloutv1alpha1.RolloutRunStep{ - { - Breakpoint: true, - Targets: []rolloutv1alpha1.RolloutRunStepTarget{ - { - CrossClusterObjectNameReference: rolloutv1alpha1.CrossClusterObjectNameReference{ - Cluster: "cluster1", - Name: stsName, - }, - Replicas: intstr.FromString("50%"), - }, - }, - }, - }, - } rollout.Annotations = map[string]string{ - rolloutapi.AnnoRolloutTrigger: "trigger-onetime-inline", + rolloutapi.AnnoRolloutTrigger: "trigger-onetime-v2", } err = s.fedClient.Create(ctx, rollout) s.Require().NoError(err) @@ -693,7 +719,7 @@ func (s *RolloutControllerTestSuite) Test_ApplyOneTimeStrategyWithInlineBatch() for i := range runList.Items { r := &runList.Items[i] owner := metav1.GetControllerOf(r) - if owner != nil && owner.Name == rollout.Name && r.Name == "trigger-onetime-inline" { + if owner != nil && owner.Name == rollout.Name && r.Name == "trigger-onetime-v2" { run = r return true } @@ -706,41 +732,23 @@ func (s *RolloutControllerTestSuite) Test_ApplyOneTimeStrategyWithInlineBatch() s.Require().Len(run.Spec.Batch.Batches, 1, "Should have 1 batch initially") s.Require().Equal("50%", run.Spec.Batch.Batches[0].Targets[0].Replicas.String()) - // 6. Apply one-time strategy via annotation using InlineBatch + // 6. Apply one-time strategy via annotation using BatchV2 oneTimeStrategy := ontimestrategy.OneTimeStrategy{ - InlineBatch: &rolloutv1alpha1.RolloutRunBatchStrategy{ - Batches: []rolloutv1alpha1.RolloutRunStep{ + BatchV2: &rolloutv1alpha1.BatchStrategyV2{ + Batches: []rolloutv1alpha1.RolloutBatchStep{ { - Targets: []rolloutv1alpha1.RolloutRunStepTarget{ - { - CrossClusterObjectNameReference: rolloutv1alpha1.CrossClusterObjectNameReference{ - Cluster: "cluster1", - Name: stsName, - }, - Replicas: intstr.FromString("20%"), - }, + Targets: []rolloutv1alpha1.RolloutTargets{ + {Replicas: intstr.FromString("20%")}, }, }, { - Targets: []rolloutv1alpha1.RolloutRunStepTarget{ - { - CrossClusterObjectNameReference: rolloutv1alpha1.CrossClusterObjectNameReference{ - Cluster: "cluster1", - Name: stsName, - }, - Replicas: intstr.FromString("40%"), - }, + Targets: []rolloutv1alpha1.RolloutTargets{ + {Replicas: intstr.FromString("40%")}, }, }, { - Targets: []rolloutv1alpha1.RolloutRunStepTarget{ - { - CrossClusterObjectNameReference: rolloutv1alpha1.CrossClusterObjectNameReference{ - Cluster: "cluster1", - Name: stsName, - }, - Replicas: intstr.FromString("60%"), - }, + Targets: []rolloutv1alpha1.RolloutTargets{ + {Replicas: intstr.FromString("60%")}, }, }, }, @@ -947,6 +955,7 @@ func newTestRollout(name, namespace string) *rolloutv1alpha1.Rollout { Namespace: namespace, }, Spec: rolloutv1alpha1.RolloutSpec{ + StrategyRef: "default-strategy", WorkloadRef: rolloutv1alpha1.WorkloadRef{ APIVersion: "apps/v1", Kind: "StatefulSet", diff --git a/pkg/controllers/rollout/utils.go b/pkg/controllers/rollout/utils.go index ec25e6b..5433d54 100644 --- a/pkg/controllers/rollout/utils.go +++ b/pkg/controllers/rollout/utils.go @@ -68,21 +68,9 @@ func filterWorkloadsByMatch(workloads []*workload.Info, match *rolloutv1alpha1.R return result } -func constructRolloutRun(obj *rolloutv1alpha1.Rollout, strategy *rolloutv1alpha1.RolloutStrategy, workloadWrappers []*workload.Info, rolloutId string) (*rolloutv1alpha1.RolloutRun, error) { - var run *rolloutv1alpha1.RolloutRun - var hasInline bool - // Try inline strategy first - run, hasInline, err := constructRolloutRunFromInlineStrategy(obj, workloadWrappers, rolloutId) - if hasInline { - if err != nil { - return nil, err - } - return run, nil - } - - // Fall back to strategy reference +func constructRolloutRun(obj *rolloutv1alpha1.Rollout, strategy *rolloutv1alpha1.RolloutStrategy, workloadWrappers []*workload.Info, rolloutId string) *rolloutv1alpha1.RolloutRun { owner := metav1.NewControllerRef(obj, rolloutv1alpha1.SchemeGroupVersion.WithKind("Rollout")) - run = &rolloutv1alpha1.RolloutRun{ + run := &rolloutv1alpha1.RolloutRun{ ObjectMeta: metav1.ObjectMeta{ Namespace: obj.Namespace, Name: rolloutId, @@ -97,15 +85,31 @@ func constructRolloutRun(obj *rolloutv1alpha1.Rollout, strategy *rolloutv1alpha1 Kind: obj.Spec.WorkloadRef.Kind, }, TrafficTopologyRefs: obj.Spec.TrafficTopologyRefs, - Canary: constructRolloutRunCanary(strategy.Canary, workloadWrappers), - Batch: &rolloutv1alpha1.RolloutRunBatchStrategy{ - Toleration: strategy.Batch.Toleration, - Batches: constructRolloutRunBatches(strategy.Batch, workloadWrappers), - }, - Webhooks: strategy.Webhooks, + Webhooks: strategy.Webhooks, }, } + // Determine V1 vs V2 path based on BatchV2 presence + if strategy.BatchV2 != nil { + // V2 path: BatchV2 + optional CanaryV2 + if strategy.CanaryV2 != nil { + run.Spec.Canary = constructRolloutRunCanaryV2(strategy.CanaryV2, workloadWrappers) + } + run.Spec.Batch = &rolloutv1alpha1.RolloutRunBatchStrategy{ + Toleration: strategy.BatchV2.Toleration, + Batches: constructRolloutRunBatchesV2(strategy.BatchV2, workloadWrappers), + } + } else if strategy.Batch != nil { + // V1 path: Batch + optional Canary + if strategy.Canary != nil { + run.Spec.Canary = constructRolloutRunCanary(strategy.Canary, workloadWrappers) + } + run.Spec.Batch = &rolloutv1alpha1.RolloutRunBatchStrategy{ + Toleration: strategy.Batch.Toleration, + Batches: constructRolloutRunBatches(strategy.Batch, workloadWrappers), + } + } + if features.DefaultFeatureGate.Enabled(features.OneTimeStrategy) { onetime := ontimestrategy.ConvertFrom(strategy) data := onetime.JSONData() @@ -118,7 +122,7 @@ func constructRolloutRun(obj *rolloutv1alpha1.Rollout, strategy *rolloutv1alpha1 run.Labels[rolloutapi.LabelRolloutClass] = class } } - return run, nil + return run } func constructRolloutRunCanary(strategy *rolloutv1alpha1.CanaryStrategy, workloadWrappers []*workload.Info) *rolloutv1alpha1.RolloutRunCanaryStrategy { @@ -183,6 +187,64 @@ func constructRolloutRunBatches(strategy *rolloutv1alpha1.BatchStrategy, workloa return result } +// constructRolloutRunCanaryV2 constructs RolloutRunCanaryStrategy from CanaryStrategyV2 +func constructRolloutRunCanaryV2(strategy *rolloutv1alpha1.CanaryStrategyV2, workloadWrappers []*workload.Info) *rolloutv1alpha1.RolloutRunCanaryStrategy { + if strategy == nil { + return nil + } + targets := resolveRolloutTargets(strategy.Targets, workloadWrappers) + + return &rolloutv1alpha1.RolloutRunCanaryStrategy{ + Targets: targets, + Traffic: strategy.Traffic, + Properties: strategy.Properties, + TemplateMetadataPatch: strategy.TemplateMetadataPatch, + } +} + +// constructRolloutRunBatchesV2 constructs RolloutRunStep list from BatchStrategyV2 +func constructRolloutRunBatchesV2(strategy *rolloutv1alpha1.BatchStrategyV2, workloadWrappers []*workload.Info) []rolloutv1alpha1.RolloutRunStep { + if strategy == nil { + return nil + } + + if len(strategy.Batches) == 0 { + panic("no valid batches found in batchV2 strategy") + } + + result := make([]rolloutv1alpha1.RolloutRunStep, 0, len(strategy.Batches)) + for _, b := range strategy.Batches { + step := rolloutv1alpha1.RolloutRunStep{ + Targets: resolveRolloutTargets(b.Targets, workloadWrappers), + Breakpoint: b.Breakpoint, + Properties: b.Properties, + Traffic: b.Traffic, + } + result = append(result, step) + } + return result +} + +// resolveRolloutTargets resolves RolloutTargets into RolloutRunStepTarget by matching workloads +func resolveRolloutTargets(targets []rolloutv1alpha1.RolloutTargets, workloadWrappers []*workload.Info) []rolloutv1alpha1.RolloutRunStepTarget { + result := make([]rolloutv1alpha1.RolloutRunStepTarget, 0) + for _, t := range targets { + filteredWorkloads := filterWorkloadsByMatch(workloadWrappers, t.Match) + for _, info := range filteredWorkloads { + target := rolloutv1alpha1.RolloutRunStepTarget{ + CrossClusterObjectNameReference: rolloutv1alpha1.CrossClusterObjectNameReference{ + Cluster: info.ClusterName, + Name: info.Name, + }, + Replicas: t.Replicas, + ReplicaSlidingWindow: t.ReplicaSlidingWindow, + } + result = append(result, target) + } + } + return result +} + func GetWatchableWorkloads(r registry.WorkloadRegistry, logger logr.Logger, c client.Client, cfg *rest.Config) []workload.Accessor { discoveryClient := NewGVKDiscovery(c, cfg) diff --git a/pkg/controllers/rollout/utils_test.go b/pkg/controllers/rollout/utils_test.go index 54ff0a9..0a970ae 100644 --- a/pkg/controllers/rollout/utils_test.go +++ b/pkg/controllers/rollout/utils_test.go @@ -179,140 +179,66 @@ func Test_constructRolloutRunBatches(t *testing.T) { } } -func Test_constructRolloutRun(t *testing.T) { +func Test_constructRolloutRun_V2Path(t *testing.T) { tests := []struct { - name string - obj *rolloutv1alpha1.Rollout - strategy *rolloutv1alpha1.RolloutStrategy - workloadWrappers []*workload.Info - rolloutId string - wantInline bool // true if should use inline strategy + name string + obj *rolloutv1alpha1.Rollout + strategy *rolloutv1alpha1.RolloutStrategy + workloads []*workload.Info + rolloutId string + wantV2 bool // true if V2 strategy path expected + wantCanary bool + wantBatch bool }{ { - name: "inline batch strategy takes precedence over StrategyRef", + name: "V2 batch strategy", obj: &rolloutv1alpha1.Rollout{ ObjectMeta: metav1.ObjectMeta{ Namespace: "test", Name: "test-rollout", }, Spec: rolloutv1alpha1.RolloutSpec{ + StrategyRef: "test-strategy", WorkloadRef: rolloutv1alpha1.WorkloadRef{ APIVersion: "apps/v1", Kind: "Deployment", }, - BatchStrategy: &rolloutv1alpha1.RolloutRunBatchStrategy{ - Batches: []rolloutv1alpha1.RolloutRunStep{ - { - Targets: []rolloutv1alpha1.RolloutRunStepTarget{ - { - CrossClusterObjectNameReference: rolloutv1alpha1.CrossClusterObjectNameReference{ - Cluster: "cluster-a", - Name: "test-1", - }, - Replicas: intstr.FromString("20%"), - }, - }, - }, - }, - }, }, }, strategy: &rolloutv1alpha1.RolloutStrategy{ - Batch: &rolloutv1alpha1.BatchStrategy{ - Batches: []rolloutv1alpha1.RolloutStep{ + BatchV2: &rolloutv1alpha1.BatchStrategyV2{ + Batches: []rolloutv1alpha1.RolloutBatchStep{ { - Replicas: intstr.FromString("50%"), - Match: &rolloutv1alpha1.ResourceMatch{ - Names: []rolloutv1alpha1.CrossClusterObjectNameReference{ - {Cluster: "cluster-a", Name: "test-1"}, - }, + Targets: []rolloutv1alpha1.RolloutTargets{ + {Replicas: intstr.FromString("30%")}, }, }, - }, - }, - }, - workloadWrappers: []*workload.Info{ - newTestInfo("cluster-a", "test", "test-1"), - }, - rolloutId: "test-rollout-1", - wantInline: true, - }, - { - name: "inline canary strategy takes precedence over StrategyRef", - obj: &rolloutv1alpha1.Rollout{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: "test", - Name: "test-rollout", - }, - Spec: rolloutv1alpha1.RolloutSpec{ - WorkloadRef: rolloutv1alpha1.WorkloadRef{ - APIVersion: "apps/v1", - Kind: "Deployment", - }, - CanaryStrategy: &rolloutv1alpha1.RolloutRunCanaryStrategy{ - Targets: []rolloutv1alpha1.RolloutRunStepTarget{ - { - CrossClusterObjectNameReference: rolloutv1alpha1.CrossClusterObjectNameReference{ - Cluster: "cluster-a", - Name: "test-1", - }, - Replicas: intstr.FromString("10%"), - }, - }, - }, - BatchStrategy: &rolloutv1alpha1.RolloutRunBatchStrategy{ - Batches: []rolloutv1alpha1.RolloutRunStep{ - { - Targets: []rolloutv1alpha1.RolloutRunStepTarget{ - { - CrossClusterObjectNameReference: rolloutv1alpha1.CrossClusterObjectNameReference{ - Cluster: "cluster-a", - Name: "test-1", - }, - Replicas: intstr.FromString("100%"), - }, - }, - }, - }, - }, - }, - }, - strategy: &rolloutv1alpha1.RolloutStrategy{ - Canary: &rolloutv1alpha1.CanaryStrategy{ - Replicas: intstr.FromString("20%"), - Match: &rolloutv1alpha1.ResourceMatch{ - Names: []rolloutv1alpha1.CrossClusterObjectNameReference{ - {Cluster: "cluster-a", Name: "test-1"}, - }, - }, - }, - Batch: &rolloutv1alpha1.BatchStrategy{ - Batches: []rolloutv1alpha1.RolloutStep{ { - Replicas: intstr.FromString("100%"), - Match: &rolloutv1alpha1.ResourceMatch{ - Names: []rolloutv1alpha1.CrossClusterObjectNameReference{ - {Cluster: "cluster-a", Name: "test-1"}, - }, + Breakpoint: true, + Targets: []rolloutv1alpha1.RolloutTargets{ + {Replicas: intstr.FromString("100%")}, }, }, }, }, }, - workloadWrappers: []*workload.Info{ + workloads: []*workload.Info{ newTestInfo("cluster-a", "test", "test-1"), }, rolloutId: "test-rollout-1", - wantInline: true, + wantV2: true, + wantCanary: false, + wantBatch: true, }, { - name: "fallback to StrategyRef when no inline strategy", + name: "V2 batch + canary strategy", obj: &rolloutv1alpha1.Rollout{ ObjectMeta: metav1.ObjectMeta{ Namespace: "test", Name: "test-rollout", }, Spec: rolloutv1alpha1.RolloutSpec{ + StrategyRef: "test-strategy", WorkloadRef: rolloutv1alpha1.WorkloadRef{ APIVersion: "apps/v1", Kind: "Deployment", @@ -320,63 +246,42 @@ func Test_constructRolloutRun(t *testing.T) { }, }, strategy: &rolloutv1alpha1.RolloutStrategy{ - Batch: &rolloutv1alpha1.BatchStrategy{ - Batches: []rolloutv1alpha1.RolloutStep{ + CanaryV2: &rolloutv1alpha1.CanaryStrategyV2{ + Targets: []rolloutv1alpha1.RolloutTargets{ + {Replicas: intstr.FromString("5%")}, + }, + }, + BatchV2: &rolloutv1alpha1.BatchStrategyV2{ + Batches: []rolloutv1alpha1.RolloutBatchStep{ { - Replicas: intstr.FromString("50%"), - Match: &rolloutv1alpha1.ResourceMatch{ - Names: []rolloutv1alpha1.CrossClusterObjectNameReference{ - {Cluster: "cluster-a", Name: "test-1"}, - }, + Targets: []rolloutv1alpha1.RolloutTargets{ + {Replicas: intstr.FromString("100%")}, }, }, }, }, }, - workloadWrappers: []*workload.Info{ + workloads: []*workload.Info{ newTestInfo("cluster-a", "test", "test-1"), }, rolloutId: "test-rollout-1", - wantInline: false, + wantV2: true, + wantCanary: true, + wantBatch: true, }, { - name: "inline batch with canary together", + name: "V1 batch strategy", obj: &rolloutv1alpha1.Rollout{ ObjectMeta: metav1.ObjectMeta{ Namespace: "test", Name: "test-rollout", }, Spec: rolloutv1alpha1.RolloutSpec{ + StrategyRef: "test-strategy", WorkloadRef: rolloutv1alpha1.WorkloadRef{ APIVersion: "apps/v1", Kind: "Deployment", }, - BatchStrategy: &rolloutv1alpha1.RolloutRunBatchStrategy{ - Batches: []rolloutv1alpha1.RolloutRunStep{ - { - Targets: []rolloutv1alpha1.RolloutRunStepTarget{ - { - CrossClusterObjectNameReference: rolloutv1alpha1.CrossClusterObjectNameReference{ - Cluster: "cluster-a", - Name: "test-1", - }, - Replicas: intstr.FromString("25%"), - }, - }, - }, - }, - }, - CanaryStrategy: &rolloutv1alpha1.RolloutRunCanaryStrategy{ - Targets: []rolloutv1alpha1.RolloutRunStepTarget{ - { - CrossClusterObjectNameReference: rolloutv1alpha1.CrossClusterObjectNameReference{ - Cluster: "cluster-a", - Name: "test-1", - }, - Replicas: intstr.FromString("5%"), - }, - }, - }, }, }, strategy: &rolloutv1alpha1.RolloutStrategy{ @@ -384,30 +289,23 @@ func Test_constructRolloutRun(t *testing.T) { Batches: []rolloutv1alpha1.RolloutStep{ { Replicas: intstr.FromString("50%"), - Match: &rolloutv1alpha1.ResourceMatch{ - Names: []rolloutv1alpha1.CrossClusterObjectNameReference{ - {Cluster: "cluster-a", Name: "test-1"}, - }, - }, }, }, }, }, - workloadWrappers: []*workload.Info{ + workloads: []*workload.Info{ newTestInfo("cluster-a", "test", "test-1"), }, rolloutId: "test-rollout-1", - wantInline: true, + wantV2: false, + wantCanary: false, + wantBatch: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - run, err := constructRolloutRun(tt.obj, tt.strategy, tt.workloadWrappers, tt.rolloutId) - if err != nil { - t.Errorf("constructRolloutRun() unexpected error: %v", err) - return - } + run := constructRolloutRun(tt.obj, tt.strategy, tt.workloads, tt.rolloutId) if run == nil { t.Errorf("constructRolloutRun() returned nil") @@ -422,44 +320,6 @@ func Test_constructRolloutRun(t *testing.T) { t.Errorf("run.Namespace = %v, want %v", run.Namespace, tt.obj.Namespace) } - if tt.wantInline { - // Verify that inline strategy was used (BatchSpec should be set based on inline config) - if tt.obj.Spec.BatchStrategy != nil { - if run.Spec.Batch == nil { - t.Errorf("run.Spec.Batch is nil, expected inline batch strategy to be used") - return - } - // Verify batch content matches inline config - if len(run.Spec.Batch.Batches) != len(tt.obj.Spec.BatchStrategy.Batches) { - t.Errorf("run.Spec.Batch.Batches length = %d, want %d", - len(run.Spec.Batch.Batches), len(tt.obj.Spec.BatchStrategy.Batches)) - } - } - - if tt.obj.Spec.CanaryStrategy != nil { - if run.Spec.Canary == nil { - t.Errorf("run.Spec.Canary is nil, expected inline canary strategy to be used") - return - } - // Verify canary content matches inline config - if len(run.Spec.Canary.Targets) != len(tt.obj.Spec.CanaryStrategy.Targets) { - t.Errorf("run.Spec.Canary.Targets length = %d, want %d", - len(run.Spec.Canary.Targets), len(tt.obj.Spec.CanaryStrategy.Targets)) - } - } - } else { - // Verify that StrategyRef was used - if run.Spec.Batch == nil { - t.Errorf("run.Spec.Batch is nil, expected StrategyRef batch to be used") - return - } - // Verify batch content matches strategy config - if len(run.Spec.Batch.Batches) != len(tt.strategy.Batch.Batches) { - t.Errorf("run.Spec.Batch.Batches length = %d, want %d", - len(run.Spec.Batch.Batches), len(tt.strategy.Batch.Batches)) - } - } - // Verify owner reference exists if len(run.OwnerReferences) != 1 { t.Errorf("len(run.OwnerReferences) = %d, want 1", len(run.OwnerReferences)) @@ -470,6 +330,229 @@ func Test_constructRolloutRun(t *testing.T) { owner.Kind, owner.Name, tt.obj.Name) } } + + // Verify canary + if tt.wantCanary { + if run.Spec.Canary == nil { + t.Errorf("run.Spec.Canary is nil, expected canary strategy") + } + } + + // Verify batch + if tt.wantBatch { + if run.Spec.Batch == nil { + t.Errorf("run.Spec.Batch is nil, expected batch strategy") + } + } + }) + } +} + +func Test_constructRolloutRunCanaryV2(t *testing.T) { + workloads := []*workload.Info{ + newTestInfo("cluster-a", "test", "test-1"), + newTestInfo("cluster-b", "test", "test-2"), + } + + tests := []struct { + name string + strategy *rolloutv1alpha1.CanaryStrategyV2 + wantNil bool + wantLen int + }{ + { + name: "nil strategy", + strategy: nil, + wantNil: true, + }, + { + name: "single target without match (match all)", + strategy: &rolloutv1alpha1.CanaryStrategyV2{ + Targets: []rolloutv1alpha1.RolloutTargets{ + {Replicas: intstr.FromString("10%")}, + }, + }, + wantNil: false, + wantLen: 2, // both workloads matched + }, + { + name: "target with match by name", + strategy: &rolloutv1alpha1.CanaryStrategyV2{ + Targets: []rolloutv1alpha1.RolloutTargets{ + { + Replicas: intstr.FromString("10%"), + Match: &rolloutv1alpha1.ResourceMatch{ + Names: []rolloutv1alpha1.CrossClusterObjectNameReference{ + {Cluster: "cluster-a", Name: "test-1"}, + }, + }, + }, + }, + }, + wantNil: false, + wantLen: 1, // only cluster-a matched + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := constructRolloutRunCanaryV2(tt.strategy, workloads) + if tt.wantNil { + if got != nil { + t.Errorf("expected nil, got %v", got) + } + return + } + if len(got.Targets) != tt.wantLen { + t.Errorf("got %d targets, want %d", len(got.Targets), tt.wantLen) + } + }) + } +} + +func Test_constructRolloutRunBatchesV2(t *testing.T) { + workloads := []*workload.Info{ + newTestInfo("cluster-a", "test", "test-1"), + newTestInfo("cluster-b", "test", "test-2"), + } + + tests := []struct { + name string + strategy *rolloutv1alpha1.BatchStrategyV2 + wantNil bool + wantLen int + }{ + { + name: "nil strategy", + strategy: nil, + wantNil: true, + }, + { + name: "two batches with targets", + strategy: &rolloutv1alpha1.BatchStrategyV2{ + Batches: []rolloutv1alpha1.RolloutBatchStep{ + { + Targets: []rolloutv1alpha1.RolloutTargets{ + {Replicas: intstr.FromString("30%")}, + }, + }, + { + Breakpoint: true, + Targets: []rolloutv1alpha1.RolloutTargets{ + {Replicas: intstr.FromString("100%")}, + }, + }, + }, + }, + wantNil: false, + wantLen: 2, + }, + { + name: "batch with match filtering", + strategy: &rolloutv1alpha1.BatchStrategyV2{ + Batches: []rolloutv1alpha1.RolloutBatchStep{ + { + Targets: []rolloutv1alpha1.RolloutTargets{ + { + Replicas: intstr.FromString("50%"), + Match: &rolloutv1alpha1.ResourceMatch{ + Names: []rolloutv1alpha1.CrossClusterObjectNameReference{ + {Cluster: "cluster-a", Name: "test-1"}, + }, + }, + }, + }, + }, + }, + }, + wantNil: false, + wantLen: 1, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := constructRolloutRunBatchesV2(tt.strategy, workloads) + if tt.wantNil { + if got != nil { + t.Errorf("expected nil, got %v", got) + } + return + } + if len(got) != tt.wantLen { + t.Errorf("got %d batches, want %d", len(got), tt.wantLen) + } + }) + } +} + +func Test_resolveRolloutTargets(t *testing.T) { + workloads := []*workload.Info{ + newTestInfo("cluster-a", "test", "test-1"), + newTestInfo("cluster-b", "test", "test-2"), + } + + tests := []struct { + name string + targets []rolloutv1alpha1.RolloutTargets + wantLen int + }{ + { + name: "empty targets", + targets: nil, + wantLen: 0, + }, + { + name: "match all workloads", + targets: []rolloutv1alpha1.RolloutTargets{ + {Replicas: intstr.FromString("50%")}, + }, + wantLen: 2, + }, + { + name: "match specific cluster", + targets: []rolloutv1alpha1.RolloutTargets{ + { + Replicas: intstr.FromString("50%"), + Match: &rolloutv1alpha1.ResourceMatch{ + Names: []rolloutv1alpha1.CrossClusterObjectNameReference{ + {Cluster: "cluster-a", Name: "test-1"}, + }, + }, + }, + }, + wantLen: 1, + }, + { + name: "multiple targets filter to different workloads", + targets: []rolloutv1alpha1.RolloutTargets{ + { + Replicas: intstr.FromString("30%"), + Match: &rolloutv1alpha1.ResourceMatch{ + Names: []rolloutv1alpha1.CrossClusterObjectNameReference{ + {Cluster: "cluster-a", Name: "test-1"}, + }, + }, + }, + { + Replicas: intstr.FromString("70%"), + Match: &rolloutv1alpha1.ResourceMatch{ + Names: []rolloutv1alpha1.CrossClusterObjectNameReference{ + {Cluster: "cluster-b", Name: "test-2"}, + }, + }, + }, + }, + wantLen: 2, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := resolveRolloutTargets(tt.targets, workloads) + if len(got) != tt.wantLen { + t.Errorf("got %d targets, want %d", len(got), tt.wantLen) + } }) } } diff --git a/pkg/features/ontimestrategy/ontimestrategy.go b/pkg/features/ontimestrategy/ontimestrategy.go index f607662..7beff66 100644 --- a/pkg/features/ontimestrategy/ontimestrategy.go +++ b/pkg/features/ontimestrategy/ontimestrategy.go @@ -28,16 +28,15 @@ const ( ) type OneTimeStrategy struct { - // Batch is the original field for StrategyRef scenario. - // Used when referencing a RolloutStrategy CRD with match/replicas. - // Mutually exclusive with InlineBatch. + // Batch is the V1 field for StrategyRef scenario. + // Used when referencing a RolloutStrategy CRD with V1 match/replicas. + // Mutually exclusive with BatchV2. Batch rolloutv1alpha1.BatchStrategy `json:"batch,omitempty"` - // InlineBatch is for inline batch strategy scenario. - // Used when RolloutSpec uses BatchStrategy inline configuration. + // BatchV2 is for V2 batch strategy scenario. + // Used when RolloutStrategy uses BatchV2 configuration. // Mutually exclusive with Batch. - // Directly reuses RolloutRunBatchStrategy type. - InlineBatch *rolloutv1alpha1.RolloutRunBatchStrategy `json:"inlineBatch,omitempty"` + BatchV2 *rolloutv1alpha1.BatchStrategyV2 `json:"batchV2,omitempty"` } func (s *OneTimeStrategy) JSONData() []byte { @@ -45,22 +44,30 @@ func (s *OneTimeStrategy) JSONData() []byte { return data } -// ConvertFrom creates a OneTimeStrategy from RolloutStrategy (for StrategyRef scenario) +// ConvertFrom creates a OneTimeStrategy from RolloutStrategy func ConvertFrom(in *rolloutv1alpha1.RolloutStrategy) *OneTimeStrategy { - if in == nil || in.Batch == nil { + if in == nil { return &OneTimeStrategy{} } - return &OneTimeStrategy{ - Batch: *in.Batch, + if in.BatchV2 != nil { + return &OneTimeStrategy{ + BatchV2: in.BatchV2, + } + } + if in.Batch != nil { + return &OneTimeStrategy{ + Batch: *in.Batch, + } } + return &OneTimeStrategy{} } -// ConvertFromInline creates a OneTimeStrategy for inline batch strategy scenario -func ConvertFromInline(batchStrategy *rolloutv1alpha1.RolloutRunBatchStrategy) *OneTimeStrategy { +// ConvertFromV2 creates a OneTimeStrategy from BatchStrategyV2 +func ConvertFromV2(batchStrategy *rolloutv1alpha1.BatchStrategyV2) *OneTimeStrategy { if batchStrategy == nil { return &OneTimeStrategy{} } return &OneTimeStrategy{ - InlineBatch: batchStrategy, + BatchV2: batchStrategy, } } From 7726a64dc761bae3dd3c191c0998ecbbc287fa45 Mon Sep 17 00:00:00 2001 From: youngLiuHY Date: Wed, 13 May 2026 10:41:11 +0800 Subject: [PATCH 09/10] fix: adjust the structure and rename some fields --- .../v1alpha1/validation/rolloutstrategy.go | 10 +++--- .../validation/rolloutstrategy_test.go | 10 +++--- go.mod | 2 +- go.sum | 4 +-- pkg/controllers/rollout/rollout_controller.go | 4 +-- .../rollout/rollout_controller_test.go | 28 +++++++-------- pkg/controllers/rollout/utils.go | 8 ++--- pkg/controllers/rollout/utils_test.go | 34 +++++++++---------- 8 files changed, 50 insertions(+), 50 deletions(-) diff --git a/apis/rollout/v1alpha1/validation/rolloutstrategy.go b/apis/rollout/v1alpha1/validation/rolloutstrategy.go index 882c93c..e2187b4 100644 --- a/apis/rollout/v1alpha1/validation/rolloutstrategy.go +++ b/apis/rollout/v1alpha1/validation/rolloutstrategy.go @@ -161,20 +161,20 @@ func ValidateBatchStrategyV2(strategy *rolloutv1alpha1.BatchStrategyV2, fldPath for i := range strategy.Batches { batch := strategy.Batches[i] - allErrs = append(allErrs, ValidateRolloutBatchStep(&batch, fldPath.Child("batches").Index(i))...) + allErrs = append(allErrs, ValidateRolloutBatchStrategyStep(&batch, fldPath.Child("batches").Index(i))...) } return allErrs } -func ValidateRolloutBatchStep(step *rolloutv1alpha1.RolloutBatchStep, fldPath *field.Path) field.ErrorList { +func ValidateRolloutBatchStrategyStep(step *rolloutv1alpha1.RolloutBatchStrategyStep, fldPath *field.Path) field.ErrorList { allErrs := field.ErrorList{} if len(step.Targets) == 0 { allErrs = append(allErrs, field.Required(fldPath.Child("targets"), "must specify at least one target")) } else { for i := range step.Targets { - allErrs = append(allErrs, ValidateRolloutTargets(&step.Targets[i], fldPath.Child("targets").Index(i))...) + allErrs = append(allErrs, ValidateRolloutStrategyTargets(&step.Targets[i], fldPath.Child("targets").Index(i))...) } } @@ -183,7 +183,7 @@ func ValidateRolloutBatchStep(step *rolloutv1alpha1.RolloutBatchStep, fldPath *f return allErrs } -func ValidateRolloutTargets(targets *rolloutv1alpha1.RolloutTargets, fldPath *field.Path) field.ErrorList { +func ValidateRolloutStrategyTargets(targets *rolloutv1alpha1.RolloutStrategyTargets, fldPath *field.Path) field.ErrorList { allErrs := field.ErrorList{} allErrs = append(allErrs, appsvalidation.ValidatePositiveIntOrPercent(targets.Replicas, fldPath.Child("replicas"))...) @@ -203,7 +203,7 @@ func ValidateCanaryStrategyV2(strategy *rolloutv1alpha1.CanaryStrategyV2, fldPat allErrs = append(allErrs, field.Required(fldPath.Child("targets"), "must specify at least one target")) } else { for i := range strategy.Targets { - allErrs = append(allErrs, ValidateRolloutTargets(&strategy.Targets[i], fldPath.Child("targets").Index(i))...) + allErrs = append(allErrs, ValidateRolloutStrategyTargets(&strategy.Targets[i], fldPath.Child("targets").Index(i))...) } } diff --git a/apis/rollout/v1alpha1/validation/rolloutstrategy_test.go b/apis/rollout/v1alpha1/validation/rolloutstrategy_test.go index 75fe7ed..d24e802 100644 --- a/apis/rollout/v1alpha1/validation/rolloutstrategy_test.go +++ b/apis/rollout/v1alpha1/validation/rolloutstrategy_test.go @@ -178,16 +178,16 @@ func TestValidateRolloutStrategy_V2(t *testing.T) { Namespace: "default", }, CanaryV2: &rolloutv1alpha1.CanaryStrategyV2{ - Targets: []rolloutv1alpha1.RolloutTargets{ + Targets: []rolloutv1alpha1.RolloutStrategyTargets{ { Replicas: intstr.FromString("10%"), }, }, }, BatchV2: &rolloutv1alpha1.BatchStrategyV2{ - Batches: []rolloutv1alpha1.RolloutBatchStep{ + Batches: []rolloutv1alpha1.RolloutBatchStrategyStep{ { - Targets: []rolloutv1alpha1.RolloutTargets{ + Targets: []rolloutv1alpha1.RolloutStrategyTargets{ { Replicas: intstr.FromString("30%"), }, @@ -198,7 +198,7 @@ func TestValidateRolloutStrategy_V2(t *testing.T) { }, { Breakpoint: true, - Targets: []rolloutv1alpha1.RolloutTargets{ + Targets: []rolloutv1alpha1.RolloutStrategyTargets{ { Replicas: intstr.FromString("100%"), }, @@ -275,7 +275,7 @@ func TestValidateRolloutStrategy_V2(t *testing.T) { obj: func() *rolloutv1alpha1.RolloutStrategy { obj := validV2Strategy.DeepCopy() obj.CanaryV2 = nil - obj.BatchV2.Batches = []rolloutv1alpha1.RolloutBatchStep{ + obj.BatchV2.Batches = []rolloutv1alpha1.RolloutBatchStrategyStep{ {Targets: nil}, } return obj diff --git a/go.mod b/go.mod index bab9de1..9d5fce4 100644 --- a/go.mod +++ b/go.mod @@ -23,7 +23,7 @@ require ( k8s.io/klog/v2 v2.130.1 k8s.io/kubernetes v1.22.2 k8s.io/utils v0.0.0-20241210054802-24370beab758 - kusionstack.io/kube-api v0.7.5-0.20260506033526-9dc0f832c099 + kusionstack.io/kube-api v0.7.5-0.20260512114711-9570d38337c2 kusionstack.io/kube-utils v0.2.1-0.20251125083928-1134a582b341 kusionstack.io/resourceconsist v0.0.4 sigs.k8s.io/controller-runtime v0.21.0 diff --git a/go.sum b/go.sum index df7a930..d2f1479 100644 --- a/go.sum +++ b/go.sum @@ -1021,8 +1021,8 @@ k8s.io/sample-apiserver v0.22.2/go.mod h1:h+/DIV5EmuNq4vfPr5TSXy9mIBVXXlPAKQMPbj k8s.io/system-validators v1.5.0/go.mod h1:bPldcLgkIUK22ALflnsXk8pvkTEndYdNuaHH6gRrl0Q= k8s.io/utils v0.0.0-20240102154912-e7106e64919e h1:eQ/4ljkx21sObifjzXwlPKpdGLrCfRziVtos3ofG/sQ= k8s.io/utils v0.0.0-20240102154912-e7106e64919e/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= -kusionstack.io/kube-api v0.7.5-0.20260506033526-9dc0f832c099 h1:FjR10d3zDRX4F+3Q1LCS84l638G6ejSu18Nz0zUt/zQ= -kusionstack.io/kube-api v0.7.5-0.20260506033526-9dc0f832c099/go.mod h1:e1jtrQH2LK5fD2nTyfIXG6nYrYbU8VXShRxTRwVPaLk= +kusionstack.io/kube-api v0.7.5-0.20260512114711-9570d38337c2 h1:jrUVO6a6/fuwdfF8NnehVXGbiYV57AfIJvqnsYRB3sI= +kusionstack.io/kube-api v0.7.5-0.20260512114711-9570d38337c2/go.mod h1:e1jtrQH2LK5fD2nTyfIXG6nYrYbU8VXShRxTRwVPaLk= kusionstack.io/kube-utils v0.2.1-0.20251125083928-1134a582b341 h1:dnMtHJvIpU3338WpqGiNN2qXWZFiXaoiuzR9jwhvWpg= kusionstack.io/kube-utils v0.2.1-0.20251125083928-1134a582b341/go.mod h1:Lz5SBYWg9+jw+kP0CAyf/b62D5DeUPf6+jE1d0WC4cI= kusionstack.io/resourceconsist v0.0.4 h1:wRqLJuNh8O4TT6p0uOklFpHUKiRdRxcAH71Sw/q9LhE= diff --git a/pkg/controllers/rollout/rollout_controller.go b/pkg/controllers/rollout/rollout_controller.go index a02c1cd..fd599a6 100644 --- a/pkg/controllers/rollout/rollout_controller.go +++ b/pkg/controllers/rollout/rollout_controller.go @@ -677,10 +677,10 @@ func (r *RolloutReconciler) applyOneTimeStrategy(ctx context.Context, obj *rollo var batch *rolloutv1alpha1.RolloutRunBatchStrategy // Check if using BatchV2 (V2 strategy scenario) + // Note: BatchStrategyV2 does not support Toleration, only V1 BatchStrategy has it if strategy.BatchV2 != nil { batch = &rolloutv1alpha1.RolloutRunBatchStrategy{ - Batches: constructRolloutRunBatchesV2(strategy.BatchV2, workloads), - Toleration: strategy.BatchV2.Toleration, + Batches: constructRolloutRunBatchesV2(strategy.BatchV2, workloads), } } else { // Use original Batch field (V1 scenario) diff --git a/pkg/controllers/rollout/rollout_controller_test.go b/pkg/controllers/rollout/rollout_controller_test.go index 87f6c13..17177d3 100644 --- a/pkg/controllers/rollout/rollout_controller_test.go +++ b/pkg/controllers/rollout/rollout_controller_test.go @@ -278,10 +278,10 @@ func (s *RolloutInitializationTestSuite) Test_CreateRolloutWithV2BatchStrategy() Namespace: s.rollout.Namespace, }, BatchV2: &rolloutv1alpha1.BatchStrategyV2{ - Batches: []rolloutv1alpha1.RolloutBatchStep{ + Batches: []rolloutv1alpha1.RolloutBatchStrategyStep{ { Breakpoint: true, - Targets: []rolloutv1alpha1.RolloutTargets{ + Targets: []rolloutv1alpha1.RolloutStrategyTargets{ {Replicas: intstr.FromString("100%")}, }, }, @@ -324,15 +324,15 @@ func (s *RolloutInitializationTestSuite) Test_CreateRolloutWithV2CanaryStrategy( Namespace: s.rollout.Namespace, }, CanaryV2: &rolloutv1alpha1.CanaryStrategyV2{ - Targets: []rolloutv1alpha1.RolloutTargets{ + Targets: []rolloutv1alpha1.RolloutStrategyTargets{ {Replicas: intstr.FromString("10%")}, }, }, BatchV2: &rolloutv1alpha1.BatchStrategyV2{ - Batches: []rolloutv1alpha1.RolloutBatchStep{ + Batches: []rolloutv1alpha1.RolloutBatchStrategyStep{ { Breakpoint: true, - Targets: []rolloutv1alpha1.RolloutTargets{ + Targets: []rolloutv1alpha1.RolloutStrategyTargets{ {Replicas: intstr.FromString("100%")}, }, }, @@ -540,15 +540,15 @@ func (s *RolloutControllerTestSuite) Test_TriggerRolloutRunWithV2BatchStrategy() Namespace: namespace, }, BatchV2: &rolloutv1alpha1.BatchStrategyV2{ - Batches: []rolloutv1alpha1.RolloutBatchStep{ + Batches: []rolloutv1alpha1.RolloutBatchStrategyStep{ { - Targets: []rolloutv1alpha1.RolloutTargets{ + Targets: []rolloutv1alpha1.RolloutStrategyTargets{ {Replicas: intstr.FromString("30%")}, }, }, { Breakpoint: true, - Targets: []rolloutv1alpha1.RolloutTargets{ + Targets: []rolloutv1alpha1.RolloutStrategyTargets{ {Replicas: intstr.FromString("100%")}, }, }, @@ -657,10 +657,10 @@ func (s *RolloutControllerTestSuite) Test_ApplyOneTimeStrategyWithV2Batch() { Namespace: namespace, }, BatchV2: &rolloutv1alpha1.BatchStrategyV2{ - Batches: []rolloutv1alpha1.RolloutBatchStep{ + Batches: []rolloutv1alpha1.RolloutBatchStrategyStep{ { Breakpoint: true, - Targets: []rolloutv1alpha1.RolloutTargets{ + Targets: []rolloutv1alpha1.RolloutStrategyTargets{ {Replicas: intstr.FromString("50%")}, }, }, @@ -735,19 +735,19 @@ func (s *RolloutControllerTestSuite) Test_ApplyOneTimeStrategyWithV2Batch() { // 6. Apply one-time strategy via annotation using BatchV2 oneTimeStrategy := ontimestrategy.OneTimeStrategy{ BatchV2: &rolloutv1alpha1.BatchStrategyV2{ - Batches: []rolloutv1alpha1.RolloutBatchStep{ + Batches: []rolloutv1alpha1.RolloutBatchStrategyStep{ { - Targets: []rolloutv1alpha1.RolloutTargets{ + Targets: []rolloutv1alpha1.RolloutStrategyTargets{ {Replicas: intstr.FromString("20%")}, }, }, { - Targets: []rolloutv1alpha1.RolloutTargets{ + Targets: []rolloutv1alpha1.RolloutStrategyTargets{ {Replicas: intstr.FromString("40%")}, }, }, { - Targets: []rolloutv1alpha1.RolloutTargets{ + Targets: []rolloutv1alpha1.RolloutStrategyTargets{ {Replicas: intstr.FromString("60%")}, }, }, diff --git a/pkg/controllers/rollout/utils.go b/pkg/controllers/rollout/utils.go index 5433d54..eb85881 100644 --- a/pkg/controllers/rollout/utils.go +++ b/pkg/controllers/rollout/utils.go @@ -92,12 +92,12 @@ func constructRolloutRun(obj *rolloutv1alpha1.Rollout, strategy *rolloutv1alpha1 // Determine V1 vs V2 path based on BatchV2 presence if strategy.BatchV2 != nil { // V2 path: BatchV2 + optional CanaryV2 + // Note: BatchStrategyV2 does not support Toleration, only V1 BatchStrategy has it if strategy.CanaryV2 != nil { run.Spec.Canary = constructRolloutRunCanaryV2(strategy.CanaryV2, workloadWrappers) } run.Spec.Batch = &rolloutv1alpha1.RolloutRunBatchStrategy{ - Toleration: strategy.BatchV2.Toleration, - Batches: constructRolloutRunBatchesV2(strategy.BatchV2, workloadWrappers), + Batches: constructRolloutRunBatchesV2(strategy.BatchV2, workloadWrappers), } } else if strategy.Batch != nil { // V1 path: Batch + optional Canary @@ -225,8 +225,8 @@ func constructRolloutRunBatchesV2(strategy *rolloutv1alpha1.BatchStrategyV2, wor return result } -// resolveRolloutTargets resolves RolloutTargets into RolloutRunStepTarget by matching workloads -func resolveRolloutTargets(targets []rolloutv1alpha1.RolloutTargets, workloadWrappers []*workload.Info) []rolloutv1alpha1.RolloutRunStepTarget { +// resolveRolloutTargets resolves RolloutStrategyTargets into RolloutRunStepTarget by matching workloads +func resolveRolloutTargets(targets []rolloutv1alpha1.RolloutStrategyTargets, workloadWrappers []*workload.Info) []rolloutv1alpha1.RolloutRunStepTarget { result := make([]rolloutv1alpha1.RolloutRunStepTarget, 0) for _, t := range targets { filteredWorkloads := filterWorkloadsByMatch(workloadWrappers, t.Match) diff --git a/pkg/controllers/rollout/utils_test.go b/pkg/controllers/rollout/utils_test.go index 0a970ae..2760a30 100644 --- a/pkg/controllers/rollout/utils_test.go +++ b/pkg/controllers/rollout/utils_test.go @@ -207,15 +207,15 @@ func Test_constructRolloutRun_V2Path(t *testing.T) { }, strategy: &rolloutv1alpha1.RolloutStrategy{ BatchV2: &rolloutv1alpha1.BatchStrategyV2{ - Batches: []rolloutv1alpha1.RolloutBatchStep{ + Batches: []rolloutv1alpha1.RolloutBatchStrategyStep{ { - Targets: []rolloutv1alpha1.RolloutTargets{ + Targets: []rolloutv1alpha1.RolloutStrategyTargets{ {Replicas: intstr.FromString("30%")}, }, }, { Breakpoint: true, - Targets: []rolloutv1alpha1.RolloutTargets{ + Targets: []rolloutv1alpha1.RolloutStrategyTargets{ {Replicas: intstr.FromString("100%")}, }, }, @@ -247,14 +247,14 @@ func Test_constructRolloutRun_V2Path(t *testing.T) { }, strategy: &rolloutv1alpha1.RolloutStrategy{ CanaryV2: &rolloutv1alpha1.CanaryStrategyV2{ - Targets: []rolloutv1alpha1.RolloutTargets{ + Targets: []rolloutv1alpha1.RolloutStrategyTargets{ {Replicas: intstr.FromString("5%")}, }, }, BatchV2: &rolloutv1alpha1.BatchStrategyV2{ - Batches: []rolloutv1alpha1.RolloutBatchStep{ + Batches: []rolloutv1alpha1.RolloutBatchStrategyStep{ { - Targets: []rolloutv1alpha1.RolloutTargets{ + Targets: []rolloutv1alpha1.RolloutStrategyTargets{ {Replicas: intstr.FromString("100%")}, }, }, @@ -368,7 +368,7 @@ func Test_constructRolloutRunCanaryV2(t *testing.T) { { name: "single target without match (match all)", strategy: &rolloutv1alpha1.CanaryStrategyV2{ - Targets: []rolloutv1alpha1.RolloutTargets{ + Targets: []rolloutv1alpha1.RolloutStrategyTargets{ {Replicas: intstr.FromString("10%")}, }, }, @@ -378,7 +378,7 @@ func Test_constructRolloutRunCanaryV2(t *testing.T) { { name: "target with match by name", strategy: &rolloutv1alpha1.CanaryStrategyV2{ - Targets: []rolloutv1alpha1.RolloutTargets{ + Targets: []rolloutv1alpha1.RolloutStrategyTargets{ { Replicas: intstr.FromString("10%"), Match: &rolloutv1alpha1.ResourceMatch{ @@ -430,15 +430,15 @@ func Test_constructRolloutRunBatchesV2(t *testing.T) { { name: "two batches with targets", strategy: &rolloutv1alpha1.BatchStrategyV2{ - Batches: []rolloutv1alpha1.RolloutBatchStep{ + Batches: []rolloutv1alpha1.RolloutBatchStrategyStep{ { - Targets: []rolloutv1alpha1.RolloutTargets{ + Targets: []rolloutv1alpha1.RolloutStrategyTargets{ {Replicas: intstr.FromString("30%")}, }, }, { Breakpoint: true, - Targets: []rolloutv1alpha1.RolloutTargets{ + Targets: []rolloutv1alpha1.RolloutStrategyTargets{ {Replicas: intstr.FromString("100%")}, }, }, @@ -450,9 +450,9 @@ func Test_constructRolloutRunBatchesV2(t *testing.T) { { name: "batch with match filtering", strategy: &rolloutv1alpha1.BatchStrategyV2{ - Batches: []rolloutv1alpha1.RolloutBatchStep{ + Batches: []rolloutv1alpha1.RolloutBatchStrategyStep{ { - Targets: []rolloutv1alpha1.RolloutTargets{ + Targets: []rolloutv1alpha1.RolloutStrategyTargets{ { Replicas: intstr.FromString("50%"), Match: &rolloutv1alpha1.ResourceMatch{ @@ -494,7 +494,7 @@ func Test_resolveRolloutTargets(t *testing.T) { tests := []struct { name string - targets []rolloutv1alpha1.RolloutTargets + targets []rolloutv1alpha1.RolloutStrategyTargets wantLen int }{ { @@ -504,14 +504,14 @@ func Test_resolveRolloutTargets(t *testing.T) { }, { name: "match all workloads", - targets: []rolloutv1alpha1.RolloutTargets{ + targets: []rolloutv1alpha1.RolloutStrategyTargets{ {Replicas: intstr.FromString("50%")}, }, wantLen: 2, }, { name: "match specific cluster", - targets: []rolloutv1alpha1.RolloutTargets{ + targets: []rolloutv1alpha1.RolloutStrategyTargets{ { Replicas: intstr.FromString("50%"), Match: &rolloutv1alpha1.ResourceMatch{ @@ -525,7 +525,7 @@ func Test_resolveRolloutTargets(t *testing.T) { }, { name: "multiple targets filter to different workloads", - targets: []rolloutv1alpha1.RolloutTargets{ + targets: []rolloutv1alpha1.RolloutStrategyTargets{ { Replicas: intstr.FromString("30%"), Match: &rolloutv1alpha1.ResourceMatch{ From ac924677fa1c670c71176de85e7ad1ac69ad4974 Mon Sep 17 00:00:00 2001 From: youngLiuHY Date: Wed, 13 May 2026 10:43:41 +0800 Subject: [PATCH 10/10] fix: update crds --- .../rollout.kusionstack.io_rollouts.yaml | 46 +++++++++++++------ ...lout.kusionstack.io_rolloutstrategies.yaml | 26 ----------- 2 files changed, 31 insertions(+), 41 deletions(-) diff --git a/config/crd/bases/rollout.kusionstack.io_rollouts.yaml b/config/crd/bases/rollout.kusionstack.io_rollouts.yaml index a1d77e3..d749091 100644 --- a/config/crd/bases/rollout.kusionstack.io_rollouts.yaml +++ b/config/crd/bases/rollout.kusionstack.io_rollouts.yaml @@ -96,12 +96,14 @@ spec: description: Kind is the type of resource being referenced type: string match: - description: Match indicates how to match workloads. only one workload should be matches in one cluster + description: Match indicates how to match workloads. only one + workload should be matches in one cluster properties: names: description: Names is a list of workload name items: - description: CrossClusterObjectNameReference contains cluster and name reference to a k8s object + description: CrossClusterObjectNameReference contains cluster + and name reference to a k8s object properties: cluster: description: Cluster indicates the name of cluster @@ -114,17 +116,20 @@ spec: type: object type: array selector: - description: Selector is a label query over a set of resources, in this case resource + description: Selector is a label query over a set of resources, + in this case resource properties: matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + description: matchExpressions is a list of label selector + requirements. The requirements are ANDed. items: description: |- A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. properties: key: - description: key is the label key that the selector applies to. + description: key is the label key that the selector + applies to. type: string operator: description: |- @@ -172,7 +177,8 @@ spec: See: https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#typical-status-properties properties: lastTransitionTime: - description: Last time the condition transitioned from one status to another. + description: Last time the condition transitioned from one status + to another. format: date-time type: string lastUpdateTime: @@ -180,7 +186,8 @@ spec: format: date-time type: string message: - description: A human-readable message indicating details about the transition. + description: A human-readable message indicating details about + the transition. type: string reason: description: The reason for the condition's last transition. @@ -217,7 +224,8 @@ spec: items: properties: availableReplicas: - description: AvailableReplicas is the number of service available pods targeted by workload. + description: AvailableReplicas is the number of service available + pods targeted by workload. format: int32 type: integer cluster: @@ -231,30 +239,38 @@ spec: description: Name is the workload name type: string observedGeneration: - description: ObservedGeneration is the most recent generation observed for this workload. + description: ObservedGeneration is the most recent generation + observed for this workload. format: int64 type: integer replicas: - description: Replicas is the desired number of pods targeted by workload + description: Replicas is the desired number of pods targeted + by workload format: int32 type: integer stableRevision: - description: StableRevision is the old stable revision used to generate pods. + description: StableRevision is the old stable revision used + to generate pods. type: string updatedAvailableReplicas: - description: UpdatedAvailableReplicas is the number of service available pods targeted by workload that have the updated template spec. + description: UpdatedAvailableReplicas is the number of service + available pods targeted by workload that have the updated + template spec. format: int32 type: integer updatedReadyReplicas: - description: UpdatedReadyReplicas is the number of ready pods targeted by workload that have the updated template spec. + description: UpdatedReadyReplicas is the number of ready pods + targeted by workload that have the updated template spec. format: int32 type: integer updatedReplicas: - description: UpdatedReplicas is the number of pods targeted by workload that have the updated template spec. + description: UpdatedReplicas is the number of pods targeted + by workload that have the updated template spec. format: int32 type: integer updatedRevision: - description: UpdatedRevision is the updated template revision used to generate pods. + description: UpdatedRevision is the updated template revision + used to generate pods. type: string type: object type: array diff --git a/config/crd/bases/rollout.kusionstack.io_rolloutstrategies.yaml b/config/crd/bases/rollout.kusionstack.io_rolloutstrategies.yaml index bd9851e..a60da61 100644 --- a/config/crd/bases/rollout.kusionstack.io_rolloutstrategies.yaml +++ b/config/crd/bases/rollout.kusionstack.io_rolloutstrategies.yaml @@ -4564,32 +4564,6 @@ spec: - targets type: object type: array - toleration: - description: Toleration is the toleration policy of the canary strategy - properties: - initialDelaySeconds: - description: Number of seconds after the toleration check has started before the task are initiated. - format: int32 - type: integer - taskFailureThreshold: - anyOf: - - type: integer - - type: string - description: |- - FailureThreshold indicates how many failed pods can be tolerated before marking the rollout task as success - If not set, the default value is 0, which means no failed pods can be tolerated - This is a task level threshold. - x-kubernetes-int-or-string: true - workloadTotalFailureThreshold: - anyOf: - - type: integer - - type: string - description: |- - WorkloadFailureThreshold indicates how many failed pods can be tolerated in all upgraded pods of one workload. - The default value is 0, which means no failed pods can be tolerated. - This is a workload level threshold. - x-kubernetes-int-or-string: true - type: object type: object canary: description: Canary defines the canary strategy for upgrade and operation