-
Notifications
You must be signed in to change notification settings - Fork 5
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support Naming Policy #17
Changes from 6 commits
1748cc3
e2e94da
18d211a
81f24f4
634f66f
76f9830
80c5742
83b738b
1ccc93c
8e3f2da
ccc9986
d050eaa
5c91ab4
01d189c
2de266e
b45c179
6d0ed08
71870a2
9421085
4de6fd4
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -23,3 +23,5 @@ watches: | |
kind: RoleBinding | ||
- version: v1 | ||
kind: Secret | ||
|
||
namingPolicies: [] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please add comments just like in the other fields. |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -49,6 +49,15 @@ controller: | |
kind: RoleBinding | ||
- version: v1 | ||
kind: Secret | ||
|
||
# controller.config.namingPolicies -- List of nameing policy for SubNamespaces. | ||
# root and match are both regular expressions. | ||
# When a SubNamespace is created in a tree starting from a root namespace and the root namespace's name matches root expression, the SubNamespace name is validated with match expression. | ||
# namingPolicies: | ||
# - root: foo | ||
# match: foo_.* | ||
# - root: bar | ||
# match: bar_.* | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why don't we uncomment these lines? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. uncommented. |
||
<snip> | ||
``` | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,8 +5,10 @@ import ( | |
"encoding/json" | ||
"fmt" | ||
"net/http" | ||
"regexp" | ||
|
||
accuratev1 "github.com/cybozu-go/accurate/api/v1" | ||
"github.com/cybozu-go/accurate/pkg/config" | ||
"github.com/cybozu-go/accurate/pkg/constants" | ||
admissionv1 "k8s.io/api/admission/v1" | ||
corev1 "k8s.io/api/core/v1" | ||
|
@@ -43,11 +45,17 @@ func (m *subNamespaceMutator) Handle(ctx context.Context, req admission.Request) | |
return admission.PatchResponseFromRaw(req.Object.Raw, data) | ||
} | ||
|
||
type NamingPolicyRegexp struct { | ||
Root *regexp.Regexp | ||
Match *regexp.Regexp | ||
} | ||
|
||
//+kubebuilder:webhook:path=/validate-accurate-cybozu-com-v1-subnamespace,mutating=false,failurePolicy=fail,sideEffects=None,groups=accurate.cybozu.com,resources=subnamespaces,verbs=create;update,versions=v1,name=vsubnamespace.kb.io,admissionReviewVersions={v1,v1beta1} | ||
|
||
type subNamespaceValidator struct { | ||
client.Client | ||
dec *admission.Decoder | ||
dec *admission.Decoder | ||
namingPolicies []NamingPolicyRegexp | ||
} | ||
|
||
var _ admission.Handler = &subNamespaceValidator{} | ||
|
@@ -67,25 +75,69 @@ func (v *subNamespaceValidator) Handle(ctx context.Context, req admission.Reques | |
return admission.Errored(http.StatusInternalServerError, err) | ||
} | ||
|
||
if ns.Labels[constants.LabelType] == constants.NSTypeRoot || ns.Labels[constants.LabelParent] != "" { | ||
return admission.Allowed("") | ||
if ns.Labels[constants.LabelType] != constants.NSTypeRoot && ns.Labels[constants.LabelParent] == "" { | ||
return admission.Denied(fmt.Sprintf("namespace %s is neither a root nor a sub namespace", ns.Name)) | ||
} | ||
|
||
ok, err := v.notMatchingNamingPolicy(ctx, sn) | ||
if err != nil { | ||
return admission.Errored(http.StatusInternalServerError, err) | ||
} | ||
if !ok { | ||
return admission.Denied(fmt.Sprintf("namespace %s is not match naming policies", ns.Name)) | ||
} | ||
|
||
return admission.Allowed("") | ||
} | ||
|
||
return admission.Denied(fmt.Sprintf("namespace %s is neither a root nor a sub namespace", ns.Name)) | ||
func (v *subNamespaceValidator) notMatchingNamingPolicy(ctx context.Context, sn *accuratev1.SubNamespace) (bool, error) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The regular expression should be pre-compiled when loaded from the configuration file, |
||
for _, policy := range v.namingPolicies { | ||
if policy.Root.MatchString(sn.Namespace) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think |
||
if !policy.Match.MatchString(sn.Name) { | ||
return false, nil | ||
} | ||
} | ||
} | ||
return true, nil | ||
} | ||
|
||
// SetupSubNamespaceWebhook registers the webhooks for SubNamespace | ||
func SetupSubNamespaceWebhook(mgr manager.Manager, dec *admission.Decoder) { | ||
func SetupSubNamespaceWebhook(mgr manager.Manager, dec *admission.Decoder, namingPolicies []config.NamingPolicy) error { | ||
serv := mgr.GetWebhookServer() | ||
|
||
m := &subNamespaceMutator{ | ||
dec: dec, | ||
} | ||
serv.Register("/mutate-accurate-cybozu-com-v1-subnamespace", &webhook.Admission{Handler: m}) | ||
|
||
namingPolicyRegexps, err := compileNamingPolicies(namingPolicies) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. compile and validate policies in pkg/config.Config.Validate method. |
||
if err != nil { | ||
return err | ||
} | ||
|
||
v := &subNamespaceValidator{ | ||
Client: mgr.GetClient(), | ||
dec: dec, | ||
Client: mgr.GetClient(), | ||
dec: dec, | ||
namingPolicies: namingPolicyRegexps, | ||
} | ||
serv.Register("/validate-accurate-cybozu-com-v1-subnamespace", &webhook.Admission{Handler: v}) | ||
return nil | ||
} | ||
|
||
func compileNamingPolicies(namingPolicies []config.NamingPolicy) ([]NamingPolicyRegexp, error) { | ||
var result []NamingPolicyRegexp | ||
for _, policy := range namingPolicies { | ||
root, err := regexp.Compile(policy.Root) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
match, err := regexp.Compile(policy.Match) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
result = append(result, NamingPolicyRegexp{Root: root, Match: match}) | ||
} | ||
return result, nil | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we adopt the proposed spec from @zoetrope, this example should be updated too.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added an example.