{"id":13646024,"url":"https://github.com/operatify/operatify","last_synced_at":"2026-01-14T22:54:01.710Z","repository":{"id":57504183,"uuid":"222215893","full_name":"operatify/operatify","owner":"operatify","description":"Operators made simple for resources with CRUD APIs","archived":false,"fork":false,"pushed_at":"2020-09-13T10:51:46.000Z","size":16822,"stargazers_count":22,"open_issues_count":2,"forks_count":1,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-04-21T17:42:47.355Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"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/operatify.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"docs/CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-11-17T08:01:26.000Z","updated_at":"2022-02-12T19:33:06.000Z","dependencies_parsed_at":"2022-08-28T02:01:51.639Z","dependency_job_id":null,"html_url":"https://github.com/operatify/operatify","commit_stats":null,"previous_names":[],"tags_count":4,"template":false,"template_full_name":null,"purl":"pkg:github/operatify/operatify","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/operatify%2Foperatify","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/operatify%2Foperatify/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/operatify%2Foperatify/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/operatify%2Foperatify/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/operatify","download_url":"https://codeload.github.com/operatify/operatify/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/operatify%2Foperatify/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28437136,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-14T22:37:52.437Z","status":"ssl_error","status_checked_at":"2026-01-14T22:37:31.496Z","response_time":107,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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-08-02T01:02:47.025Z","updated_at":"2026-01-14T22:54:01.691Z","avatar_url":"https://github.com/operatify.png","language":"Go","funding_links":[],"categories":["Go"],"sub_categories":[],"readme":"# Operatify\n\n***Operators made simple for resources with CRUD management APIs.***\n\nOperatify provides a generic custom controller implementation for [Kubebuilder](https://book.kubebuilder.io/) operators for resources with management APIs \nconsisting of CRUD (create, read, update and delete) operations, typically REST APIs. These may be for example:\n* Cloud resources and services\n* PaaS (Platform as a Service) services\n\nFor a full motivation and introduction, see [this blog post](https://www.stephenzoio.com/kubernetes-operators-for-resource-management/).\n\n## Roadmap\n\n* Example operators forthcoming... watch this space for details.\n\n## Getting Started\n\n### Building Operatify\n\nA dev container is provided with all the dependencies installed for your convenience. These include:\n\n* [Kubebuilder](https://book.kubebuilder.io/)\n* [Kustomise](https://github.com/kubernetes-sigs/kustomize)\n* [Kind (Kubernetes in Docker)](https://github.com/kubernetes-sigs/kind)\n\nTo make and run tests:\n* Changed to the `./.devcontainer` folder.\n* Run `./build.sh`\n* Run `docker-conmpose up`\n* In another terminal window run a bash shell in this container `docker exec -it devcontainer_docker-in-docker_1 bash`\n* In this shell run `make test`\n\nIf all goes according to plan, you should see the following output or something similar:\n\n```text\nRan 19 of 19 Specs in 24.559 seconds\nSUCCESS! -- 19 Passed | 0 Failed | 0 Pending | 0 Skipped\n--- PASS: TestAPIs (24.56s)\n```\n\nYou can also spin up a Kind cluster and run tests against that:\n    \n```\nmake set-kindcluster\nUSE_EXISTING_CLUSTER=\"true\" make test\n```\n\n### Using Operatify\n\nStart by following the Kubebuilder Instructions [as in their tutorial](https://book.kubebuilder.io/cronjob-tutorial/cronjob-tutorial.html)\n\n1. Initialise the Kubebuilder project:\n\n    ```bash\n    kubebuilder init --domain my.domain\n    ```\n\n2. Add the following require to your `go.mod` file (use the latest release version rather than v0.1.1 below).\n\n    ```go\n    github.com/operatify/operatify v0.1.1\n    ```\n    \n3. Add the following import where required:\n\n    ```go\n    import \"github.com/operatify/operatify/reconciler\"\n    ```\n    \n4. Create a new API:\n\n    ```bash\n    kubebuilder create api --group mygroup --version v1 --kind MyResource\n    ```\n    \n    This will ask you if you want to:\n    * create a resource (y/n) - type `y`.\n    * create a controller (y/n) - you can do this, but you will end up deleting the code it generates. We only need the following markers, which Kubebuilder uses:\n    ```go\n    // +kubebuilder:rbac:groups=mygroup.my.domain,resources=myresources,verbs=get;list;watch;create;update;patch;delete\n    // +kubebuilder:rbac:groups=mygroup.my.domain,resources=myresources/status,verbs=get;update;patch\n    ```\n    \n5. Create an operator controller for this resource.\n\n    To do so we need to:\n    * Implement the `ResourceManager` interface.\n    * Implement the `DefinitionManager` interface.\n    * Call the `CreateGenericController` method to create a `GenericController`.\n    \n    This `GenericController` implements the `Reconciler` interface of the Kubernetes controller runtime:\n    ```go\n    type Reconciler interface {\n    \tReconcile(Request) (Result, error)\n    }\n    ```\n\n6. Wire this into our main method. \n\n    Take a look at the example `main.go` to see how this is done.\n\n## Implementation details\n\n### Resource diffing\n\nEvery time the `Create` or `Update` method returns successfully, \nan `[annotation-base-name]/last-applied-spec` \nannotation is saved with the Json representation of the `spec` that was used to create or update the resource. \n\n### Passing back status data\n\nThe `Create`, `Update` and `Verify` can also return an extra status payload return parameter. \nThis is an `interface{}`, so can be anything. The idea is this should be saved as a status field in the manifest. \nThe reconciler will not care about it, but can be passed back into the subsequent calls to `Verify`.\n\n#### Locking down access control\n\nIt is possible to restrict acess control to certain external resources to prevent unintended modifications and deletes.\nThe reconciler recognises an annotation `[annotation-base-name]/access-permissions`, \nin which it recognises each one of the permissions, create, update and delete via the initial. \nRead permission is implicit. For example `\"CD\"` is permission to create and delete, `\"CUD\"` is everything (the default if this annotation is not defined), and anything that doesn't have these initials (e.g. `\"none\"`)\n is read-only permissions.\n \nRead-only permission allows one to assert the state of a dependent resource without being able to modify or deleting it.\n\nIf the delete permission is not set, it will simply not delete the external resource when the Kubernetes resource is delete.\nHowever if the `Verify` method returns `VerifyResultRecreateRequired` and delete permission is not present, it will return an error.\n\n#### Implementing a handler upon success\n\nSometimes after creating or updating a resource, further interaction with Kubenetes is necessary.\n\nFor example an operator that provisions a database may need to create a Kubernetes secret with database credentials.  \n\nTo facilitate this, a hook to invoke these interactions which gets called, if it is defined, after a successful create or update operation.\n\nTo define this hook, we need to call the `CreateGenericController` with a non-nil `completetionRunner` parameter.\n\nThis is more accurately a factory method for a `CompletionRunner`:\n\n```go\ntype CompletionRunner interface {\n\tRun(ctx context.Context, r runtime.Object) error\n}\n```\n\nThe implementation of this operation must be idempotent.\n\nBecause the factory method gets the `GenericController` instance, it has full access to both the Kubernetes client and the `ResourceManager` instance.\nThis the only instance where such power is given to the user. \n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Foperatify%2Foperatify","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Foperatify%2Foperatify","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Foperatify%2Foperatify/lists"}