{"id":27203160,"url":"https://github.com/rhpds/anarchy","last_synced_at":"2025-04-09T22:02:51.978Z","repository":{"id":41984596,"uuid":"191686210","full_name":"rhpds/anarchy","owner":"rhpds","description":"An operator for adding state for arbitrary api interactions","archived":false,"fork":false,"pushed_at":"2024-10-31T18:24:32.000Z","size":2903,"stargazers_count":28,"open_issues_count":23,"forks_count":10,"subscribers_count":10,"default_branch":"main","last_synced_at":"2025-04-09T22:02:44.497Z","etag":null,"topics":["babylon","gpte"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/rhpds.png","metadata":{"files":{"readme":"README.adoc","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-06-13T03:42:00.000Z","updated_at":"2025-02-05T19:21:01.000Z","dependencies_parsed_at":"2024-07-16T22:15:52.503Z","dependency_job_id":"06a65b4a-e889-4b4b-b0bc-5093761cce2c","html_url":"https://github.com/rhpds/anarchy","commit_stats":null,"previous_names":["rhpds/anarchy"],"tags_count":151,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rhpds%2Fanarchy","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rhpds%2Fanarchy/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rhpds%2Fanarchy/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rhpds%2Fanarchy/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rhpds","download_url":"https://codeload.github.com/rhpds/anarchy/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248119296,"owners_count":21050755,"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":["babylon","gpte"],"created_at":"2025-04-09T22:02:51.279Z","updated_at":"2025-04-09T22:02:51.960Z","avatar_url":"https://github.com/rhpds.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"= Anarchy\n\nimage::docs/Anarchy.png[Anarchy Diagram,300,300]\n\n== Introducing a Little Anarchy\n\nThe world of Kubernetes management is experiencing an Operator revolution.\n\n“The Operator pattern aims to capture the key aim of a human operator who is managing a service or set of services.\nHuman operators who look after specific applications and services have deep knowledge of how the system ought to behave, how to deploy it, and how to react if there are problems.\n\n“People who run workloads on Kubernetes often like to use automation to take care of repeatable tasks.\nThe Operator pattern captures how you can write code to automate a task beyond what Kubernetes itself provides.”\n\n— https://kubernetes.io/docs/concepts/extend-kubernetes/operator/[Kubernetes Operator Motivation^]\n\nUnfortunately, operators are all too often wresting control away from the mere humans who would manage their own resources.\nMost Operators embed their logic in compiled container images.\nThe typical human systems operator does not program in Go and does not have a container image build pipeline.\nHuman application operators may have experince with builds, but often do not have cluster administrative rights required to deploy operators.\n\nAnarchy democratizes the potential of the Operator pattern by putting the operator logic in the operator configuration. Users write their own logic in Ansible, which requires little more programming experience than using a command line. Through configuration, the Ansible code is directly controlled at runtime to automate anything you can do in the cluster.\nAnarchy makes your cluster truly self-governing.\n\n== Anarchy in Action\n\nTODO - Add example anarchy operator for managing an application with a Helm chart.\n\n== Architecture\n\nimage::docs/AnarchyDiagram.png[Anarchy Diagram,545,131]\n\nEach AnarchySubject is managed by an AnarchyGovernor.\nEach AnarchyGovernor is configured to run Ansible tasks on a single AnarchyRunner.\nAnarchySubjects can have AnarchyActions created to schedule task execution.\nAnarchyRuns are created for specific Ansible task execution, for processing an subject event handler, run an action, or handle an action callback event.\n\nimage::docs/AnarchyCallbackDiagram.png[Anarchy Diagram,748,338]\n\n. An action defined in the AnarchyGovernor config is scheduled for an AnarchySubject, creating an AnarchyAction\n. An AnarchyRun is created to execute the AnarchyAction's tasks\n. Ansible in the AnarchyRun calls a Job Template or Survey in Ansible Tower, passing the callback URL and token for the AnarchyAction\n. Ansible executing in Ansible Tower calls the AnarchyAction callback\n. A new AnarchyRun is created to process the callback from Tower\n. The AnarchyRun for the callback updates the status of the AnarchySubject\n\n== Installation\n\n=== Prerequisite\n\nAnarchy is using [Kopf](https://github.com/nolar/kopf) and needs the `kopfpeerings.kopf.dev` CustomResourceDefinition must be configured before deploying Anarchy.\n\n---------------------------------\noc apply -f kopfpeerings.crd.yaml\n---------------------------------\n\n=== Install with Helm\n\nClone this repo to your local workstation and change directory:\n\n----\ngit clone https://github.com/redhat-cop/anarchy.git\ncd anarchy\n----\n\nInstall with Helm\n\n----\nhelm template anarchy helm/ --include-crds | oc apply -f -\n----\n\nCheck your to make sure the anarchy-operator pod is running and the default runner starts soon after:\n\n-------------------------------------------------------------------------\n$ oc get pods\nNAME                                     READY   STATUS    RESTARTS   AGE\nanarchy-5f7d7898d7-f6dww                 1/1     Running   0          11m\nanarchy-runner-default-9767c79b6-vt6b4   1/1     Running   0          12m\n-------------------------------------------------------------------------\n\nAnarchy can be installed even if you do not have cluster admin privileges. This will require the CRDs and ClusterRoles to already have been installed.\n\n----\nhelm template anarchy helm/ | oc apply -f -\n----\n\n== Anarchy Design\n\nThe Anarchy Operator is configured with custom resource type AnarchyGovernor in order to manage AnarchySubject resources.\nEach AnarchySubject is managed according to a single AnarchyGovernor.\nThe AnarchyGovernor defines actions to perform against APIs to instantiate and manage the AnarchySubject.\nEach action performed for an AnarchySubject according to the AnarchyGovernor definition is represented as an AnarchyAction custom resource.\nAn AnarchyAction always begins with an call to an API.\nThe Anarchy operator listens for callbacks to its own API for events relating to actions such as notifications that an action has completed, or encountered an error.\nThe AnarchyGovernor defines event handlers for actions which may include scheduling further AnarchyActions to occur for the AnarchySubject.\n\nThis repository includes a test suite that demonstrates these capabilities by calling a test API.\nThe usage of the test suite is explained in the \"Testing\" section below.\nThe conceptual overview of the test design is described here.\n\nLet's start with the AnarchySubject definition:\n\n----\napiVersion: anarchy.gpte.redhat.com/v1\nkind: AnarchySubject\nmetadata:\n  generateName: test-\n  namespace: anarchy-operator\nspec:\n  desiredState: started \u003c1\u003e\n  governor: test \u003c2\u003e\n  parameters: \u003c3\u003e\n    openshift_release: \"4.1\"\n    aws_region: us-east-1\n    repo_version: \"3.11\"\n    subdomain_base_suffix: .example.opentlc.com\n----\n\n\u003c1\u003e The desired state of the resource, this is an arbitrary string which should be implemented by the AnarchyGovernor.\n\u003c2\u003e The test AnarchySubject references the name of the AnarchyGovernor that will manage it.\n\u003c3\u003e Each subject may include a list of parameters to pass to the API, though the governor and API get the final say in how and when the parameters are used.\n\nThe test AnarchyGovernor definition is shown here:\n\n----\napiVersion: anarchy.gpte.redhat.com/v1\nkind: AnarchyGovernor\nmetadata:\n  name: test\nspec:\n  # Ansible processing for this governor will occur on the default runner.\n  runner: default\n\n  var:\n    ansible_tower_hostname: tower.example.com\n    cloud_provider: ec2\n  varSecrets:\n  - name: api-creds\n    var: api_creds\n  - name: aws-credentials\n\n  # The `subjectEventHandlers` provide configuration for how to respond to\n  # AnarchySubjects being added, updated, and deleted.\n  subjectEventHandlers:\n    # The `create` event is processed only for subjects that are newly created.\n    create:\n      tasks:\n        # The `anarchy_subject_update` module is provided to make it easy to\n        # update the AnarchySubject relating to the current action.\n        - name: Set state provision-scheduled in subject status\n          anarchy_subject_update:\n            metadata:\n              labels:\n                state: provision-scheduled\n            status:\n              state: provision-scheduled\n        # The `anarchy_schedule_action` module is used to create AnarchyActions\n        # for the current AnarchySubject. In this case it schedules an\n        # AnarchyAction to be processed immediately.\n        - name: Start Provision\n          anarchy_schedule_action:\n            action: provision\n\n    # The `update` event is processed when a resource changes.\n    update:\n      # The `anarchy_subject` variable stores the state of the AnarchySubject\n      # which triggered this update. A useful pattern is to implement state\n      # handling using `spec.desiredState` and `status.state`.\n      - when: \u003e-\n          anarchy_subject.spec.desiredState|default('') == 'started' and\n          (anarchy_subject.status|default({})).state|default('') == 'stopped'\n        block:\n        - name: Set state start-scheduled in subject status\n          anarchy_subject_update:\n            metadata:\n              labels:\n                state: start-scheduled\n            status:\n              state: start-scheduled\n        - name: Schedule start\n          anarchy_schedule_action:\n            action: start\n      - when: \u003e-\n          anarchy_subject.spec.desiredState|default('stopped') == 'stopped' and\n          (anarchy_subject.status|default({})).state|default('') == 'started'\n        block:\n        - name: Set state stop-scheduled in subject status\n          anarchy_subject_update:\n            metadata:\n              labels:\n                state: stop-scheduled\n            status:\n              state: stop-scheduled\n        - name: Schedule stop\n          anarchy_schedule_action:\n            action: stop\n\n    # The `delete` event is processed when a subject delete is requsted. This\n    # is detected by the presence of a `metadata.deletionTimestamp`. This should\n    # schedule an action that will result in removing the finalizer from the\n    # subject when complete.\n    delete:\n      tasks:\n      - name: Schedule destroy\n        anarchy_schedule_action:\n          action: destroy\n\n  # Actions represent entry points for doing something related to a resource.\n  # Each action here consists of an API request followed by `callbackHandlers`\n  # to respond to callbacks from the API endpoint.\n  actions:\n    provision:\n      tasks:\n      - name: Call API\n        uri:\n          url: https://{{ ansible_tower_hostname }}/api/v2/job_templates/job-runner/launch/\n          url_username: \"{{ api_creds.user }}\"\n          url_password: \"{{ api_creds.password }}\"\n          validate_certs: false\n          method: POST\n          return_content: true\n          body_format: json\n          body:\n            extra_vars:\n              job_vars: \u003e-\n                {{ anarchy_subject.vars.job_vars | default({})\n                 | combine(anarchy_governor.vars.job_vars, recursive=True)\n                 | combine({\n                     'ACTION': 'provision',\n                     '__meta__': {\n                       'deployer': {'entry_point': 'ansible/main.yml'},\n                       'tower': {'action': 'provision'}\n                     }\n                   }, recursive=True)\n                }}\n        ignore_errors: true\n\n      callbackHandlers:\n        started:\n          tasks:\n          - name: Set state provisioning in subject status\n            anarchy_subject_update:\n              metadata:\n                labels:\n                  state: provisioning\n              status:\n                state: provisioning\n        - event: complete\n          tasks:\n          - name: Set state started in subject status\n            anarchy_subject_update:\n              metadata:\n                labels:\n                  state: started\n              status:\n                state: started\n          # Subsequent actions are scheduled to run later with the `after` parameter.\n          - name: Schedule stop\n            anarchy_schedule_action:\n              action: stop\n              after: 8h\n          - name: Schedule destroy\n            anarchy_schedule_action:\n              action: destroy\n              after: 6d\n\n    stop:\n      tasks:\n      - name: Call API for stop\n        uri:\n          url: https://{{ ansible_tower_hostname }}/api/v2/job_templates/job-runner/launch/\n          url_username: \"{{ api_creds.user }}\"\n          url_password: \"{{ api_creds.password }}\"\n          validate_certs: false\n          method: POST\n          return_content: true\n          body_format: json\n          body:\n            extra_vars:\n              job_vars: \u003e-\n                {{ anarchy_subject.vars.job_vars | default({})\n                 | combine(anarchy_governor.vars.job_vars, recursive=True)\n                 | combine({\n                     'ACTION': 'stop',\n                     '__meta__': {\n                       'deployer': {'entry_point': 'ansible/lifecycle.yml'},\n                       'tower': {'action': 'stop'}\n                     }\n                   }, recursive=True)\n                }}\n        ignore_errors: true\n\n      callbackHandlers:\n        started:\n          tasks:\n          - name: Set state stopping in subject status\n            anarchy_subject_update:\n              spec:\n                desiredState: stopped\n              metadata:\n                labels:\n                  state: stopping\n              status:\n                state: stopping\n        complete:\n          tasks:\n          - name: Set state stopped in subject status\n            anarchy_subject_update:\n              metadata:\n                labels:\n                  state: stopped\n              status:\n                state: stopped\n\n    start:\n      tasks:\n      - name: Call API\n        uri:\n          url: https://{{ ansible_tower_hostname }}/api/v2/job_templates/job-runner/launch/\n          url_username: \"{{ api_creds.user }}\"\n          url_password: \"{{ api_creds.password }}\"\n          validate_certs: false\n          method: POST\n          return_content: true\n          body_format: json\n          body:\n            extra_vars:\n              job_vars: \u003e-\n                {{ anarchy_subject.vars.job_vars | default({})\n                 | combine(anarchy_governor.vars.job_vars, recursive=True)\n                 | combine({\n                     'ACTION': 'start',\n                     '__meta__': {\n                       'deployer': {'entry_point': 'ansible/lifecycle.yml'},\n                       'tower': {'action': 'start'}\n                     }\n                   }, recursive=True)\n                }}\n        ignore_errors: true\n\n      callbackHandlers:\n        started:\n          tasks:\n          - name: Set state starting in subject status\n            anarchy_subject_update:\n              metadata:\n                labels:\n                  state: starting\n              status:\n                state: starting\n        complete:\n          tasks:\n          - name: Set state started in subject status\n            anarchy_subject_update:\n              metadata:\n                labels:\n                  state: started\n              status:\n                state: started\n          - name: Schedule stop\n            anarchy_schedule_action:\n              action: stop\n              after: 8h\n\n    destroy:\n      tasks:\n      - name: Call API for destroy\n        uri:\n          url: https://{{ babylon_tower_hostname }}/api/v2/job_templates/job-runner/launch/\n          url_username: \"{{ api_creds.user }}\"\n          url_password: \"{{ api_creds.password }}\"\n          validate_certs: false\n          method: POST\n          return_content: true\n          body_format: json\n          body:\n            extra_vars:\n              job_vars: \u003e-\n                {{ anarchy_subject.vars.job_vars | default({})\n                 | combine(anarchy_governor.vars.job_vars, recursive=True)\n                 | combine({\n                     'ACTION': 'destroy',\n                     '__meta__': {\n                       'deployer': {'entry_point': 'ansible/destroy.yml'},\n                       'tower': {'action': 'destroy'}\n                     }\n                   }, recursive=True)\n                }}\n        ignore_errors: true\n\n      callbackHandlers:\n        complete:\n          tasks:\n          - name: Delete anarchy subject\n            anarchy_subject_delete:\n              remove_finalizers: true\n----\n\n== Testing\n\n=== Examples\n\nExamples are found in the examples folder.\n\n== Configuration\n\nEnvironment valiable to specify how long subjects should remain cached when active:\n`ANARCHY_SUBJECT_CACHE_AGE_LIMIT` default 600\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frhpds%2Fanarchy","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frhpds%2Fanarchy","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frhpds%2Fanarchy/lists"}