{"id":22096872,"url":"https://github.com/streamnative/pulumi-controller-runtime","last_synced_at":"2025-07-24T22:32:31.026Z","repository":{"id":40480615,"uuid":"382469064","full_name":"streamnative/pulumi-controller-runtime","owner":"streamnative","description":"A prototype of a Kubernetes controller based on Pulumi.","archived":false,"fork":false,"pushed_at":"2023-07-05T21:05:43.000Z","size":214,"stargazers_count":9,"open_issues_count":2,"forks_count":1,"subscribers_count":24,"default_branch":"master","last_synced_at":"2024-06-21T18:11:26.017Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/streamnative.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-07-02T21:33:49.000Z","updated_at":"2023-06-02T11:14:27.000Z","dependencies_parsed_at":"2024-06-21T16:49:36.435Z","dependency_job_id":"eda4874d-7849-46ff-b3fd-c13b552bb381","html_url":"https://github.com/streamnative/pulumi-controller-runtime","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/streamnative%2Fpulumi-controller-runtime","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/streamnative%2Fpulumi-controller-runtime/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/streamnative%2Fpulumi-controller-runtime/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/streamnative%2Fpulumi-controller-runtime/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/streamnative","download_url":"https://codeload.github.com/streamnative/pulumi-controller-runtime/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":227482464,"owners_count":17779968,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-12-01T04:12:58.553Z","updated_at":"2024-12-01T04:12:59.129Z","avatar_url":"https://github.com/streamnative.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"_This project is in an alpha stage, not suitable for production usage.  Expect breaking changes._\n\n# Purpose\n\nContollers/Operators frequently follow this pattern:\n\n1. They have an API extension (ex. CRD) that declaratively describes what one would like deployed\n2. The controller/operator watches for creations and updates (ex. of the CRD)\n3. A kubernetes object (ex CR) is created or updated\n4. The operator responds to the change and works forward to get the cluster to the neccessary final state (ex creating a statefulset,\nupdating a service account, ectera)\n\nThe last step is where the substance of many operators reside; however, the code is often boiletplate and boring.\nGather the state of the cluster, figure out the difference between what is needed and what exists on the cluster,\nand do the neccessary creates, updates, and deletes. Often sequentially and frequently checking for errors.\n\n**Our CRDs give us a declarative way to specify what we want to deploy but we find ourselves writing controllers imperatively.**\nOur utility in this component is to show how to use the Pulumi Go SDK to write declarative code, eliminating the often common imperative parts\nof our controllers/operators.\n\n# Getting Started\nThis library is designed to work with any Kubernetes controller that is based on\nthe [kubernetes-sigs/controller-runtime](https://github.com/kubernetes-sigs/controller-runtime) library.\nUse the [Kubebuilder](https://book.kubebuilder.io/) tool to scaffold an ordinary Kubernetes controller.\n\nSee the sample controller in `sample/`.\n\n## Implement a Custom Resource\nYou'll use this library to implement a reconciler for your custom resource.   A reconciler typically provisions\nresources based on a resource specification, and that specification will be defined using the Pulumi Go SDK, as a \nresource graph built within the reconciliation loop.  The other task of a reconciler is to maintain a status block \non the resource object.  A status block primarily consists of conditions that reflect the object's current state\nwith respect to its specification.  Your reconciliation loop uses Pulumi stack state to update the status information.\n\n### Reconciler Struct\nA typical reconciler is implemented as a `struct` that implements the `Reconciler` interface.  To use Pulumi\nwithin your reocnciler, embed the `pulumireconcile.PulumiReconciler` type.\n\n### Controller Setup\nDuring the setup of your controller, configure the `PulumiReconciler`.  For example:\n```go\nfunc (r *IamAccountReconciler) SetupWithManager(mgr ctrl.Manager) error {\n\t// Build a Pulumi-based reconciler for IamAccount, with resources defined by the MakeResources function\n\tr.PulumiReconciler, _ := pulumireconcile.NewReconcilerManagedBy(mgr).\n\t\tFor(\u0026samplev1.IamAccount{}).\n\t\tWithProgram(r.MakeResources).\n\t\tWithOptions(pulumireconcile.FinalizerName(FinalizerName)).\n\t\tBuild()\n\n\treturn ctrl.NewControllerManagedBy(mgr).\n\t\tFor(\u0026samplev1.IamAccount{}).\n\t\tWithEventFilter(predicate.GenerationChangedPredicate{}).\n\t\tComplete(r)\n}\n```\n\n### Reconcile\nIn the `Reconcile` function, get the custom object as normal.  Use the object's metadata and specification to\nset configuration values for the object's Pulumi stack configuration.  It is also possible to generate the resource graph\nbased on the object; the library provides the whole object as a configuration value named `obj`.\n\nInvoke the `ReconcileObject` function on your reconciler.  The library performs the following tasks:\n1. Calls the program function (provided during setup and described below) to generate a resource graph.\n2. Fetches the current stack state, and makes a callback to your reconciler to update the status block of the custom object.\n3. Applies changes to the resource.\n4. If any changes were made, updates the status again.\n\nThe library implements object finalization automatically.  When the custom object is marked for deletion, the library\ndestroys the current resources.\n\n_This functionality may change based on feedback.  One thought is to not handle finalization automatically, in favor of\nhaving the reconciler call `Up` or `Destroy` instead of `ReconcileObject`.  This would be to improve\nflexibility._\n\n### Resource Graph\nYour reconciler uses the Pulumi Go SDK to define a resource graph for the custom object.  The library\nprovides your reconciler with a context object for this purpose.\n\nFor example, here's an implementation of `ReconcileObject` that simply creates a Kubernetes Service Account (KSA)\nusing the [Pulumi Kubernetes Provider](https://www.pulumi.com/registry/packages/kubernetes/#pulumi-kubernetes-provider).\n\n```go\nfunc (r *IamAccountReconciler) MakeResources(ctx *pulumi.Context) error {\n    // obtain the object being reconciled as a configuration parameter.\n    conf := pulumiconfig.New(ctx, \"\")\n    obj := samplev1.IamAccount{}\n    conf.RequireObject(\"obj\", \u0026obj)\n    \n    // make a KSA for the IamAccount object\n    ksa, err := pulumicorev1.NewServiceAccount(ctx, \"iamaccount\", \u0026pulumicorev1.ServiceAccountArgs{\n        Metadata: \u0026pulumimetav1.ObjectMetaArgs{\n            Name:        pulumi.StringPtr(makeServiceAccountId(\u0026obj)),\n            Namespace:   pulumi.StringPtr(obj.Namespace),\n        },\n    })\n    if err != nil {\n        return err\n    }\n    ctx.Export(\"ksa\", ksa.Metadata.Name())\n    return nil\n}\n```\n\nUse configuration values, such as the custom object itself or selected values from it, to parameterize the resource graph.\n\nUse stack outputs to expose output values to your reconciler.\n\n_Future: add support for stack references to other objects._\n\n### Status Update\nBefore making changes, Pulumi generates a plan that reflects the planned additions, deletions, and other modifications to\nthe object's resources.  The plan may be used to update the status of the custom object itself.  For example, imagine that\nthe custom object's resource graph consists of a Kubernetes `Deployment` object.  The `Ready` condition of the object\nshould reflect the readiness of the deployment.  The plan contains enough information for your reconciler to report on\ncurrent conditions.\n\nAn important aspect to keep in mind is the mutability of your custom object's specification.  As a specification changes\nover time, Kubernetes automatically increments the `metadata.generation` field.  Your object's status block should\ncontain an `observedGeneration` field that is managed by your reconciler.  When you update the status with the Pulumi plan in hand,\nset the `observedGeneration` to the `generation` that the plan is based on.  Keep in mind that a status condition reflects\ncurrent conditions _with respect to that generation_.\n\nUse admission control webhooks to impose constraints on mutability as desired.\n\n### Stack State\nEach custom resource object that undergoes reconciliation has an independent resource graph and associated stack that is named\nafter the object.  The stack configuration is not stored as a file (e.g. `Pulumi.foo.yaml`, but is set by the reconciler\nduring the reconciliation loop.\n\nThe library uses Kubernetes secrets as a state backend, one secret per custom resource object.  \n\n_In the future, tools will be developed to import and export the stack state for operational purposes._\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstreamnative%2Fpulumi-controller-runtime","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fstreamnative%2Fpulumi-controller-runtime","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstreamnative%2Fpulumi-controller-runtime/lists"}