From 4efb12ed0cceece0d8a5e72d2485731a9d766621 Mon Sep 17 00:00:00 2001 From: Sagilio Date: Mon, 11 Oct 2021 23:12:48 +0800 Subject: [PATCH] feat: Implement admission handler and operator Signed-off-by: Sagilio --- pkg/api/admission/v1alpha1/types.go | 46 +-- pkg/kapis/admission/v1alpha1/handler.go | 184 ++++++++++- pkg/kapis/admission/v1alpha1/register.go | 59 +--- .../polciyTemplates/policyTemplates.go | 81 ++++- pkg/models/admission/policies/policies.go | 291 ++++++++++++++++-- pkg/models/admission/provider/gatekeeper.go | 24 +- pkg/models/admission/provider/provider.go | 1 - pkg/models/admission/rules/rules.go | 204 ++++++++++-- .../v1alpha3/admission/policies/policies.go | 77 +++++ .../policytemplates/policytemplates.go | 77 +++++ .../v1alpha3/admission/rules/rules.go | 77 +++++ .../api/admission/v1alpha1/policy_types.go | 3 + .../v1alpha1/policytemplate_types.go | 6 +- .../api/admission/v1alpha1/rule_types.go | 2 +- 14 files changed, 979 insertions(+), 153 deletions(-) create mode 100644 pkg/models/resources/v1alpha3/admission/policies/policies.go create mode 100644 pkg/models/resources/v1alpha3/admission/policytemplates/policytemplates.go create mode 100644 pkg/models/resources/v1alpha3/admission/rules/rules.go diff --git a/pkg/api/admission/v1alpha1/types.go b/pkg/api/admission/v1alpha1/types.go index 2b7e637588..ebab75f5e9 100644 --- a/pkg/api/admission/v1alpha1/types.go +++ b/pkg/api/admission/v1alpha1/types.go @@ -18,12 +18,15 @@ package v1alpha1 import ( "errors" - apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" + "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions" utilerrors "k8s.io/apimachinery/pkg/util/errors" "regexp" ) var ( + ErrProviderNotFound = errors.New("the provide of policy was not found") + ErrTemplateOfProviderNotSupport = errors.New("the template not support the specific provider") + ErrPolicyTemplateNotFound = errors.New("the policy template was not found") ErrPolicyNotFound = errors.New("the policy was not found") @@ -37,27 +40,28 @@ var ( ) type PolicyTemplate struct { - Name string `json:"name"` - Description string `json:"description,omitempty"` - Targets []*PolicyTemplateTarget `json:"targets"` - Parameters Parameters `json:"parameters,omitempty" description:"policy rule parameters"` + Name string `json:"name"` + Description string `json:"description,omitempty"` + Targets []PolicyTemplateTarget `json:"targets"` + Parameters Parameters `json:"parameters,omitempty" description:"policy rule parameters"` } type Policy struct { - Name string `json:"name"` - PolicyTemplate string `json:"templateName,omitempty"` - Provider string `json:"provider,omitempty"` - Description string `json:"description,omitempty"` - Targets []*PolicyTarget `json:"targets"` - Parameters Parameters `json:"parameters,omitempty" description:"policy rule parameters"` + Name string `json:"name"` + PolicyTemplate string `json:"templateName,omitempty"` + Provider string `json:"provider,omitempty"` + Description string `json:"description,omitempty"` + Targets []PolicyTarget `json:"targets"` + Parameters Parameters `json:"parameters,omitempty" description:"policy rule parameters"` } type Rule struct { - Name string `json:"name"` - Policy string `json:"templateName,omitempty"` - Provider string `json:"provider,omitempty"` - Description string `json:"description,omitempty"` - Parameters string `json:"parameters,omitempty"` + Name string `json:"name"` + Policy string `json:"templateName,omitempty"` + Provider string `json:"provider,omitempty"` + Description string `json:"description,omitempty"` + Match Match `json:"match,omitempty"` + Parameters map[string]interface{} `json:"parameters,omitempty"` } // List @@ -124,8 +128,14 @@ type Parameters struct { } type Validation struct { - OpenAPIV3Schema *apiextensionsv1.JSONSchemaProps `json:"openAPIV3Schema,omitempty"` - LegacySchema bool `json:"legacySchema,omitempty"` + OpenAPIV3Schema *apiextensions.JSONSchemaProps `json:"openAPIV3Schema,omitempty"` + LegacySchema bool `json:"legacySchema,omitempty"` +} + +// Match selects objects to apply mutations to. +type Match struct { + Namespaces []string `json:"namespaces,omitempty"` + ExcludedNamespaces []string `json:"excludedNamespaces,omitempty"` } func (r *PostPolicy) Validate() error { diff --git a/pkg/kapis/admission/v1alpha1/handler.go b/pkg/kapis/admission/v1alpha1/handler.go index 562fe7bcb1..39328a825c 100644 --- a/pkg/kapis/admission/v1alpha1/handler.go +++ b/pkg/kapis/admission/v1alpha1/handler.go @@ -23,6 +23,8 @@ import ( "github.com/open-policy-agent/gatekeeper/pkg/target" "k8s.io/klog" ksapi "kubesphere.io/kubesphere/pkg/api" + "kubesphere.io/kubesphere/pkg/api/admission/v1alpha1" + "kubesphere.io/kubesphere/pkg/apiserver/query" kubesphere "kubesphere.io/kubesphere/pkg/client/clientset/versioned" "kubesphere.io/kubesphere/pkg/informers" admissionmodel "kubesphere.io/kubesphere/pkg/models/admission" @@ -83,7 +85,8 @@ func newAdmissionHandler(informers informers.InformerFactory, ksClient kubespher // List func (h admissionHandler) handleListPolicyTemplates(req *restful.Request, resp *restful.Response) { - templateList, err := h.Operator.ListPolicyTemplates(req.Request.Context()) + q := query.ParseQueryParameter(req) + templateList, err := h.Operator.ListPolicyTemplates(req.Request.Context(), q) if err != nil { klog.Error(err) ksapi.HandleInternalError(resp, nil, err) @@ -93,23 +96,25 @@ func (h admissionHandler) handleListPolicyTemplates(req *restful.Request, resp * } func (h admissionHandler) handleListPolicies(req *restful.Request, resp *restful.Response) { - namespace := req.PathParameter("namespace") - policyList, err := h.Operator.ListPolicies(req.Request.Context(), namespace) + q := query.ParseQueryParameter(req) + policyList, err := h.Operator.ListPolicies(req.Request.Context(), q) if err != nil { klog.Error(err) - ksapi.HandleInternalError(resp, nil, err) + ksapi.HandleInternalError(resp, req, err) return } _ = resp.WriteEntity(policyList) } func (h admissionHandler) handleListRules(req *restful.Request, resp *restful.Response) { - namespace := req.PathParameter("namespace") + q := query.ParseQueryParameter(req) policyName := req.PathParameter("policy_name") - ruleList, err := h.Operator.ListRules(req.Request.Context(), namespace, policyName) + ruleList, err := h.Operator.ListRules(req.Request.Context(), policyName, q) if err != nil { - klog.Error(err) - ksapi.HandleInternalError(resp, nil, err) + if err == v1alpha1.ErrPolicyNotFound { + ksapi.HandleNotFound(resp, req, err) + } + ksapi.HandleInternalError(resp, req, err) return } _ = resp.WriteEntity(ruleList) @@ -118,43 +123,188 @@ func (h admissionHandler) handleListRules(req *restful.Request, resp *restful.Re // Get func (h admissionHandler) handleGetPolicyTemplate(req *restful.Request, resp *restful.Response) { - panic("implement me") + templateName := req.PathParameter("template_name") + ruleList, err := h.Operator.GetPolicyTemplate(req.Request.Context(), templateName) + if err != nil { + if err == v1alpha1.ErrPolicyTemplateNotFound { + ksapi.HandleNotFound(resp, req, err) + } + ksapi.HandleInternalError(resp, req, err) + return + } + _ = resp.WriteEntity(ruleList) } func (h admissionHandler) handleGetPolicy(req *restful.Request, resp *restful.Response) { - panic("implement me") + policyName := req.PathParameter("policy_name") + policy, err := h.Operator.GetPolicy(req.Request.Context(), policyName) + if err != nil { + if err == v1alpha1.ErrPolicyNotFound { + ksapi.HandleNotFound(resp, req, err) + } + ksapi.HandleInternalError(resp, req, err) + return + } + _ = resp.WriteEntity(policy) } func (h admissionHandler) handleGetRule(req *restful.Request, resp *restful.Response) { - panic("implement me") + policyName := req.PathParameter("policy_name") + ruleName := req.PathParameter("rule_name") + rule, err := h.Operator.GetRule(req.Request.Context(), policyName, ruleName) + if err != nil { + if err == v1alpha1.ErrPolicyNotFound { + ksapi.HandleNotFound(resp, req, err) + } + if err == v1alpha1.ErrRuleNotFound { + ksapi.HandleNotFound(resp, req, err) + } + ksapi.HandleInternalError(resp, req, err) + return + } + _ = resp.WriteEntity(rule) } // Create func (h admissionHandler) handleCreatePolicy(req *restful.Request, resp *restful.Response) { - panic("implement me") + var policy v1alpha1.PostPolicy + if err := req.ReadEntity(&policy); err != nil { + klog.Error(err) + ksapi.HandleBadRequest(resp, req, err) + return + } + if err := policy.Validate(); err != nil { + klog.Error(err) + ksapi.HandleBadRequest(resp, req, err) + return + } + err := h.Operator.CreatePolicy(req.Request.Context(), &policy) + if err != nil { + if err == v1alpha1.ErrPolicyTemplateNotFound { + ksapi.HandleNotFound(resp, req, err) + } + if err == v1alpha1.ErrTemplateOfProviderNotSupport { + ksapi.HandleBadRequest(resp, req, err) + } + if err == v1alpha1.ErrPolicyAlreadyExists { + ksapi.HandleBadRequest(resp, req, err) + } + ksapi.HandleInternalError(resp, req, err) + return + } } func (h admissionHandler) handleCreateRule(req *restful.Request, resp *restful.Response) { - panic("implement me") + policyName := req.PathParameter("policy_name") + var rule v1alpha1.PostRule + if err := req.ReadEntity(&rule); err != nil { + klog.Error(err) + ksapi.HandleBadRequest(resp, req, err) + return + } + if err := rule.Validate(); err != nil { + klog.Error(err) + ksapi.HandleBadRequest(resp, req, err) + return + } + err := h.Operator.CreateRule(req.Request.Context(), policyName, &rule) + if err != nil { + if err == v1alpha1.ErrPolicyNotFound { + ksapi.HandleNotFound(resp, req, err) + } + if err == v1alpha1.ErrRuleAlreadyExists { + ksapi.HandleBadRequest(resp, req, err) + } + ksapi.HandleInternalError(resp, req, err) + return + } } // Update func (h admissionHandler) handleUpdatePolicy(req *restful.Request, resp *restful.Response) { - panic("implement me") + policyName := req.PathParameter("policy_name") + var policy v1alpha1.PostPolicy + if err := req.ReadEntity(&policy); err != nil { + klog.Error(err) + ksapi.HandleBadRequest(resp, req, err) + return + } + if err := policy.Validate(); err != nil { + klog.Error(err) + ksapi.HandleBadRequest(resp, req, err) + return + } + err := h.Operator.UpdatePolicy(req.Request.Context(), policyName, &policy) + if err != nil { + if err == v1alpha1.ErrPolicyNotFound { + ksapi.HandleNotFound(resp, req, err) + } + if err == v1alpha1.ErrPolicyAlreadyExists { + ksapi.HandleBadRequest(resp, req, err) + } + ksapi.HandleInternalError(resp, req, err) + return + } } func (h admissionHandler) handleUpdateRule(req *restful.Request, resp *restful.Response) { - panic("implement me") + policyName := req.PathParameter("policy_name") + ruleName := req.PathParameter("rule_name") + var rule v1alpha1.PostRule + if err := req.ReadEntity(&rule); err != nil { + klog.Error(err) + ksapi.HandleBadRequest(resp, req, err) + return + } + if err := rule.Validate(); err != nil { + klog.Error(err) + ksapi.HandleBadRequest(resp, req, err) + return + } + err := h.Operator.UpdateRule(req.Request.Context(), policyName, ruleName, &rule) + if err != nil { + if err == v1alpha1.ErrPolicyNotFound { + ksapi.HandleNotFound(resp, req, err) + } + if err == v1alpha1.ErrRuleNotFound { + ksapi.HandleNotFound(resp, req, err) + } + if err == v1alpha1.ErrRuleAlreadyExists { + ksapi.HandleBadRequest(resp, req, err) + } + ksapi.HandleInternalError(resp, req, err) + return + } } // Delete func (h admissionHandler) handleDeletePolicy(req *restful.Request, resp *restful.Response) { - panic("implement me") + policyName := req.PathParameter("policy_name") + err := h.Operator.DeletePolicy(req.Request.Context(), policyName) + if err != nil { + if err == v1alpha1.ErrPolicyNotFound { + ksapi.HandleNotFound(resp, req, err) + } + ksapi.HandleInternalError(resp, req, err) + return + } } func (h admissionHandler) handleDeleteRule(req *restful.Request, resp *restful.Response) { - panic("implement me") + policyName := req.PathParameter("policy_name") + ruleName := req.PathParameter("rule_name") + err := h.Operator.DeleteRule(req.Request.Context(), policyName, ruleName) + if err != nil { + if err == v1alpha1.ErrPolicyNotFound { + ksapi.HandleNotFound(resp, req, err) + } + if err == v1alpha1.ErrRuleNotFound { + ksapi.HandleNotFound(resp, req, err) + } + ksapi.HandleInternalError(resp, req, err) + return + } } diff --git a/pkg/kapis/admission/v1alpha1/register.go b/pkg/kapis/admission/v1alpha1/register.go index 4c46476c5c..bebedba483 100644 --- a/pkg/kapis/admission/v1alpha1/register.go +++ b/pkg/kapis/admission/v1alpha1/register.go @@ -38,7 +38,7 @@ var GroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1alpha1"} func AddToContainer(container *restful.Container, informers informers.InformerFactory, ksClient kubesphere.Interface, option *admission.Options) error { ws := runtime.NewWebService(GroupVersion) - handler := newAdmissionHandler(informers, ksClient, option) + var handler admissionHandlerInterface = newAdmissionHandler(informers, ksClient, option) // List ws.Route(ws.GET("/policytemplates"). @@ -88,18 +88,6 @@ func AddToContainer(container *restful.Container, informers informers.InformerFa Returns(http.StatusOK, ksapi.StatusOK, v1alpha1.RuleDetail{}). Metadata(restfulspec.KeyOpenAPITags, []string{constants.AdmissionRuleTag})) - ws.Route(ws.GET("/policies/{policy_name}"). - To(handler.handleGetPolicy). - Doc("get the policy template with the specified name in the specified namespace"). - Returns(http.StatusOK, ksapi.StatusOK, v1alpha1.PolicyDetail{}). - Metadata(restfulspec.KeyOpenAPITags, []string{constants.AdmissionPolicyTag})) - - ws.Route(ws.GET("/policies/{policy_name}/rules/{rule_name}"). - To(handler.handleGetRule). - Doc("get the policy template with the specified name in the specified namespace"). - Returns(http.StatusOK, ksapi.StatusOK, v1alpha1.RuleDetail{}). - Metadata(restfulspec.KeyOpenAPITags, []string{constants.AdmissionRuleTag})) - // Create ws.Route(ws.POST("/policies/{policy_name}"). To(handler.handleCreatePolicy). @@ -115,21 +103,6 @@ func AddToContainer(container *restful.Container, informers informers.InformerFa Returns(http.StatusOK, ksapi.StatusOK, nil). Metadata(restfulspec.KeyOpenAPITags, []string{constants.AdmissionRuleTag})) - // TODO: namespaced policy - //ws.Route(ws.POST("/namespaces/{namespace}/policies/{policy_name}"). - // To(handler.handleCreatePolicy). - // Doc("create the policy in the specified namespace"). - // Reads(v1alpha1.PostPolicy{}). - // Returns(http.StatusOK, ksapi.StatusOK, nil). - // Metadata(restfulspec.KeyOpenAPITags, []string{constants.AdmissionPolicyTag})) - - ws.Route(ws.POST("/namespaces/{namespace}/policies/{policy_name}/rules/{rule_name}"). - To(handler.handleCreateRule). - Doc("create the rule for the policy in the specified namespace"). - Reads(v1alpha1.PostRule{}). - Returns(http.StatusOK, ksapi.StatusOK, nil). - Metadata(restfulspec.KeyOpenAPITags, []string{constants.AdmissionRuleTag})) - // Update ws.Route(ws.PUT("/policies/{policy_name}"). To(handler.handleUpdatePolicy). @@ -145,21 +118,6 @@ func AddToContainer(container *restful.Container, informers informers.InformerFa Returns(http.StatusOK, ksapi.StatusOK, nil). Metadata(restfulspec.KeyOpenAPITags, []string{constants.AdmissionRuleTag})) - // TODO: namespaced policy - //ws.Route(ws.PUT("/namespaces/{namespace}/policies/{policy_name}"). - // To(handler.handleUpdatePolicy). - // Doc("update the policy in the specified namespace"). - // Reads(v1alpha1.PostPolicy{}). - // Returns(http.StatusOK, ksapi.StatusOK, nil). - // Metadata(restfulspec.KeyOpenAPITags, []string{constants.AdmissionPolicyTag})) - - ws.Route(ws.PUT("/namespaces/{namespace}/policies/{policy_name}/rules/{rule_name}"). - To(handler.handleUpdateRule). - Doc("update the rule for the policy in the specified namespace"). - Reads(v1alpha1.PostRule{}). - Returns(http.StatusOK, ksapi.StatusOK, nil). - Metadata(restfulspec.KeyOpenAPITags, []string{constants.AdmissionRuleTag})) - // delete ws.Route(ws.DELETE("/policies"). To(handler.handleDeletePolicy). @@ -175,21 +133,6 @@ func AddToContainer(container *restful.Container, informers informers.InformerFa Returns(http.StatusOK, ksapi.StatusOK, nil). Metadata(restfulspec.KeyOpenAPITags, []string{constants.AdmissionRuleTag})) - // TODO: namespaced policy - //ws.Route(ws.DELETE("/namespaces/{namespace}/policies"). - // To(handler.handleDeletePolicy). - // Doc("delete the policy in the specified namespace"). - // Param(ws.QueryParameter("name", "policy name").CollectionFormat(restful.CollectionFormatMulti).AllowMultiple(true)). - // Returns(http.StatusOK, ksapi.StatusOK, nil). - // Metadata(restfulspec.KeyOpenAPITags, []string{constants.AdmissionPolicyTag})) - - ws.Route(ws.DELETE("/namespaces/{namespace}/policies/{policy_name}/rules"). - To(handler.handleDeleteRule). - Doc("delete the rule for the policy in the specified namespace"). - Param(ws.QueryParameter("name", "rule name").CollectionFormat(restful.CollectionFormatMulti).AllowMultiple(true)). - Returns(http.StatusOK, ksapi.StatusOK, nil). - Metadata(restfulspec.KeyOpenAPITags, []string{constants.AdmissionRuleTag})) - container.Add(ws) return nil } diff --git a/pkg/models/admission/polciyTemplates/policyTemplates.go b/pkg/models/admission/polciyTemplates/policyTemplates.go index 8295f0baf8..a4c3cbb9fa 100644 --- a/pkg/models/admission/polciyTemplates/policyTemplates.go +++ b/pkg/models/admission/polciyTemplates/policyTemplates.go @@ -2,29 +2,92 @@ package polciyTemplates import ( "context" - "kubesphere.io/kubesphere/pkg/api/alerting/v2alpha1" + admission "kubesphere.io/api/admission/v1alpha1" + "kubesphere.io/kubesphere/pkg/api/admission/v1alpha1" + "kubesphere.io/kubesphere/pkg/apiserver/query" "kubesphere.io/kubesphere/pkg/client/informers/externalversions" + resources "kubesphere.io/kubesphere/pkg/models/resources/v1alpha3" + "kubesphere.io/kubesphere/pkg/models/resources/v1alpha3/admission/policytemplates" + "strings" ) type PolicyTemplateManagerInterface interface { // GetPolicyTemplate gets the admission policy template with the given name. - GetPolicyTemplate(ctx context.Context, templateName string) (*v2alpha1.GettableAlertingRule, error) + GetPolicyTemplate(ctx context.Context, templateName string) (*v1alpha1.PolicyTemplateDetail, error) // ListPolicyTemplates lists the alerts of the custom alerting rule with the given name. - ListPolicyTemplates(ctx context.Context) (*v2alpha1.AlertList, error) + ListPolicyTemplates(ctx context.Context, query *query.Query) (*v1alpha1.PolicyTemplateList, error) } type PolicyTemplateManager struct { - ksInformers externalversions.SharedInformerFactory + getter resources.Interface } func NewPolicyTemplateManager(ksInformers externalversions.SharedInformerFactory) *PolicyTemplateManager { - return &PolicyTemplateManager{ksInformers: ksInformers} + return &PolicyTemplateManager{policytemplates.New(ksInformers)} } -func (p *PolicyTemplateManager) GetPolicyTemplate(ctx context.Context, templateName string) (*v2alpha1.GettableAlertingRule, error) { - panic("implement me") +func (m *PolicyTemplateManager) GetPolicyTemplate(_ context.Context, templateName string) (*v1alpha1.PolicyTemplateDetail, error) { + obj, err := m.getter.Get("", PolicyTemplateUniqueName(templateName)) + if err != nil { + return nil, err + } + template := obj.(*admission.PolicyTemplate).DeepCopy() + if template == nil { + return nil, v1alpha1.ErrPolicyTemplateNotFound + } + return PolicyTemplateDetail(template), nil } -func (p *PolicyTemplateManager) ListPolicyTemplates(ctx context.Context) (*v2alpha1.AlertList, error) { - panic("implement me") +func (m *PolicyTemplateManager) ListPolicyTemplates(_ context.Context, query *query.Query) (*v1alpha1.PolicyTemplateList, error) { + objs, err := m.getter.List("", query) + if err != nil { + return nil, err + } + list := &v1alpha1.PolicyTemplateList{ + Total: objs.TotalItems, + } + for _, obj := range objs.Items { + template := obj.(*admission.PolicyTemplate).DeepCopy() + list.Items = append(list.Items, PolicyTemplate(template)) + } + return list, err +} + +func PolicyTemplateDetail(policy *admission.PolicyTemplate) *v1alpha1.PolicyTemplateDetail { + detail := &v1alpha1.PolicyTemplateDetail{ + PolicyTemplate: *PolicyTemplate(policy), + } + return detail +} + +func PolicyTemplate(policy *admission.PolicyTemplate) *v1alpha1.PolicyTemplate { + targets := policy.Spec.Content.Targets + + var templateTargets []v1alpha1.PolicyTemplateTarget + for _, target := range targets { + templateTargets = append(templateTargets, v1alpha1.PolicyTemplateTarget{ + Target: target.Target, + Expression: target.Expression, + Import: target.Import, + Provider: target.Provider, + }) + } + + validation := policy.Spec.Content.Spec.Parameters.Validation + + return &v1alpha1.PolicyTemplate{ + Name: policy.Spec.Name, + Description: policy.Spec.Description, + Targets: templateTargets, + Parameters: v1alpha1.Parameters{ + Validation: &v1alpha1.Validation{ + OpenAPIV3Schema: validation.OpenAPIV3Schema, + LegacySchema: validation.LegacySchema, + }, + }, + } +} + +func PolicyTemplateUniqueName(templateName string) string { + return strings.ToLower(templateName) } diff --git a/pkg/models/admission/policies/policies.go b/pkg/models/admission/policies/policies.go index 63a2e40e36..33ce1c7fa3 100644 --- a/pkg/models/admission/policies/policies.go +++ b/pkg/models/admission/policies/policies.go @@ -2,51 +2,304 @@ package policies import ( "context" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + admission "kubesphere.io/api/admission/v1alpha1" "kubesphere.io/kubesphere/pkg/api/admission/v1alpha1" + "kubesphere.io/kubesphere/pkg/apiserver/query" kubesphere "kubesphere.io/kubesphere/pkg/client/clientset/versioned" "kubesphere.io/kubesphere/pkg/client/informers/externalversions" + "kubesphere.io/kubesphere/pkg/models/admission/polciyTemplates" "kubesphere.io/kubesphere/pkg/models/admission/provider" + resources "kubesphere.io/kubesphere/pkg/models/resources/v1alpha3" + "kubesphere.io/kubesphere/pkg/models/resources/v1alpha3/admission/policies" + "kubesphere.io/kubesphere/pkg/models/resources/v1alpha3/admission/policytemplates" + "strings" ) type PolicyManagerInterface interface { // GetPolicy gets the admission policy with the given name. - GetPolicy(ctx context.Context, namespace, policyName string) (*v1alpha1.PolicyDetail, error) + GetPolicy(ctx context.Context, policyName string) (*v1alpha1.PolicyDetail, error) // ListPolicies lists the admission policies with the given name. - ListPolicies(ctx context.Context, namespace string) (*v1alpha1.PolicyList, error) + ListPolicies(ctx context.Context, query *query.Query) (*v1alpha1.PolicyList, error) // CreatePolicy creates an admission policy. - CreatePolicy(ctx context.Context, namespace string, policy *v1alpha1.PostPolicy) error + CreatePolicy(ctx context.Context, policy *v1alpha1.PostPolicy) error // UpdatePolicy updates the admission policy with the given name. - UpdatePolicy(ctx context.Context, namespace, policyName string, policy *v1alpha1.PostPolicy) error + UpdatePolicy(ctx context.Context, policyName string, policy *v1alpha1.PostPolicy) error // DeletePolicy deletes the admission policy with the given name. - DeletePolicy(ctx context.Context, namespace, policyName string) error + DeletePolicy(ctx context.Context, policyName string) error } type PolicyManager struct { - ksClient kubesphere.Interface - ksInformers externalversions.SharedInformerFactory - Providers map[string]provider.Provider + ksClient kubesphere.Interface + getter resources.Interface + templateGetter resources.Interface + providers map[string]provider.Provider } func NewPolicyManager(ksClient kubesphere.Interface, ksInformers externalversions.SharedInformerFactory, providers map[string]provider.Provider) *PolicyManager { - return &PolicyManager{ksClient: ksClient, ksInformers: ksInformers, Providers: providers} + return &PolicyManager{ksClient: ksClient, getter: policies.New(ksInformers), templateGetter: policytemplates.New(ksInformers), providers: providers} } -func (p PolicyManager) GetPolicy(ctx context.Context, namespace, policyName string) (*v1alpha1.PolicyDetail, error) { - panic("implement me") +func (m *PolicyManager) GetPolicy(_ context.Context, policyName string) (*v1alpha1.PolicyDetail, error) { + obj, err := m.getter.Get("", PolicyUniqueName(policyName)) + if err != nil { + return nil, err + } + policy := obj.(*admission.Policy).DeepCopy() + if policy == nil { + return nil, v1alpha1.ErrPolicyNotFound + } + return PolicyDetail(policy), nil } -func (p PolicyManager) ListPolicies(ctx context.Context, namespace string) (*v1alpha1.PolicyList, error) { - panic("implement me") +func (m *PolicyManager) ListPolicies(_ context.Context, query *query.Query) (*v1alpha1.PolicyList, error) { + objs, err := m.getter.List("", query) + if err != nil { + return nil, err + } + list := &v1alpha1.PolicyList{ + Total: objs.TotalItems, + } + for _, obj := range objs.Items { + policy := obj.(*admission.Policy).DeepCopy() + list.Items = append(list.Items, Policy(policy)) + } + return list, err } -func (p PolicyManager) CreatePolicy(ctx context.Context, namespace string, policy *v1alpha1.PostPolicy) error { - panic("implement me") +func (m *PolicyManager) CreatePolicy(ctx context.Context, policy *v1alpha1.PostPolicy) error { + obj, err := m.getter.Get("", PolicyUniqueName(policy.Name)) + if err != nil { + return err + } + nowPolicy := obj.(*admission.Policy) + if nowPolicy != nil { + return v1alpha1.ErrPolicyAlreadyExists + } + p, ok := m.providers[policy.Provider] + if !ok { + return v1alpha1.ErrProviderNotFound + } + + var newPolicy *admission.Policy + if policy.PolicyTemplate != "" && len(policy.Targets) == 0 { + obj, err := m.templateGetter.Get("", polciyTemplates.PolicyTemplateUniqueName(policy.PolicyTemplate)) + if err != nil { + return err + } + template := obj.(*admission.PolicyTemplate).DeepCopy() + if template == nil { + return v1alpha1.ErrPolicyTemplateNotFound + } + newPolicy, err = NewPolicyFromTemplate(template, policy.Name, policy.Provider, policy.Description, admission.PolicyInactive) + if err != nil { + return err + } + } else { + newPolicy = NewPolicy(policy, admission.PolicyInactive) + } + + err = p.AddPolicy(ctx, newPolicy) + if err != nil { + return err + } + _, err = m.ksClient.AdmissionV1alpha1().Policies().Create(ctx, newPolicy, metav1.CreateOptions{}) + if err != nil { + return err + } + return nil +} + +func (m *PolicyManager) UpdatePolicy(ctx context.Context, policyName string, policy *v1alpha1.PostPolicy) error { + obj, err := m.getter.Get("", PolicyUniqueName(policyName)) + if err != nil { + return err + } + nowPolicy := obj.(*admission.Policy) + if nowPolicy == nil { + return v1alpha1.ErrPolicyNotFound + } + p, ok := m.providers[nowPolicy.Spec.Provider] + if !ok { + return v1alpha1.ErrProviderNotFound + } + newPolicy := NewPolicy(policy, nowPolicy.Status.State) + err = p.RemovePolicy(ctx, nowPolicy) + if err != nil { + return err + } + err = p.AddPolicy(ctx, newPolicy) + if err != nil { + return err + } + _, err = m.ksClient.AdmissionV1alpha1().Policies().Update(ctx, newPolicy, metav1.UpdateOptions{}) + if err != nil { + return err + } + return nil +} + +func (m *PolicyManager) DeletePolicy(ctx context.Context, policyName string) error { + obj, err := m.getter.Get("", PolicyUniqueName(policyName)) + if err != nil { + return err + } + policy := obj.(*admission.Policy) + if policy == nil { + return v1alpha1.ErrPolicyNotFound + } + p, ok := m.providers[policy.Spec.Provider] + if !ok { + return v1alpha1.ErrProviderNotFound + } + err = p.RemovePolicy(ctx, policy) + if err != nil { + return err + } + err = m.ksClient.AdmissionV1alpha1().Policies().Delete(ctx, PolicyUniqueName(policyName), metav1.DeleteOptions{}) + if err != nil { + return err + } + return nil +} + +func PolicyDetail(policy *admission.Policy) *v1alpha1.PolicyDetail { + detail := &v1alpha1.PolicyDetail{ + Policy: *Policy(policy), + } + return detail +} + +func Policy(policy *admission.Policy) *v1alpha1.Policy { + targets := policy.Spec.Content.Targets + + var policyTargets []v1alpha1.PolicyTarget + for _, target := range targets { + policyTargets = append(policyTargets, v1alpha1.PolicyTarget{ + Target: target.Target, + Expression: target.Expression, + Import: target.Import, + }) + } + + validation := policy.Spec.Content.Spec.Parameters.Validation + + return &v1alpha1.Policy{ + Name: policy.Spec.Name, + PolicyTemplate: policy.Spec.PolicyTemplate, + Provider: policy.Spec.Provider, + Description: policy.Spec.Description, + Targets: policyTargets, + Parameters: v1alpha1.Parameters{ + Validation: &v1alpha1.Validation{ + OpenAPIV3Schema: validation.OpenAPIV3Schema, + LegacySchema: validation.LegacySchema, + }, + }, + } +} + +func NewPolicy(postPolicy *v1alpha1.PostPolicy, state admission.PolicyState) *admission.Policy { + if state == "" { + state = admission.PolicyInactive + } + + params := postPolicy.Parameters + targets := postPolicy.Targets + + var policyTargets []admission.PolicyContentTarget + for _, target := range targets { + policyTargets = append(policyTargets, admission.PolicyContentTarget{ + Target: target.Target, + Expression: target.Expression, + Import: target.Import, + }) + } + + policy := &admission.Policy{ + TypeMeta: metav1.TypeMeta{}, + ObjectMeta: metav1.ObjectMeta{ + Name: PolicyUniqueName(postPolicy.Name), + }, + Spec: admission.PolicySpec{ + Name: postPolicy.Name, + PolicyTemplate: postPolicy.PolicyTemplate, + Description: postPolicy.Description, + Provider: postPolicy.Provider, + Content: admission.PolicyContent{ + Spec: admission.PolicyContentSpec{ + Names: admission.Names{ + Name: postPolicy.Name, + }, + Parameters: admission.Parameters{ + Validation: &admission.Validation{ + OpenAPIV3Schema: params.Validation.OpenAPIV3Schema, + LegacySchema: params.Validation.LegacySchema, + }, + }, + }, + Targets: policyTargets, + }, + }, + Status: admission.PolicyStatus{State: state}, + } + return policy } -func (p PolicyManager) UpdatePolicy(ctx context.Context, namespace, policyName string, policy *v1alpha1.PostPolicy) error { - panic("implement me") +func NewPolicyFromTemplate(template *admission.PolicyTemplate, name string, provider string, desc string, state admission.PolicyState) (*admission.Policy, error) { + if state == "" { + state = admission.PolicyInactive + } + if name == "" { + name = template.Name + } + if desc == "" { + desc = template.Spec.Description + } + templateContent := template.Spec.Content + targets := templateContent.Targets + var policyTargets []admission.PolicyContentTarget + for _, target := range targets { + if target.Provider != provider { + continue + } + policyTargets = append(policyTargets, admission.PolicyContentTarget{ + Target: target.Target, + Expression: target.Expression, + Import: target.Import, + }) + } + + if len(policyTargets) == 0 { + return nil, v1alpha1.ErrTemplateOfProviderNotSupport + } + + policy := &admission.Policy{ + TypeMeta: metav1.TypeMeta{}, + ObjectMeta: metav1.ObjectMeta{ + Name: PolicyUniqueName(name), + Labels: map[string]string{ + admission.AdmissionPolicyTemplateLabel: template.Name, + }, + }, + Spec: admission.PolicySpec{ + Name: name, + PolicyTemplate: template.Spec.Name, + Description: desc, + Provider: provider, + Content: admission.PolicyContent{ + Spec: admission.PolicyContentSpec{ + Names: templateContent.Spec.Names, + Parameters: templateContent.Spec.Parameters, + }, + Targets: policyTargets, + }, + }, + Status: admission.PolicyStatus{State: state}, + } + return policy, nil } -func (p PolicyManager) DeletePolicy(ctx context.Context, namespace, policyName string) error { - panic("implement me") +func PolicyUniqueName(policyName string) string { + return strings.ToLower(policyName) } diff --git a/pkg/models/admission/provider/gatekeeper.go b/pkg/models/admission/provider/gatekeeper.go index ed0a0ccaa7..143182c4e8 100644 --- a/pkg/models/admission/provider/gatekeeper.go +++ b/pkg/models/admission/provider/gatekeeper.go @@ -12,7 +12,14 @@ import ( "strings" ) -const GateKeeperProviderName = "gatekeeper" +const ( + GateKeeperProviderName = "gatekeeper" +) + +var ( + ConstraintsGroup = "constraints.gatekeeper.sh" + ConstraintsVersion = "v1alpha1" +) type GateKeeperProvider struct { *client.Client @@ -111,12 +118,7 @@ func Template(policy *v1alpha1.Policy) (*templates.ConstraintTemplate, error) { func Constraint(rule *v1alpha1.Rule) (*unstructured.Unstructured, error) { c := &unstructured.Unstructured{} - c.SetGroupVersionKind(schema.GroupVersionKind{ - Group: "constraints.gatekeeper.sh", - Version: "v1alpha1", - Kind: rule.Name, - }) - + c.SetGroupVersionKind(ConstraintGvk(rule.Name)) paramMap := map[string]interface{}{} err := json.Unmarshal(rule.Spec.Parameters.Raw, ¶mMap) if err := unstructured.SetNestedMap(c.Object, paramMap, "spec", "parameters"); err != nil { @@ -127,3 +129,11 @@ func Constraint(rule *v1alpha1.Rule) (*unstructured.Unstructured, error) { } return c, nil } + +func ConstraintGvk(kind string) schema.GroupVersionKind { + return schema.GroupVersionKind{ + Group: ConstraintsGroup, + Version: ConstraintsVersion, + Kind: kind, + } +} diff --git a/pkg/models/admission/provider/provider.go b/pkg/models/admission/provider/provider.go index b99b022990..f425535f70 100644 --- a/pkg/models/admission/provider/provider.go +++ b/pkg/models/admission/provider/provider.go @@ -8,7 +8,6 @@ import ( type Provider interface { AddPolicy(ctx context.Context, policy *v1alpha1.Policy) error RemovePolicy(ctx context.Context, policy *v1alpha1.Policy) error - AddRule(ctx context.Context, rule *v1alpha1.Rule) error RemoveRule(ctx context.Context, rule *v1alpha1.Rule) error } diff --git a/pkg/models/admission/rules/rules.go b/pkg/models/admission/rules/rules.go index 9eebd0cdf0..f545dc37de 100644 --- a/pkg/models/admission/rules/rules.go +++ b/pkg/models/admission/rules/rules.go @@ -2,56 +2,218 @@ package rules import ( "context" + "encoding/json" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/klog" admission "kubesphere.io/api/admission/v1alpha1" "kubesphere.io/kubesphere/pkg/api/admission/v1alpha1" + "kubesphere.io/kubesphere/pkg/apiserver/query" kubesphere "kubesphere.io/kubesphere/pkg/client/clientset/versioned" "kubesphere.io/kubesphere/pkg/client/informers/externalversions" "kubesphere.io/kubesphere/pkg/models/admission/provider" + resources "kubesphere.io/kubesphere/pkg/models/resources/v1alpha3" + "kubesphere.io/kubesphere/pkg/models/resources/v1alpha3/admission/rules" + "strings" +) + +const ( + Kind = "rule.kubesphere.io" ) type RuleManagerInterface interface { // GetRule gets the admission rule for the policy. - GetRule(ctx context.Context, namespace, policyName, ruleName string) (*v1alpha1.RuleDetail, error) + GetRule(ctx context.Context, policyName, ruleName string) (*v1alpha1.RuleDetail, error) // ListRules lists the admission rules from the given policy. - ListRules(ctx context.Context, namespace, policyName string) (*v1alpha1.RuleList, error) + ListRules(ctx context.Context, policyName string, query *query.Query) (*v1alpha1.RuleList, error) // CreateRule creates an admission rule for the policy. - CreateRule(ctx context.Context, namespace string, policyName, rule *v1alpha1.PostRule) error + CreateRule(ctx context.Context, policyName string, rule *v1alpha1.PostRule) error // UpdateRule updates the admission rule for the policy with the given name. - UpdateRule(ctx context.Context, namespace, policyName, ruleName string, rule *v1alpha1.PostRule) error + UpdateRule(ctx context.Context, policyName, ruleName string, rule *v1alpha1.PostRule) error // DeleteRule deletes the admission rule for the policy with the given name. - DeleteRule(ctx context.Context, namespace, policyName, ruleName string) error + DeleteRule(ctx context.Context, policyName, ruleName string) error } type RuleManager struct { - ksClient kubesphere.Interface - ksInformers externalversions.SharedInformerFactory - Providers map[string]provider.Provider + ksClient kubesphere.Interface + getter resources.Interface + providers map[string]provider.Provider } func NewRuleManager(ksClient kubesphere.Interface, ksInformers externalversions.SharedInformerFactory, providers map[string]provider.Provider) *RuleManager { - return &RuleManager{ksClient: ksClient, ksInformers: ksInformers, Providers: providers} + return &RuleManager{ksClient: ksClient, getter: rules.New(ksInformers), providers: providers} } -func (r RuleManager) GetRule(ctx context.Context, namespace, policyName, ruleName string) (*v1alpha1.RuleDetail, error) { - panic("implement me") +func (m *RuleManager) GetRule(_ context.Context, policyName, ruleName string) (*v1alpha1.RuleDetail, error) { + obj, err := m.getter.Get("", RuleUniqueName(policyName, ruleName)) + if err != nil { + return nil, err + } + rule := obj.(*admission.Rule).DeepCopy() + if rule == nil { + return nil, v1alpha1.ErrRuleNotFound + } + return RuleDetail(rule), nil } -func (r RuleManager) ListRules(ctx context.Context, namespace, policyName string) (*v1alpha1.RuleList, error) { - panic("implement me") +func (m *RuleManager) ListRules(_ context.Context, policyName string, q *query.Query) (*v1alpha1.RuleList, error) { + q.Filters[admission.ResourcesSingularPolicy] = query.Value(policyName) + objs, err := m.getter.List("", q) + if err != nil { + return nil, err + } + list := &v1alpha1.RuleList{ + Total: objs.TotalItems, + } + for _, obj := range objs.Items { + rule := obj.(*admission.Rule).DeepCopy() + list.Items = append(list.Items, Rule(rule)) + } + return list, err } -func (r RuleManager) CreateRule(ctx context.Context, namespace string, policyName, rule *v1alpha1.PostRule) error { - panic("implement me") +func (m *RuleManager) CreateRule(ctx context.Context, policyName string, rule *v1alpha1.PostRule) error { + obj, err := m.getter.Get("", RuleUniqueName(policyName, rule.Name)) + if err != nil { + return err + } + nowRule := obj.(*admission.Rule) + if nowRule != nil { + return v1alpha1.ErrRuleAlreadyExists + } + p, ok := m.providers[rule.Provider] + if !ok { + return v1alpha1.ErrProviderNotFound + } + newRule := NewRule(policyName, rule, admission.RuleInactive) + err = p.AddRule(ctx, newRule) + if err != nil { + return err + } + _, err = m.ksClient.AdmissionV1alpha1().Rules().Create(ctx, newRule, metav1.CreateOptions{}) + if err != nil { + return err + } + return nil } -func (r RuleManager) UpdateRule(ctx context.Context, namespace, policyName, ruleName string, rule *v1alpha1.PostRule) error { - panic("implement me") +func (m *RuleManager) UpdateRule(ctx context.Context, policyName, ruleName string, rule *v1alpha1.PostRule) error { + obj, err := m.getter.Get("", RuleUniqueName(policyName, ruleName)) + if err != nil { + return err + } + nowRule := obj.(*admission.Rule) + if nowRule == nil { + return v1alpha1.ErrRuleNotFound + } + p, ok := m.providers[nowRule.Spec.Provider] + if !ok { + return v1alpha1.ErrProviderNotFound + } + newRule := NewRule(policyName, rule, nowRule.Status.State) + err = p.RemoveRule(ctx, nowRule) + if err != nil { + return err + } + err = p.AddRule(ctx, newRule) + if err != nil { + return err + } + _, err = m.ksClient.AdmissionV1alpha1().Rules().Update(ctx, newRule, metav1.UpdateOptions{}) + if err != nil { + return err + } + return nil } -func (r RuleManager) DeleteRule(ctx context.Context, namespace, policyName, ruleName string) error { - panic("implement me") +func (m *RuleManager) DeleteRule(ctx context.Context, policyName, ruleName string) error { + obj, err := m.getter.Get("", RuleUniqueName(policyName, ruleName)) + if err != nil { + return err + } + rule := obj.(*admission.Rule) + if rule == nil { + return v1alpha1.ErrRuleNotFound + } + p, ok := m.providers[rule.Spec.Provider] + if !ok { + return v1alpha1.ErrProviderNotFound + } + err = p.RemoveRule(ctx, rule) + if err != nil { + return err + } + err = m.ksClient.AdmissionV1alpha1().Policies().Delete(ctx, RuleUniqueName(policyName, ruleName), metav1.DeleteOptions{}) + if err != nil { + return err + } + return nil } -func Rule(rule *v1alpha1.PostRule) *admission.Rule { - return nil +func RuleDetail(rule *admission.Rule) *v1alpha1.RuleDetail { + detail := &v1alpha1.RuleDetail{ + Rule: *Rule(rule), + } + return detail +} + +func Rule(rule *admission.Rule) *v1alpha1.Rule { + obj := make(map[string]interface{}) + err := json.Unmarshal(rule.Spec.Parameters.Raw, &obj) + if err != nil { + return nil + } + match := v1alpha1.Match{ + Namespaces: rule.Spec.Match.Namespaces, + ExcludedNamespaces: rule.Spec.Match.ExcludedNamespaces, + } + return &v1alpha1.Rule{ + Name: rule.Spec.Name, + Policy: rule.Spec.Policy, + Provider: rule.Spec.Provider, + Description: rule.Spec.Description, + Match: match, + Parameters: obj, + } +} + +func NewRule(policyName string, postRule *v1alpha1.PostRule, state admission.RuleState) *admission.Rule { + postRule.Policy = policyName + parameters, err := json.Marshal(postRule.Parameters) + if err != nil { + klog.Error(err) + parameters = []byte{} + } + if state == "" { + state = admission.RuleInactive + } + rule := &admission.Rule{ + TypeMeta: metav1.TypeMeta{}, + ObjectMeta: metav1.ObjectMeta{ + Name: RuleUniqueName(policyName, postRule.Name), + Labels: map[string]string{ + admission.AdmissionPolicyLabel: postRule.Policy, + admission.AdmissionProviderLabel: postRule.Provider, + }, + }, + Spec: admission.RuleSpec{ + Name: postRule.Name, + Policy: postRule.Policy, + Provider: postRule.Provider, + Description: postRule.Description, + Match: admission.Match{ + Namespaces: postRule.Match.Namespaces, + ExcludedNamespaces: postRule.Match.ExcludedNamespaces, + }, + Parameters: runtime.RawExtension{ + Raw: parameters, + }, + }, + Status: admission.RuleStatus{State: state}, + } + return rule +} + +func RuleUniqueName(policyName, ruleName string) string { + return strings.ToLower(policyName + "_" + ruleName) } diff --git a/pkg/models/resources/v1alpha3/admission/policies/policies.go b/pkg/models/resources/v1alpha3/admission/policies/policies.go new file mode 100644 index 0000000000..c6b4e09d22 --- /dev/null +++ b/pkg/models/resources/v1alpha3/admission/policies/policies.go @@ -0,0 +1,77 @@ +/* +Copyright 2021 The KubeSphere 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 policies + +import ( + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/klog" + admissionv1alpha1 "kubesphere.io/api/admission/v1alpha1" + "kubesphere.io/kubesphere/pkg/api" + "kubesphere.io/kubesphere/pkg/apiserver/query" + ksinformers "kubesphere.io/kubesphere/pkg/client/informers/externalversions" + "kubesphere.io/kubesphere/pkg/models/resources/v1alpha3" +) + +type policiesGetter struct { + ksInformer ksinformers.SharedInformerFactory +} + +func New(f ksinformers.SharedInformerFactory) v1alpha3.Interface { + return &policiesGetter{f} +} + +func (g *policiesGetter) Get(_, name string) (runtime.Object, error) { + policy, err := g.ksInformer.Admission().V1alpha1().Policies().Lister().Get(name) + if err != nil { + klog.Error(err) + return nil, err + } + return policy, nil +} + +func (g *policiesGetter) List(_ string, query *query.Query) (*api.ListResult, error) { + policies, err := g.ksInformer.Admission().V1alpha1().Policies().Lister().List(query.Selector()) + if err != nil { + klog.Error(err) + return nil, err + } + var result []runtime.Object + for _, p := range policies { + result = append(result, p) + } + return v1alpha3.DefaultList(result, query, g.compare, g.filter), nil +} + +func (g *policiesGetter) compare(left runtime.Object, right runtime.Object, field query.Field) bool { + leftPolicy, ok := left.(*admissionv1alpha1.Policy) + if !ok { + return false + } + rightPolicy, ok := right.(*admissionv1alpha1.Policy) + if !ok { + return false + } + return v1alpha3.DefaultObjectMetaCompare(leftPolicy.ObjectMeta, rightPolicy.ObjectMeta, field) +} + +func (g *policiesGetter) filter(object runtime.Object, filter query.Filter) bool { + p, ok := object.(*admissionv1alpha1.Policy) + if !ok { + return false + } + return v1alpha3.DefaultObjectMetaFilter(p.ObjectMeta, filter) +} diff --git a/pkg/models/resources/v1alpha3/admission/policytemplates/policytemplates.go b/pkg/models/resources/v1alpha3/admission/policytemplates/policytemplates.go new file mode 100644 index 0000000000..dccca0b3d2 --- /dev/null +++ b/pkg/models/resources/v1alpha3/admission/policytemplates/policytemplates.go @@ -0,0 +1,77 @@ +/* +Copyright 2021 The KubeSphere 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 policytemplates + +import ( + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/klog" + admissionv1alpha1 "kubesphere.io/api/admission/v1alpha1" + "kubesphere.io/kubesphere/pkg/api" + "kubesphere.io/kubesphere/pkg/apiserver/query" + ksinformers "kubesphere.io/kubesphere/pkg/client/informers/externalversions" + "kubesphere.io/kubesphere/pkg/models/resources/v1alpha3" +) + +type policyTemplateGetter struct { + ksInformer ksinformers.SharedInformerFactory +} + +func New(f ksinformers.SharedInformerFactory) v1alpha3.Interface { + return &policyTemplateGetter{f} +} + +func (g *policyTemplateGetter) Get(_, name string) (runtime.Object, error) { + template, err := g.ksInformer.Admission().V1alpha1().PolicyTemplates().Lister().Get(name) + if err != nil { + klog.Error(err) + return nil, err + } + return template, nil +} + +func (g *policyTemplateGetter) List(_ string, query *query.Query) (*api.ListResult, error) { + templates, err := g.ksInformer.Admission().V1alpha1().PolicyTemplates().Lister().List(query.Selector()) + if err != nil { + klog.Error(err) + return nil, err + } + var result []runtime.Object + for _, p := range templates { + result = append(result, p) + } + return v1alpha3.DefaultList(result, query, g.compare, g.filter), nil +} + +func (g *policyTemplateGetter) compare(left runtime.Object, right runtime.Object, field query.Field) bool { + leftTemplate, ok := left.(*admissionv1alpha1.PolicyTemplate) + if !ok { + return false + } + rightTemplate, ok := right.(*admissionv1alpha1.PolicyTemplate) + if !ok { + return false + } + return v1alpha3.DefaultObjectMetaCompare(leftTemplate.ObjectMeta, rightTemplate.ObjectMeta, field) +} + +func (g *policyTemplateGetter) filter(object runtime.Object, filter query.Filter) bool { + p, ok := object.(*admissionv1alpha1.PolicyTemplate) + if !ok { + return false + } + return v1alpha3.DefaultObjectMetaFilter(p.ObjectMeta, filter) +} diff --git a/pkg/models/resources/v1alpha3/admission/rules/rules.go b/pkg/models/resources/v1alpha3/admission/rules/rules.go new file mode 100644 index 0000000000..eb945b2840 --- /dev/null +++ b/pkg/models/resources/v1alpha3/admission/rules/rules.go @@ -0,0 +1,77 @@ +/* +Copyright 2021 The KubeSphere 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 rules + +import ( + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/klog" + admissionv1alpha1 "kubesphere.io/api/admission/v1alpha1" + "kubesphere.io/kubesphere/pkg/api" + "kubesphere.io/kubesphere/pkg/apiserver/query" + ksinformers "kubesphere.io/kubesphere/pkg/client/informers/externalversions" + "kubesphere.io/kubesphere/pkg/models/resources/v1alpha3" +) + +type rulesGetter struct { + ksInformer ksinformers.SharedInformerFactory +} + +func New(f ksinformers.SharedInformerFactory) v1alpha3.Interface { + return &rulesGetter{f} +} + +func (g *rulesGetter) Get(namespace, name string) (runtime.Object, error) { + rule, err := g.ksInformer.Admission().V1alpha1().Rules().Lister().Get(name) + if err != nil { + klog.Error(err) + return nil, err + } + return rule, nil +} + +func (g *rulesGetter) List(_ string, query *query.Query) (*api.ListResult, error) { + rules, err := g.ksInformer.Admission().V1alpha1().Rules().Lister().List(query.Selector()) + if err != nil { + klog.Error(err) + return nil, err + } + var result []runtime.Object + for _, p := range rules { + result = append(result, p) + } + return v1alpha3.DefaultList(result, query, g.compare, g.filter), nil +} + +func (g *rulesGetter) compare(left runtime.Object, right runtime.Object, field query.Field) bool { + leftRule, ok := left.(*admissionv1alpha1.Rule) + if !ok { + return false + } + rightRule, ok := right.(*admissionv1alpha1.Rule) + if !ok { + return false + } + return v1alpha3.DefaultObjectMetaCompare(leftRule.ObjectMeta, rightRule.ObjectMeta, field) +} + +func (g *rulesGetter) filter(object runtime.Object, filter query.Filter) bool { + p, ok := object.(*admissionv1alpha1.Rule) + if !ok { + return false + } + return v1alpha3.DefaultObjectMetaFilter(p.ObjectMeta, filter) +} diff --git a/staging/src/kubesphere.io/api/admission/v1alpha1/policy_types.go b/staging/src/kubesphere.io/api/admission/v1alpha1/policy_types.go index 00930a59e0..5b21cb06af 100644 --- a/staging/src/kubesphere.io/api/admission/v1alpha1/policy_types.go +++ b/staging/src/kubesphere.io/api/admission/v1alpha1/policy_types.go @@ -24,6 +24,9 @@ const ( ResourceKindPolicy = "Policy" ResourcesSingularPolicy = "policy" ResourcesPluralPolicy = "policies" + + AdmissionPolicyLabel = "kubesphere.io/admission/policy" + AdmissionProviderLabel = "kubesphere.io/admission/provider" ) // +genclient diff --git a/staging/src/kubesphere.io/api/admission/v1alpha1/policytemplate_types.go b/staging/src/kubesphere.io/api/admission/v1alpha1/policytemplate_types.go index 0aad8f0654..24d87f1621 100644 --- a/staging/src/kubesphere.io/api/admission/v1alpha1/policytemplate_types.go +++ b/staging/src/kubesphere.io/api/admission/v1alpha1/policytemplate_types.go @@ -23,8 +23,10 @@ import ( const ( ResourceKindPolicyTemplate = "PolicyTemplate" - ResourcesSingularPolicyTemplate = "policyTemplate" - ResourcesPluralPolicyTemplate = "policyTemplates" + ResourcesSingularPolicyTemplate = "policytemplate" + ResourcesPluralPolicyTemplate = "policytemplates" + + AdmissionPolicyTemplateLabel = "kubesphere.io/admission/policytemplate" ) // +genclient diff --git a/staging/src/kubesphere.io/api/admission/v1alpha1/rule_types.go b/staging/src/kubesphere.io/api/admission/v1alpha1/rule_types.go index f1af337387..393d3f7c33 100644 --- a/staging/src/kubesphere.io/api/admission/v1alpha1/rule_types.go +++ b/staging/src/kubesphere.io/api/admission/v1alpha1/rule_types.go @@ -23,7 +23,7 @@ import ( ) const ( - ResourceKindRule = "PolicyTemplate" + ResourceKindRule = "Rule" ResourcesSingularRule = "rule" ResourcesPluralRule = "rules" )