pepr icon indicating copy to clipboard operation
pepr copied to clipboard

Include a combined example of Mutate/Validate/Watch where each enforce the same policy

Open bburky opened this issue 9 months ago • 0 comments

related to #288 -> (replacement example should have this below)

Include an example in the documentation that combines all of:

  • Mutation of newly created resources (Mutate())
  • Validation enforcing the mutation occurred (Validate())
  • Enforcement of policy on startup (during Pepr startup/restart Watch() observes existing resources, kubernetes-fluent-client can apply changes back to cluster)
    • This same Watch() also does background drift detection
    • This also enables changing Pepr configuration/capabilities, restarting Pepr, and applying updated policy to existing resources.

The example in the README is actually fairly close to this: it creates a label in Mutate() and then checks it in Validate(). The example's Watch doesn't use the label though and doesn't enforce the same policy. It could check for the same label, apply the same mutation and fixup existing resources with kubernetes-fluent-client.

Ideally I'd like to see an example using a shared JS function between Mutate/Validate/Watch, to show that you can write the logic once in terms of mutation, then reuse it in each. This isn't required though. Maybe a future helper function in Pepr could simplify this workflow, but it isn't required.

A contrived example with some pseudo code that reuses a mutation function:

// Validates the argument and patches it in place if invalid
function validateAndFixNamespace(ns) {
  if (ns.metadata.name?.startsWith("foo")) {
    ns.metadata.name = `bar-${ns.metadata.name}`;
    return true;
  }
  return false;
}

When(a.Namespace)
  .Mutate((request) => {
    // Fixup any new resources on the fly during creation
    validateAndFixNamespace(req.Raw);
  })
  .Validate((request) => {
    // Validate does the same check as Mutate, shouldn't ever be needed but this is how you correctly do enforcement in Validate instead of Mutate
    const fixed = deepcopy(req.Raw);
    if (validateAndFixNamespace(fixed)) {
      // Provide nice output to the user.
      // If you don't want to show a diff you can skip the deepcopy above entirely and just write a static message here
      return request.Deny(`Namespace is invalid, required changes: ${diff(req.Raw, fixed)}`);
    }
    return request.Approve()
  })
  .Watch((ns) => {
    // Fix up any existing resources in the cluster during Pepr startup (and do drift detection on any that somehow bypass the admission controller)
    if (validateAndFixNamespace(ns)) {
      kube.apply(ns);
    }
  })

bburky avatar Oct 03 '23 22:10 bburky