-
Notifications
You must be signed in to change notification settings - Fork 0
feat: implement job primitive #26
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
Changes from all commits
5924932
0cf92c9
a17d2b9
f5b042b
d59c276
2d257fd
0fdd811
1534d48
a46382a
1522f24
4733a38
8f166b9
5f71355
12070ac
15df44a
27a4dec
46f8082
ebb22c4
9918500
7f0e9bf
5736a4b
639d12a
cb763d3
6059324
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 | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,256 @@ | ||||||
| # Job Primitive | ||||||
|
|
||||||
| The `job` primitive is the framework's built-in task abstraction for managing Kubernetes `Job` resources. It integrates | ||||||
| fully with the component lifecycle and provides a rich mutation API for managing containers, pod specs, and metadata — | ||||||
| following the same pod-template mutation pattern as the Deployment primitive. | ||||||
|
|
||||||
sourcehawk marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
| ## Capabilities | ||||||
|
|
||||||
| | Capability | Detail | | ||||||
| | ----------------------- | ----------------------------------------------------------------------------------------------- | | ||||||
| | **Completion tracking** | Monitors Job conditions and reports `Completed`, `TaskRunning`, `TaskPending`, or `TaskFailing` | | ||||||
| | **Suspension** | Sets `spec.suspend=true` or deletes the Job (default); reports `Suspending` / `Suspended` | | ||||||
|
||||||
| | **Suspension** | Sets `spec.suspend=true` or deletes the Job (default); reports `Suspending` / `Suspended` | | |
| | **Suspension** | Suspends/stops the Job (for example via `spec.suspend=true`) and, by default, deletes it once `Suspended`; reports `Suspending` / `Suspended` | |
sourcehawk marked this conversation as resolved.
Show resolved
Hide resolved
sourcehawk marked this conversation as resolved.
Show resolved
Hide resolved
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
| # Job Primitive Example | ||
|
|
||
| This example demonstrates the usage of the `job` primitive within the operator component framework. It shows how to | ||
| manage a Kubernetes Job as a component of a larger application, utilizing features like: | ||
|
|
||
| - **Base Construction**: Initializing a Job with basic metadata, spec, and restart policy. | ||
| - **Feature Mutations**: Applying version-gated or conditional changes (env vars, image version, retry policies) using | ||
| the `Mutator`. | ||
| - **Custom Status Handlers**: Overriding the default `ConvergingStatus` interface using the `WithCustomConvergeStatus` | ||
| builder option. | ||
| - **Suspension**: Demonstrating how Jobs are suspended (deleted by default) when the component is suspended. | ||
| - **Data Extraction**: Harvesting information from the reconciled resource. | ||
|
|
||
| ## Directory Structure | ||
|
|
||
| - `app/`: Defines the mock `ExampleApp` CRD and the controller that uses the component framework. | ||
| - `features/`: Contains modular feature definitions: | ||
| - `mutations.go`: tracing env vars, retry policies, and version-based image updates. | ||
| - `status.go`: implementation of a custom handler for completion status. | ||
| - `resources/`: Contains the central `NewJobResource` factory that assembles all features using the `job.Builder`. | ||
| - `main.go`: A standalone entry point that demonstrates a single reconciliation loop using a fake client. | ||
|
|
||
| ## Running the Example | ||
|
|
||
| You can run this example directly using `go run`: | ||
|
|
||
| ```bash | ||
| go run examples/job-primitive/main.go | ||
| ``` | ||
|
|
||
| This will: | ||
|
|
||
| 1. Initialize a fake Kubernetes client. | ||
| 2. Create an `ExampleApp` owner object. | ||
| 3. Reconcile the `ExampleApp` components through multiple spec changes. | ||
| 4. Print the resulting status conditions after each reconciliation step. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,54 @@ | ||
| // Package app provides a sample controller using the job primitive. | ||
| package app | ||
|
|
||
| import ( | ||
| "context" | ||
|
|
||
| "github.com/sourcehawk/operator-component-framework/pkg/component" | ||
| "k8s.io/apimachinery/pkg/runtime" | ||
| "k8s.io/client-go/tools/record" | ||
| "sigs.k8s.io/controller-runtime/pkg/client" | ||
| ) | ||
|
|
||
| // ExampleController reconciles an ExampleApp object using the component framework. | ||
| type ExampleController struct { | ||
| client.Client | ||
| Scheme *runtime.Scheme | ||
| Recorder record.EventRecorder | ||
| Metrics component.Recorder | ||
|
|
||
| // NewJobResource is a factory function to create the job resource. | ||
| // This allows us to inject the resource construction logic. | ||
| NewJobResource func(*ExampleApp) (component.Resource, error) | ||
| } | ||
|
|
||
| // Reconcile performs the reconciliation for a single ExampleApp. | ||
| func (r *ExampleController) Reconcile(ctx context.Context, owner *ExampleApp) error { | ||
| // 1. Build the job resource for this owner. | ||
| jobResource, err := r.NewJobResource(owner) | ||
| if err != nil { | ||
| return err | ||
| } | ||
|
|
||
| // 2. Build the component that manages the job. | ||
| comp, err := component.NewComponentBuilder(). | ||
| WithName("example-migration"). | ||
| WithConditionType("MigrationReady"). | ||
| WithResource(jobResource, component.ResourceOptions{}). | ||
| Suspend(owner.Spec.Suspended). | ||
| Build() | ||
| if err != nil { | ||
| return err | ||
| } | ||
|
|
||
| // 3. Execute the component reconciliation. | ||
| resCtx := component.ReconcileContext{ | ||
| Client: r.Client, | ||
| Scheme: r.Scheme, | ||
| Recorder: r.Recorder, | ||
| Metrics: r.Metrics, | ||
| Owner: owner, | ||
| } | ||
|
|
||
| return comp.Reconcile(ctx, resCtx) | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| package app | ||
|
|
||
| import ( | ||
| sharedapp "github.com/sourcehawk/operator-component-framework/examples/shared/app" | ||
| ) | ||
|
|
||
| // ExampleApp re-exports the shared CRD type so callers in this package need no import alias. | ||
| type ExampleApp = sharedapp.ExampleApp | ||
|
|
||
| // ExampleAppSpec re-exports the shared spec type. | ||
| type ExampleAppSpec = sharedapp.ExampleAppSpec | ||
|
|
||
| // ExampleAppStatus re-exports the shared status type. | ||
| type ExampleAppStatus = sharedapp.ExampleAppStatus | ||
|
|
||
| // ExampleAppList re-exports the shared list type. | ||
| type ExampleAppList = sharedapp.ExampleAppList | ||
|
|
||
| // AddToScheme registers the ExampleApp types with the given scheme. | ||
| var AddToScheme = sharedapp.AddToScheme |
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.
PR description checklist says this PR “does not modify shared files”, but this PR updates shared docs (this file) and also changes shared editor tests (pkg/mutation/editors/jobspec_test.go). Please either update the checklist/description to reflect these shared changes, or revert them if they were unintended.