Skip to content

Commit

Permalink
chore: document sdk helpers (#774)
Browse files Browse the repository at this point in the history
## Description
Document the sdk helpers in the Pepr docs.
...

## Related Issue

Fixes #751
<!-- or -->
Relates to #

## Type of change

- [ ] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Other (security config, docs update, etc)

## Checklist before merging

- [ ] Test, docs, adr added or updated as needed
- [ ] [Contributor Guide
Steps](https://docs.pepr.dev/main/contribute/contributor-guide/#submitting-a-pull-request)
followed

---------

Co-authored-by: Case Wylie <cmwylie19@defenseunicorns.com>
  • Loading branch information
schaeferka and cmwylie19 committed May 2, 2024
1 parent b1337ae commit 2c5c47e
Show file tree
Hide file tree
Showing 7 changed files with 198 additions and 48 deletions.
13 changes: 1 addition & 12 deletions docs/030_user-guide/010_pepr-cli.md
Original file line number Diff line number Diff line change
@@ -1,22 +1,11 @@
# Pepr CLI

- [Pepr CLI](#pepr-cli)
- [`npx pepr init`](#npx-pepr-init)
- [`npx pepr update`](#npx-pepr-update)
- [`npx pepr dev`](#npx-pepr-dev)
- [`npx pepr deploy`](#npx-pepr-deploy)
- [`npx pepr monitor`](#npx-pepr-monitor)
- [`npx pepr uuid`](#npx-pepr-uuid)
- [`npx pepr build`](#npx-pepr-build)
- [`npx pepr kfc`](#npx-pepr-kfc)

## `npx pepr init`

Initialize a new Pepr Module.

**Options:**


- `--skip-post-init` - Skip npm install, git init and VSCode launch

---
Expand All @@ -27,7 +16,6 @@ Update the current Pepr Module to the latest SDK version. This command is not re

**Options:**


- `--skip-template-update` - Skip updating the template files

---
Expand Down Expand Up @@ -97,6 +85,7 @@ Create a [zarf.yaml](https://zarf.dev) and K8s manifest for the current module.
- `-v, --version <version>. Example: '0.27.3'` - The version of the Pepr image to use in the deployment manifests.

## `npx pepr kfc`

Execute a `kubernetes-fluent-client` command. This command is a wrapper around `kubernetes-fluent-client`.

Usage:
Expand Down
93 changes: 93 additions & 0 deletions docs/030_user-guide/015_sdk.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
# Pepr SDK

## `containers`

Returns list of all containers in a pod. Accepts the following parameters:

- **@param peprValidationRequest** The request/pod to get the containers from
- **@param containerType** The type of container to get

**Usage:**

**_Get all containers_**

```typescript
let result = containers(peprValidationRequest)
```

**_Get only the standard containers_**

```typescript
let result = containers(peprValidationRequest, "containers")
```

**_Get only the init containers_**

```typescript
let result = containers(peprValidationRequest, "initContainers")
```

**_Get only the ephemeral containers_**

```typescript
let result = containers(peprValidationRequest, "ephemeralContainers")
```

---

## `getOwnerRefFrom`

Returns the owner reference for a Kubernetes resource. Accepts the following parameters:

- **@param kubernetesResource: GenericKind** The Kubernetes resource to get the owner reference for

**Usage:**

```typescript
const ownerRef = getOwnerRefFrom(kubernetesResource);

---

## `writeEvent`

Write a K8s event for a CRD. Accepts the following parameters:

- **@param kubernetesResource: GenericKind** The Kubernetes resource to write the event for
- **@param event** The event to write, should contain a human-readable message for the event
- **@param eventType** The type of event to write, for example "Warning"
- **@param eventReason** The reason for the event, for example "ReconciliationFailed"
- **@param reportingComponent** The component that is reporting the event, for example "uds.dev/operator"
- **@param reportingInstance** The instance of the component that is reporting the event, for example process.env.HOSTNAME

**Usage:**

```typescript
writeEvent(
kubernetesResource,
event,
"Warning",
"ReconciliationFailed",
"uds.dev/operator",
process.env.HOSTNAME,
);
```

---

## `sanitizeResourceName`

Returns a sanitized resource name to make the given name a valid Kubernetes resource name. Accepts the following parameter:

- **@param resourceName** The name of the resource to sanitize

**Usage:**

```typescript
const sanitizedResourceName = sanitizeResourceName(resourceName)
```

---

## See Also

Looking for information on the Pepr mutate helpers? See [Helpers](./030_actions/010_mutate.md) for information on helpers for mutate actions.
83 changes: 83 additions & 0 deletions docs/030_user-guide/030_actions/010_mutate.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
# Mutate

Mutating admission webhooks are invoked first and can modify objects sent to the API server to enforce custom defaults. After an object is sent to Pepr's Mutating Admission Webhook, Pepr will [annotate the object](https://github.com/defenseunicorns/pepr/blob/f01f5eeda16c13ecd0d51b26b8a16ed7e4c1b080/src/lib/mutate-processor.ts#L64) to indicate the status.

After a successful mutation of an object in a module with UUID static-test, and capability name hello-pepr, expect to see this annotation: `static-test.pepr.dev/hello-pepr: succeeded`.

## Mutate Helpers

### `SetLabel`

`SetLabel` is used to set a lable on a Kubernetes object as part of a Pepr Mutate action.

For example, to add a label when a ConfigMap is created:

```typescript
When(a.ConfigMap)
.IsCreated()
.Mutate(request => {
request
// Here we are adding a label to the ConfigMap.
.SetLabel("pepr", "was-here")

// Note that we are not returning anything here. This is because Pepr is tracking the changes in each action automatically.
});
```

### `RemoveLabel`

`RemoveLabel` is used to remove a label on a Kubernetes object as part of a Pepr Mutate action.

For example, to remove a label when a ConfigMap is updated:

```typescript
When(a.ConfigMap)
.IsCreated()
.Mutate(request => {
request
// Here we are removing a label from the ConfigMap.
.RemoveLabel("remove-me")

// Note that we are not returning anything here. This is because Pepr is tracking the changes in each action automatically.
});
```

### `SetAnnotation`

`SetAnnotation` is used to set an annotation on a Kubernetes object as part of a Pepr Mutate action.

For example, to add an annotation when a ConfigMap is created:

```typescript
When(a.ConfigMap)
.IsCreated()
.Mutate(request => {
request
// Here we are adding an annotation to the ConfigMap.
.SetAnnotation("pepr.dev", "annotations-work-too");

// Note that we are not returning anything here. This is because Pepr is tracking the changes in each action automatically.
});
```

### `RemoveAnnotation`

`RemoveAnnotation` is used to remove an annotation on a Kubernetes object as part of a Pepr Mutate action.

For example, to remove an annotation when a ConfigMap is updated:

```typescript
When(a.ConfigMap)
.IsUpdated()
.Mutate(request => {
request
// Here we are removing an annotation from the ConfigMap.
.RemoveAnnotation("remove-me");

// Note that we are not returning anything here. This is because Pepr is tracking the changes in each action automatically.
});
```

## See Also

See also [SDK](../130_sdk.md) for information on the Pepr SDK.
5 changes: 5 additions & 0 deletions docs/030_user-guide/030_actions/020_validate.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Validate

After the Mutation phase comes the Validation phase where the validating admission webhooks are invoked and can reject requests to enforce custom policies.

Validate does not annotate the objects that are allowed into the cluster, but the validation webhook can be audited with `npx pepr monitor`. Read the [monitoring docs](https://docs.pepr.dev/main/best-practices/#monitoring) for more information.
3 changes: 3 additions & 0 deletions docs/030_user-guide/030_actions/030_reconcile.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Reconcile

Reconcile functions the same as Watch but is tailored for building Kubernetes Controllers and Operators because it processes callback operations in a [Queue](https://github.com/defenseunicorns/pepr/blob/f01f5eeda16c13ecd0d51b26b8a16ed7e4c1b080/src/lib/watch-processor.ts#L86), guaranteeing ordered and synchronous processing of events, even when the system may be under heavy load.
3 changes: 3 additions & 0 deletions docs/030_user-guide/030_actions/040_watch.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Watch

[Kubernetes](https://kubernetes.io/docs/reference/using-api/api-concepts) supports efficient change notifications on resources via watches. Pepr uses the Watch action for monitoring resources that previously existed in the cluster and for performing long-running asynchronous events upon receiving change notifications on resources, as watches are not limited by [timeouts](https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/#timeouts).
Original file line number Diff line number Diff line change
@@ -1,13 +1,7 @@
# Actions

- [Overview](#overview)
- [Mutate](#mutate)
- [Validate](#validate)
- [Watch](#watch)
- [Reconcile](#reconcile)

## Overview

## Overview

An action is a discrete set of behaviors defined in a single function that acts on a given Kubernetes GroupVersionKind (GVK) passed in during the admission controller lifecycle. Actions are the atomic operations that are performed on Kubernetes resources by Pepr.

For example, an action could be responsible for adding a specific label to a Kubernetes resource, or for modifying a specific field in a resource's metadata. Actions can be grouped together within a Capability to provide a more comprehensive set of operations that can be performed on Kubernetes resources.
Expand Down Expand Up @@ -83,40 +77,40 @@ When(WebApp)
.IsCreatedOrUpdated()
.Validate(validator)
.Reconcile(async instance => {

const { namespace, name, generation } = instance.metadata;

if (!instance.metadata?.namespace) {
Log.error(instance, `Invalid WebApp definition`);
return;
}

const isPending = instance.status?.phase === Phase.Pending;
const isCurrentGeneration = generation === instance.status?.observedGeneration;

if (isPending || isCurrentGeneration) {
Log.debug(instance, `Skipping pending or completed instance`);
return;
}

Log.debug(instance, `Processing instance ${namespace}/${name}`);


try {
// Set Status to pending
await updateStatus(instance, { phase: Phase.Pending });

// Deploy Deployment, ConfigMap, Service, ServiceAccount, and RBAC based on instance
await Deploy(instance);

// Set Status to ready
await updateStatus(instance, {
phase: Phase.Ready,
observedGeneration: instance.metadata.generation,
});
} catch (e) {
Log.error(e, `Error configuring for ${namespace}/${name}`);

// Set Status to failed
void updateStatus(instance, {
phase: Phase.Failed,
Expand All @@ -125,23 +119,3 @@ When(WebApp)
}
});
```

## Mutate

Mutating admission webhooks are invoked first and can modify objects sent to the API server to enforce custom defaults. After an object is sent to Pepr's Mutating Admission Webhook, Pepr will [annotate the object](https://github.com/defenseunicorns/pepr/blob/f01f5eeda16c13ecd0d51b26b8a16ed7e4c1b080/src/lib/mutate-processor.ts#L64) to indicate the status.

After a successful mutation of an object in a module with UUID static-test, and capability name hello-pepr, expect to see this annotation: `static-test.pepr.dev/hello-pepr: succeeded`.

## Validate

After the Mutation phase, after all object modifications are complete, and after the incoming object is validated by the API server, validating admission webhooks are invoked and can reject requests to enforce custom policies.

Validate does not annotate the objects that are allowed into the cluster, but the validation webhook can be audited with `npx pepr monitor`. Read the [monitoring docs](https://docs.pepr.dev/main/best-practices/#monitoring) for more information.

## Watch

[Kubernetes](https://kubernetes.io/docs/reference/using-api/api-concepts) supports efficient change notifications on resources via watches. Pepr uses the Watch action for monitoring resources that previously existed in the cluster and for performing long-running asynchronous events upon receiving change notifications on resources, as watches are not limited by [timeouts](https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/#timeouts).

## Reconcile

Reconcile functions the same as Watch but is tailored for building Kubernetes Controllers and Operators because it processes callback operations in a [Queue](https://github.com/defenseunicorns/pepr/blob/f01f5eeda16c13ecd0d51b26b8a16ed7e4c1b080/src/lib/watch-processor.ts#L86), guaranteeing ordered and synchronous processing of events, even when the system may be under heavy load.

0 comments on commit 2c5c47e

Please sign in to comment.