为了限制用户在创建CRD时只能设置嵌入资源的名称/命名空间/gvk,可以在metadata.namespace字段上添加CEL验证。以下是一个示例:
package main
import (
"fmt"
"k8s.io/apiextensions-apiserver/pkg/apiserver/schema"
)
func main() {
// 定义一个自定义的CEL验证规则,要求namespace字段必须是字符串类型且不能为空
customValidationRule := schema.NewFieldPath("metadata", "namespace").String().NotEmpty()
// 使用WithTypeAndObjectMeta确保kind、apiVersion和metadata.name以及metadata.generateName属性被指定,如果需要则进行浅拷贝
withTypeAndObjectMeta := schema.WithTypeAndObjectMeta(customValidationRule)
// 创建一个新的结构体,包含我们刚刚定义的验证规则
newStruct := &schema.Structural{
Generic: schema.Generic{Type: "object"},
Extensions: schema.Extensions{},
ValueValidation: schema.ValueValidation{},
}
newStruct.Properties["metadata"] = schema.Structural{
Generic: schema.Generic{Type: "object"},
Properties: map[string]schema.Structural{
"name": withTypeAndObjectMeta,
"generateName": withTypeAndObjectMeta,
},
}
// 输出新的结构体,可以看到已经包含了我们的自定义验证规则
fmt.Println(newStruct)
}
这段代码定义了一个自定义的CEL验证规则,要求metadata.namespace字段必须是字符串类型且不能为空。然后,我们使用这个规则创建了一个新的结构体,并将其添加到metadata字段中。最后,输出新的结构体,可以看到已经包含了我们的自定义验证规则。
7条答案
按热度按时间iqxoj9l91#
/sig api-machinery
eqfvzcg82#
/triage已接受
添加一些背景信息:我们目前仅限制对apiVersion、kind、metadata.name和metadata.generateName的访问,正如当前文档所述:
背后的考虑主要是我们希望元数据在类型之间保持一致。
作为此问题的替代解决方案是 ValidatingAdmissionPolicy ,它将允许您访问namespace。
cmssoen23#
是的,我可以使用ValidatingAdmissionPolicy,但说实话,如果这是解决方案,那么在CRD级别上限制这个有什么意义呢?如果我可以使用VAP验证任何我想验证的内容?
如果可能的话,我希望这些验证策略的来源靠近我的代码库中的Go结构(如果我有访问命名空间的话),而不是“远”地放在VAP中的helm图表里,这样可能会意外地与CRD中的字段失去同步。
rjzwgtxy4#
建议:允许在CRD嵌入式资源中对metadata.namespace进行CEL验证
概述:
目前,CRD嵌入式资源缺乏对metadata.namespace字段的CEL验证。这阻碍了用户在不同CR示例中为嵌入式资源寻求稳定的身份标识。
提议的解决方案:
将CEL验证扩展到嵌入式资源中的metadata.namespace。这与其他元数据字段的做法保持一致。
好处:
稳定的身份标识:确保嵌入式资源具有稳定的身份标识,对于多租户或跨命名空间资源管理等场景至关重要。
操作效率:使用户能够在依赖稳定身份配置的应用中维持可预测性和可靠性。
可行性和考虑因素:
实施:讨论可行性,同时考虑对工作流程、向后兼容性和实施工作的影响。
挑战:承认挑战和潜在的权衡,例如增加的复杂性或依赖关系。
解决关注点:
替代方案:讨论替代方案,包括ValidatingAdmissionPolicy (VAP),并突出其优缺点。
社区反馈:鼓励社区就该提案提供反馈和多样化的观点。
dkqlctbz5#
这确实感觉有点奇怪,因为
x-kubernetes-embedded-resource
并不排除 CRD 作者在同一个子模式上放置进一步的约束。我尝试编写一个强制元数据.namespace 在嵌入式资源上的不可变性的模式,结果是:这似乎对必须命名空间化的嵌入式资源有效。但它有两个原因显得很别扭:
has(self.namespace) == has(oldSelf.namespace)
这样的表情式。如果嵌入式资源必须始终有命名空间,那么可以在不使用 CEL 扩展的情况下使命名空间成为必需字段。controller-gen
生成这样的模式。uinbv5nw6#
这似乎对必须命名空间的嵌入式资源有效。但它有两个尴尬的地方:
如果我理解正确,(1)、(2)和(3)都导致与根资源相比,验证质量较差。我很想看到这一点得到改进。
我的笔记:
(1) - 这似乎是个bug。我们在根资源上看不到,因为我们有内置的不可变性验证。这也是OpenAPI值验证的问题吗?(例如正则表达式规则或长度规则)?
(2) - 能够指定是否需要命名空间显然是有用的。我们在根资源验证中可以免费获得这一点。
(3) - 正确的行为应该是需要name或generateName。我认为?
(4) - 我对此不那么惊讶。如果有人不想让嵌入式资源完全被替换,他们需要在上面有一个过渡规则,以匹配他们的预期。.
(5) - ack
d7v8vwbk7#
@aerfio 的解决方法是将所有CEL规则声明在嵌入式资源之上:
请注意,所有元数据字段必须显式声明。我不确定你是否在使用kubebuilder时能得到这个。
此外,确切的验证规则将取决于:
我的示例假设嵌入式资源是必需的、命名空间范围的,并使用name(而不是generateName)。