{"id":43052809,"url":"https://github.com/cloud-native-toolkit/atkmod","last_synced_at":"2026-01-31T10:38:22.420Z","repository":{"id":64646147,"uuid":"576757587","full_name":"cloud-native-toolkit/atkmod","owner":"cloud-native-toolkit","description":"libraries for itzcli","archived":false,"fork":false,"pushed_at":"2023-02-13T22:56:17.000Z","size":99,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":6,"default_branch":"main","last_synced_at":"2025-06-22T03:02:55.106Z","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/cloud-native-toolkit.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":null,"security":null,"support":null}},"created_at":"2022-12-10T22:02:13.000Z","updated_at":"2022-12-10T23:14:51.000Z","dependencies_parsed_at":"2023-02-19T12:00:49.852Z","dependency_job_id":null,"html_url":"https://github.com/cloud-native-toolkit/atkmod","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/cloud-native-toolkit/atkmod","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cloud-native-toolkit%2Fatkmod","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cloud-native-toolkit%2Fatkmod/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cloud-native-toolkit%2Fatkmod/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cloud-native-toolkit%2Fatkmod/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/cloud-native-toolkit","download_url":"https://codeload.github.com/cloud-native-toolkit/atkmod/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cloud-native-toolkit%2Fatkmod/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28938845,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-31T10:18:23.202Z","status":"ssl_error","status_checked_at":"2026-01-31T10:18:22.693Z","response_time":128,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: 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":"2026-01-31T10:38:22.230Z","updated_at":"2026-01-31T10:38:22.412Z","avatar_url":"https://github.com/cloud-native-toolkit.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# atkmod: A go library API for module manifests\n\n![Go build](https://github.com/cloud-native-toolkit/atkmod/actions/workflows/go.yml/badge.svg)\n\n\u003e Note: this proof of concept is not dead, but as of Sept 21, 2022 is shelved \n\u003e while some other work. That being said, the module is in use by the `itz` \n\u003e [CLI](https://github.com/cloud-native-toolkit/itzli), which is also a proof \n\u003e of concept. This module includes some code for dealing with the Podman/Docker\n\u003e command line and output that is unit tested, and it was better to re-use this \n\u003e than copy and paste it or include it in the CLI outside this module.\n\nThe purpose of this project was originally to demonstrate a proof of concept for\ndefining a \"module file\" that would be basically a descriptor used in a module's\nrepository to provide a mechanism for dealing with the module using a\nPodman-based, container plugin architecture.\n\nIn other words, this was intended to prove an approach to answer the questions:\n\n* *What if I didn't need to care how I got the parameters, or how I even\n  deployed the module?*\n* *What if I left that up to plugins (in the form of containers that emit\n  documented output)?*\n\n## Overview\n\nTo accomplish these goals, this project uses a container-based, plugin-style\narchitecture in which a manifest file defines a deployment lifecycle (see\n[\"Lifecycle Overview\"](#lifeycle-overview) for details) for the given module.\nThis was inspired by build solutions, such as [Drone CI](https://docs.drone.io/)\nto a great extent, especially the container-based execution steps.\n\nThis project includes an \"executor\" that simply stages of the lifecycle,\nusing state to collect error conditions. For each plugin, the container mounts a\nlocal folder as a volume in the container and then executes the entrypoint to\nact upon the files in the volume. For example, during the *deploy* stage of the\nlifecycle, the itz-plugins/terrform-base plugin will use Terraform to apply the\n`main.tf` file and print the command's standard out to the plugin's standard out\nto be captured and used by whatever consumes this library.\n\nOther plugins should print information to standard out for their stage in the\nlifecycle, such as the list-variables and get-state. See more in the\ndocumentation for the lifecycles.\n\n### What this is not\n\nNotice, however, that other than the required input and output variables for the\nmodule that other dependency information is left out. That is by design. For\nthe sake of [separation of concerns](https://en.wikipedia.org/wiki/Separation_of_concerns),\na module's dependencies and how a particular module should be installed and\ndealt with are two separate concerns. It's the opinionated stance of this library\nthat it is only concerned with managing a module through its lifecycle via\nplugins. Dependency management--including downloading and resolving\ndependencies--are the responsibility of some other component.\n\n## Lifeycle Overview\n\nThe *lifecycle* is a set of three stages for the deployment: *pre_deploy*,\n*deploy*, and *post_deploy*. These stages are intended to be called in order\nlisted, serially, with each stage completing successfully before continuing on to\nthe next stage. That means that, by default, an error in *pre_deploy* stage means\nthat the executor will not run the *deploy* and *post_deploy* stages.\n\nAdditionally, there are three *hooks* meta information about the lifecycle:\n*list*, *validate*, and *get_state*. These are called various times during the\nexecution of the lifecycle should output information to standard output in a\nspecific format and should also accept information via standard input in a\nspecific format. You can read more on the expected formats in the documentation\nfor the lifecycle hook. Because the hooks should get information about the\nmodule and the environment, they are covered first in this documentation.\n\n### Hook: get_state\n\nThe *get_state* hook is called by the executor to get the current *state* of the\nmodule. For each module, that could mean something slightly different. For\nexample, for a module that configures basic networking that might mean returning\nthe IP addresses of the existing network. Therefore, aside from the `health`\nelement, the state returned as a response can be in any form returned in\nproperly-formatted JSON within the `data` element. As example is show here:\n\n```json\n{\n  \"health\": {\n    \"status\": \"DEPLOYED\",\n    \"lifecycle\": {\n      \"pre_deploy\": \"SUCCESS\",\n      \"deploy\": \"SUCCESS\",\n      \"post_deploy\": \"SUCCESS\"\n    }\n  },\n  \"data\": {}\n}\n```\n\nThis state is passed along to the lifecycle plugins as STDIN. They can use it or\nignore it--that's the flexibility of these plugins. The `data` element here\nshould contain various state data important to the module. For example, if the\nmodule is a base VPC network in AWS, this state data may include the VPC and\nsubnet IDs, IP addresses, etc.\n\nSince `health` is reserved, a `status` of \"DEPLOYED\" should mean the module has\nbeen successfully deployed. In the `lifecycle` elements, each name maps exactly\nto the name of the stage in the lifecycle. This is intended to provide the\ncapacity for retry or rollback logic, where a status of \"SUCCESS\" for the\n*deploy* stage of the lifecycle will be skipped by default. If the status were\nsomething else, the *deploy* stage may be retried, depending on the\nimplementation of the plugin.\n\n### Hook: list\n\nThe responsibility of the *list* hook is to provide information about the module\nto the executor; most importantly is the list of input variables expected by the\nexecutor.\n\nImplementations of this hook can vary from reading input files, such as .tfvars\nor tfinput files or source files.\n\n\u003e Note: Output information should be included in the *get_state* hook.\n\nListed here is an example of the output from list:\n\n```json\n{\n  \"specversion\": \"1.0\",\n  \"type\": \"com.ibm.techzone.itz.tf_hook_list.response\",\n  \"source\": \"https://github.ibm.com/skol/itz-deployer-plugins/tf-hook-list\",\n  \"subject\": \"fyre-vm\",\n  \"id\": \"7208f364-86af-4d18-8fcd-c1f5cd06cdb4\",\n  \"time\": \"2023-02-13T17:17:48.570677\",\n  \"datacontenttype\": \"application/json\",\n  \"data\": {\n    \"variables\": [\n      {\n        \"name\": \"TF_VAR_cloud_provider\",\n        \"default\": \"fyre\"\n      },\n      {\n        \"name\": \"TF_VAR_cloud_type\",\n        \"default\": \"private\"\n      },\n      {\n        \"name\": \"TF_VAR_fyre_api_key\",\n        \"default\": \"\"\n      },\n      {\n        \"name\": \"TF_VAR_fyre_root_password\",\n        \"default\": \"\"\n      },\n      {\n        \"name\": \"TF_VAR_fyre_username\",\n        \"default\": \"\"\n      }\n    ]\n  }\n}\n```\n\n### Hook: validate\n\nThe *validate* hook provides a means to validate state of the module before\nexecuting any of the lifecycle stages. The validate hook should take the\n`variables` input as STDIN and return a status like the following JSON:\n\n```json\n{\n  \"status\": \"OK\",\n  \"messages\": []\n}\n```\n\nShown here is an example of an error status that provides a meaningful error\nmessage to the caller:\n\n```json\n{\n  \"status\": \"ERROR\",\n  \"messages\": [\n    \"Variable 'TF_VAR_cluster_api' is invalid.\"\n  ]\n}\n```\n\nThe *validate* hook should be designed to validate single variables as\nwell as the entire variable set or more and should be idempotent. This is so\ncallers can call validate a single variable, such as in the case of an interactive\nprompt validating the input of a question before proceeding to the next, or\nvalidation of several variables at once in the case of a source or .env file\nthat contains many input variables.\n\n### Stage: pre_deploy\n\nThe *pre_deploy* stage is used to initialize the workspace (working volume) to\nthe state that it should be in prior to proceeding to the *deploy* stage.\nPlugin implementations for this stage could download any dependencies, run a\ncommand such as `tf plan`\n\nLike the rest of the plugins, errors should result in a non-zero exit status\nfrom the container execution as well as some error messages written to STDOUT.\nSee \"[Handling errors](#handling-errors)\" for more information about the\nerror message envelope.\n\n### Stage: deploy\n\nThe *deploy* stage is where the actual deployment of the module in the workspace\nis performed by the execution engine. In Terraform terms, this is where the\nTerraform plugin executes the `tf apply` command or the Ansible plugin executes\nthe `ansible-playbook` or the CloudFormation plugin executes the \n`aws cloudformation create-stack` command or `oc apply -f` for an OpenShift\napplication by default.\n\nRegardless of the implementation, the plugin should actually deploy the module,\nwhatever that means for the given module.\n\n### Stage: post_deploy\n\nThe *post_deploy* stage is where a plugin can perform cleanup, validation, \nwriting state, etc., of the module.\n\n## The module manifest file\n\nExamples of the module manifest file are best viewed in the *test/examples*\ndirectory, because those are the files that are run against unit tests and\ntherefore verified against actual code. But, for convenience, an example is\nshown here:\n\n```yaml\n# The apiVersion of the file. Supported values for the apiVersion are currently\n# only v1alpha1. Any other value will cause an error when the file is being \n# loaded. itzcli is the namespace.\napiVersion: itzcli/v1alpha1\n# \"InstallManifest\" is used for the type of file that is included in modules to \n# tell ITZ CLI how to install the module.\nkind: InstallManifest\n\n# Meta information about this project.\nmetadata:\n  # The namespace for the module. This can be any value right now.\n  namespace: IBMTechnologyZone\n  # The name of the module. This really should match the name that is displayed\n  # to users in software catalogs, etc.\n  name: MyModule\n  # Any arbitrary labels for the module. Reserved for future use.\n  labels:\n    \"label1\": value1\n\nspec:\n\n  # Hooks are not part of the lifecycle of the module but are called at various\n  # points during the lifecycle to validate state and lifecycle completeness.\n  hooks:\n    # Uses the container specified by \"image\" to get a list of the parameters\n    # for the project. This is either a custom container or command specified\n    # by the maintainer, or could be a \"plugin\" that is supported by the\n    # ITZ CLI.\n    list:\n      image: something/parameter-lister:latest\n      env:\n        - name: MY_PROJECT_NAME\n          value: my-base-project\n      volumeMounts:\n        - mountPath: /workspace\n          name: ${HOME}/.itz/cache\n\n    # Similar to list (above), but uses the container to validate the values\n    # for the parameters.\n    validate:\n      image: something/parameter-validator:latest\n\n    # Gets the current state of the project and returns a structure documented at\n    get_state:\n      image: something/get-stater:latest\n\n  lifecycle:\n\n    # Uses the container specified by image to run any pre-deployment tasks for\n    # the project. This could be, for example, generating files in the project\n    # based on metadata before actually starting the deployment step.\n    pre_deploy:\n      image: something/pre-deployer:latest\n\n    # Uses the container specified by image to run the deployment\n    deploy:\n      image: something/deployer:latest\n\n    # Uses the container specified by image to run post-deployment steps, such\n    # as clean-ups, notifications, etc.\n    post_deploy:\n      image: something/post-deployer:latest\n```\n\n## The included Podman/Docker API\n\nIn order to read the `img` tag in the module manifest and do something with it, capturing\nthe output, errors, etc. in an elegant fashion, I implemented a command builder using the\n[Builder Patter](https://en.wikipedia.org/wiki/Builder_pattern) and also incorporated the\nnotion of contexts, which is similar to a [Pipeline](https://en.wikipedia.org/wiki/Component-based_software_engineering)\nin that several commands can be strung together (for example, to execute the entire lifecycle\nof a module) and be contextually aware.\n\nAn example of using the `PodmanCliCommandBuilder` is shown here:\n\n```go\nbuilder := atk.NewPodmanCliCommandBuilder(nil)\n\nactual, err := builder.WithVolume(\"/home/myuser/workdir\").\nWithImage(\"localhost/myimage\").\nWithEnvvar(\"MYVAR\", \"thisismyvalue\").\nBuild()\n\nassert.Nil(t, err)\nassert.Equal(t, \"/usr/local/bin/podman run --rm -v /home/myuser/workdir:/workspace -e MYVAR=thisismyvalue localhost/myimage\", actual)\n```\n\nMore examples of using the builder can be found in [podmanclibuilder_test.go](test/podmanclibuilder_test.go).\n\n## Developing your own plugin\n\nThere are few basic rules for the plugins:\n\n1. Make sure to check the plugin documentation to understand the required STDIN\nand/or STDOUT of the plugin.\n1. Make sure to use proper UNIX exit codes--use zero for success and non-zero \nfor failure or error conditions. For your own trouble-shooting, consider making\nyour non-zero exit codes mean something--that is, a code of 135 means something\ndifferent than a 140.\n1. Use STDOUT and STDERR properly. STDOUT is reserved for JSON output sent to\nexecutors, while STDERR is should be used for process debugging or logging\nmessages that are either displayed to a console or printed to a log file.\n\nFortunately, there (will be) a container that you can call in your CI/CD\npipeline to validate\n\n## Reference implementations\n\nReference implementations are in progress.\n\n## FAQ\n\n### Why not just use... \\[TravisCI, Drone, Jenkins, kubectl, Airflow, WorkflowXYX...\\]\n\nI looked, and looked pretty hard, and even evaluated some of the command line\nrunners such as that of AWS CodeBuild. Afterall, this is primarily a Day Zero\ninstaller--Day One operations should be handled by GitOps, DevOps, or DevSecOps\npipelines. For a while, even, I used a Jenkins container and tried to basically\nimplement this within Jenkins.\n\nHowever, it turned out that building a very lightweight, purpose-built executor\nthat deferred execution to container-based plugins was the best solution for\nboth speed of development, lowest impact on modules, backwards compatibility,\nand future-proofing. For example, any current Terraform project such as that\ncurrently deployed in TechZone should--for the most part--simply be able to use\nthe supported plugins and therefore require no additional code other than the\n`itz-manifest.yaml` file.\n\n### Why not just use settle on one specific tech (eg., Terraform) and use its built-in goodness?\n\nThis didn't seem like a realistic goal, long-term, and likely would drive some\nsub-optimal behavior. For example, Ansible is a great choice for deploying and\nmanaging configuration and infrastructure, so providing the ability to use\nTerraform or CloudFormation or Bicep for some infrastructure while providing\nAnsible or Helm or make for others is inline with both hybrid cloud and\nheterogeneous ecosystem approaches.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcloud-native-toolkit%2Fatkmod","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcloud-native-toolkit%2Fatkmod","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcloud-native-toolkit%2Fatkmod/lists"}