Skip to content

Commit

Permalink
Merge a2b964c into 12e8e0c
Browse files Browse the repository at this point in the history
  • Loading branch information
waleedhammam authored Feb 19, 2023
2 parents 12e8e0c + a2b964c commit f137d7e
Show file tree
Hide file tree
Showing 10 changed files with 390 additions and 14 deletions.
21 changes: 20 additions & 1 deletion api/v2beta2/policyconfig_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@ var (
PolicyConfigGroupVersionResource = GroupVersion.WithResource(PolicyConfigResourceName)
)

// PolicyConfigStatus will hold the policies ids that don't exist in the cluster
type PolicyConfigStatus struct {
Status string `json:"status,omitempty"`
MissingPolicies []string `json:"missingPolicies,omitempty"`
}
type PolicyTargetApplication struct {
//+kubebuilder:validation:Enum=HelmRelease;Kustomization
Kind string `json:"kind"`
Expand Down Expand Up @@ -62,12 +67,26 @@ type PolicyConfigSpec struct {
// +kubebuilder:object:root=true
// +kubebuilder:resource:scope=Cluster
// +kubebuilder:storageversion
// +kubebuilder:subresource:status
// +kubebuilder:printcolumn:name="Status",type=string,JSONPath=`.status.status`
// +kubebuilder:printcolumn:name="Age",type=date,JSONPath=`.metadata.creationTimestamp`

// PolicyConfig is the Schema for the policyconfigs API
type PolicyConfig struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`
Spec PolicyConfigSpec `json:"spec,omitempty"`
Spec PolicyConfigSpec `json:"spec,omitempty"`
Status PolicyConfigStatus `json:"status,omitempty"`
}

// SetPolicyConfigStatus sets policy config status
func (c *PolicyConfig) SetPolicyConfigStatus(missingPolicies []string) {
if len(missingPolicies) > 0 {
c.Status.Status = "Warning"
} else {
c.Status.Status = "OK"
}
c.Status.MissingPolicies = missingPolicies
}

func (c *PolicyConfig) Validate() error {
Expand Down
21 changes: 21 additions & 0 deletions api/v2beta2/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion codecov.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ coverage:
project:
default:
target: auto # auto compares coverage to the previous base commit
threshold: 0.2% # percentage of coverage allowed to be decreased
threshold: 1.5% # percentage of coverage allowed to be decreased
22 changes: 21 additions & 1 deletion config/crd/bases/pac.weave.works_policyconfigs.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,14 @@ spec:
singular: policyconfig
scope: Cluster
versions:
- name: v2beta2
- additionalPrinterColumns:
- jsonPath: .status.status
name: Status
type: string
- jsonPath: .metadata.creationTimestamp
name: Age
type: date
name: v2beta2
schema:
openAPIV3Schema:
description: PolicyConfig is the Schema for the policyconfigs API
Expand Down Expand Up @@ -87,9 +94,22 @@ spec:
- config
- match
type: object
status:
description: PolicyConfigStatus will hold the policies ids that don't
exist in the cluster
properties:
missingPolicies:
items:
type: string
type: array
status:
type: string
type: object
type: object
served: true
storage: true
subresources:
status: {}
status:
acceptedNames:
kind: ""
Expand Down
2 changes: 0 additions & 2 deletions controllers/policy_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@ func (p *PolicyReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctr
if apierrors.IsNotFound(err) {
return ctrl.Result{}, nil
}
logger.Errorw("unable to get policy", "error", err)
return ctrl.Result{}, err
}

Expand All @@ -51,7 +50,6 @@ func (p *PolicyReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctr

var policySets pacv2.PolicySetList
if err := p.List(ctx, &policySets); err != nil {
logger.Errorw("unable to list policysets", "error", err)
return ctrl.Result{}, err
}

Expand Down
109 changes: 104 additions & 5 deletions controllers/policyconfig_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,32 @@ import (
"fmt"
"net/http"

"github.com/MagalixTechnologies/core/logger"
pacv2 "github.com/weaveworks/policy-agent/api/v2beta2"
apierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/fields"
"k8s.io/apimachinery/pkg/types"

ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/builder"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/handler"
"sigs.k8s.io/controller-runtime/pkg/predicate"
"sigs.k8s.io/controller-runtime/pkg/reconcile"
"sigs.k8s.io/controller-runtime/pkg/source"
"sigs.k8s.io/controller-runtime/pkg/webhook"
"sigs.k8s.io/controller-runtime/pkg/webhook/admission"
)

type PolicyConfigValidator struct {
type PolicyConfigController struct {
Client client.Client
decoder *admission.Decoder
}

const (
policyConfigIndexKey = "spec.config.policies"
)

func checkTargetOverlap(config, newConfig pacv2.PolicyConfig) error {
if config.Spec.Match.Namespaces != nil {
if newConfig.Spec.Match.Namespaces == nil {
Expand Down Expand Up @@ -65,7 +78,7 @@ func checkTargetOverlap(config, newConfig pacv2.PolicyConfig) error {
return nil
}

func (pc *PolicyConfigValidator) Handle(ctx context.Context, req admission.Request) admission.Response {
func (pc *PolicyConfigController) Handle(ctx context.Context, req admission.Request) admission.Response {
newConfig := &pacv2.PolicyConfig{}
err := pc.decoder.Decode(req, newConfig)
if err != nil {
Expand Down Expand Up @@ -94,16 +107,102 @@ func (pc *PolicyConfigValidator) Handle(ctx context.Context, req admission.Reque
return admission.Allowed("")
}

func (pc *PolicyConfigValidator) SetupWithManager(mgr ctrl.Manager) error {
func (pc *PolicyConfigController) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
logger.Infow("reconciling policy config", "policy config", req.Name)

policyConfig := pacv2.PolicyConfig{}
if err := pc.Client.Get(ctx, req.NamespacedName, &policyConfig); err != nil {
return ctrl.Result{}, client.IgnoreNotFound(err)
}

if !policyConfig.DeletionTimestamp.IsZero() {
return ctrl.Result{}, nil
}

policyConfigConfig := policyConfig.Spec.Config

missingPolicies := []string{}

for policyID := range policyConfigConfig {
policy := pacv2.Policy{}
policyName := types.NamespacedName{
Name: policyID,
}
if err := pc.Client.Get(ctx, policyName, &policy); err != nil {
if apierrors.IsNotFound(err) {
missingPolicies = append(missingPolicies, policyID)
} else {
return ctrl.Result{}, err
}
}
}
patch := client.MergeFrom(policyConfig.DeepCopy())
policyConfig.SetPolicyConfigStatus(missingPolicies)

logger.Infow("updating policy config config status", "name", req.Name, "status", policyConfig.Status.Status, "warnings", missingPolicies)
if err := pc.Client.Status().Patch(ctx, &policyConfig, patch); err != nil {
return ctrl.Result{}, err
}
return ctrl.Result{}, nil
}

func (p *PolicyConfigController) reconcile(obj client.Object) []reconcile.Request {
policiesConfigs := &pacv2.PolicyConfigList{}
opts := client.ListOptions{
FieldSelector: fields.OneTermEqualSelector(policyConfigIndexKey, obj.GetName()),
}

err := p.Client.List(context.Background(), policiesConfigs, &opts)
if err != nil {
return []reconcile.Request{}
}
requests := make([]reconcile.Request, len(policiesConfigs.Items))
for i, item := range policiesConfigs.Items {
requests[i] = reconcile.Request{
NamespacedName: types.NamespacedName{
Name: item.Name,
},
}
}
return requests
}

func (pc *PolicyConfigController) SetupWithManager(mgr ctrl.Manager) error {
mgr.GetWebhookServer().Register(
"/validate-v2beta2-policyconfig",
&webhook.Admission{Handler: pc},
)
return nil

err := mgr.GetFieldIndexer().IndexField(context.Background(), &pacv2.PolicyConfig{}, policyConfigIndexKey, func(obj client.Object) []string {
policyConfig, ok := obj.(*pacv2.PolicyConfig)
if !ok {
return nil
}
policyIDs := []string{}
for policyID := range policyConfig.Spec.Config {
policyIDs = append(policyIDs, policyID)
}
return policyIDs
})

if err != nil {
return err
}

// watch both policies and policy config in case user changed either of them
return ctrl.NewControllerManagedBy(mgr).
For(&pacv2.PolicyConfig{}).
Watches(
&source.Kind{Type: &pacv2.Policy{}},
handler.EnqueueRequestsFromMapFunc(pc.reconcile),
builder.WithPredicates(predicate.ResourceVersionChangedPredicate{}),
).
Complete(pc)

}

// InjectDecoder injects the decoder.
func (pc *PolicyConfigValidator) InjectDecoder(d *admission.Decoder) error {
func (pc *PolicyConfigController) InjectDecoder(d *admission.Decoder) error {
pc.decoder = d
return nil
}
Loading

0 comments on commit f137d7e

Please sign in to comment.