{"id":15494865,"url":"https://github.com/simonkowallik/tmconfpy","last_synced_at":"2025-04-22T20:25:42.799Z","repository":{"id":247221178,"uuid":"825309561","full_name":"simonkowallik/tmconfpy","owner":"simonkowallik","description":"serialize F5 config (bigip.conf) to JSON or python dict","archived":false,"fork":false,"pushed_at":"2024-11-29T08:34:51.000Z","size":14181,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-04-18T20:22:55.243Z","etag":null,"topics":["bigip","config","f5","f5-bigip","json","parser","serialization"],"latest_commit_sha":null,"homepage":"https://simonkowallik.github.io/tmconfpy/","language":"Python","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/simonkowallik.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,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-07-07T12:24:10.000Z","updated_at":"2024-12-06T23:34:54.000Z","dependencies_parsed_at":"2024-07-23T20:30:35.464Z","dependency_job_id":"7a464dd3-f280-4806-bc44-9d35b31f00cc","html_url":"https://github.com/simonkowallik/tmconfpy","commit_stats":null,"previous_names":["simonkowallik/tmconfpy"],"tags_count":3,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/simonkowallik%2Ftmconfpy","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/simonkowallik%2Ftmconfpy/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/simonkowallik%2Ftmconfpy/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/simonkowallik%2Ftmconfpy/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/simonkowallik","download_url":"https://codeload.github.com/simonkowallik/tmconfpy/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250317327,"owners_count":21410725,"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":["bigip","config","f5","f5-bigip","json","parser","serialization"],"created_at":"2024-10-02T08:15:27.609Z","updated_at":"2025-04-22T20:25:42.771Z","avatar_url":"https://github.com/simonkowallik.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# tmconfpy\n\n\u003cp align=\"center\" style=\"text-decoration: none;\"\u003e\n\u003ca href=\"https://github.com/simonkowallik/tmconfpy/actions/workflows/ci-pipeline.yaml\" target=\"_blank\"\u003e\n    \u003cimg src=\"https://github.com/simonkowallik/tmconfpy/actions/workflows/ci-pipeline.yaml/badge.svg\" alt=\"ci-pipeline\"\u003e\n\u003c/a\u003e\n\u003ca href=\"https://codeclimate.com/github/simonkowallik/tmconfpy/test_coverage\" target=\"_blank\"\u003e\n    \u003cimg src=\"https://api.codeclimate.com/v1/badges/3f404be294dceae16361/test_coverage\" alt=\"test coverage\"\u003e\n\u003c/a\u003e\n\u003ca href=\"https://hub.docker.com/r/simonkowallik/tmconfpy\" target=\"_blank\"\u003e\n    \u003cimg src=\"https://img.shields.io/docker/image-size/simonkowallik/tmconfpy\" alt=\"container image size\"\u003e\n\u003c/a\u003e\n\u003ca href=\"https://pypi.org/project/tmconfpy\" target=\"_blank\" target=\"_blank\"\u003e\n    \u003cimg src=\"https://img.shields.io/pypi/v/tmconfpy?color=%2334D058\u0026label=pypi%20package\" alt=\"Package version\"\u003e\n\u003c/a\u003e\n\u003ca href=\"https://github.com/simonkowallik/tmconfpy/releases\" target=\"_blank\"\u003e\n    \u003cimg src=\"https://img.shields.io/github/v/release/simonkowallik/tmconfpy\" alt=\"releases\"\u003e\n\u003c/a\u003e\n\u003c/p\u003e\n\n---\n\n**tmconfpy** provides a simple parser (`tmconfpy` command) to serialize a tmconf file (eg. `/config/bigip.conf`) to JSON (or python `dict`). The produced JSON is printed to `STDOUT` or a specified output (`--output`) file. It is also usable as a python module for easy consumption in your own projects.\n\nThis project aims to be a minimalistic dependency free tool. It is based on [tmconfjs](https://github.com/simonkowallik/tmconfjs), it's parsing implementation leans heavily on the community project [F5 BIG-IP Automation Config Converter (BIG-IP ACC)](https://github.com/f5devcentral/f5-automation-config-converter/).\n\nThe TMOS configuration parser [f5-corkscrew](https://github.com/f5devcentral/f5-corkscrew) is a more sophisticated alternative with advanced functionality and active development.\n\nHave a look at the [example directory](./example/), for interactive use of `tmconfpy` with jupyter notebooks :notebook: or for implementing policy-as-code / audit configuration for compliance :cop:.\n\nFor more details about the relevant configuration files, [data formats](https://simonkowallik.github.io/tmconfpy/data-formats.html), tmconfpy and its ansible collection please have a look at the [documentation](https://simonkowallik.github.io/tmconfpy/).\n\n## Using tmconfpy with ansible\n\ntmconfpy is available as an ansible module, please see [ansible_collections/simonkowallik/tmconfpy/README.md](https://github.com/simonkowallik/tmconfpy/tree/main/ansible_collections/simonkowallik/tmconfpy) or the [Ansible documentation](https://simonkowallik.github.io/tmconfpy/ansible.html).\n\n## Using tmconfpy for policy-as-code / configuration auditing\n\nHaving a structured and well supported configuration data is an important step towards auditing configuration and implementing policy-as-code. Have a look at [the documentation](https://simonkowallik.github.io/tmconfpy/config-audit.html) for examples on auditing BIG-IP configuration.\n\n## Documentation by example\n\n### Installation\n\n```shell\npip3 install tmconfpy\n```\n\n### Command line usage\n\nWhen installed globally, `tmconfpy` can be invoked as a command:\n\n```shell\ntmconfpy example/test.tmconf 2\u003e/dev/null \\\n    | jq '.\"ltm profile client-ssl clientssl-secure\"'\n```\n\n```json\n{\n  \"app-service\": \"none\",\n  \"cert\": \"/Common/default.crt\",\n  \"cert-key-chain\": {\n    \"default\": {\n      \"cert\": \"/Common/default.crt\",\n      \"key\": \"/Common/default.key\"\n    }\n  },\n  \"chain\": \"none\",\n  \"ciphers\": \"ecdhe:rsa:!sslv3:!rc4:!exp:!des\",\n  \"defaults-from\": \"/Common/clientssl\",\n  \"inherit-certkeychain\": \"true\",\n  \"key\": \"/Common/default.key\",\n  \"options\": [\n    \"no-ssl\",\n    \"no-tlsv1.3\"\n  ],\n  \"passphrase\": \"none\",\n  \"renegotiation\": \"disabled\"\n}\n```\n\nErrors, warnings or any debug information is written to `STDERR`:\n\n```shell\ntmconfpy example/test.tmconf \\\n    \u003e/dev/null 2\u003e example/test.tmconf.log\n\ncat example/test.tmconf.log\n```\n\n```shell\n2024-06-30T18:39:16Z - WARNING - tmconfpy.parser - UNRECOGNIZED LINE for object 'sys software update': '     auto-check enabled'\n2024-06-30T18:39:16Z - WARNING - tmconfpy.parser - UNRECOGNIZED LINE for object 'sys software update': '     auto-phonehome enabled'\n2024-06-30T18:39:16Z - WARNING - tmconfpy.parser - UNRECOGNIZED LINE for object 'fatal-grace-time': '\ttime 500'\n2024-06-30T18:39:16Z - WARNING - tmconfpy.parser - UNRECOGNIZED LINE for object 'fatal-grace-time': '\tenabled yes'\n```\n\nInput is also accepted from `STDIN`:\n\n```shell\ncat example/imap.tmconf | tmconfpy\n```\n\n```json\n{\n    \"ltm profile imap imap\": {\n        \"activation-mode\": \"require\"\n    }\n}\n```\n\nThe `\u003cfile_path\u003e` argument is preferred over `STDIN` however:\n\n```shell\ncat example/imap.tmconf | tmconfpy example/pop3.tmconf\n```\n\n```json\n{\n    \"ltm profile pop3 pop3\": {\n        \"activation-mode\": \"require\"\n    }\n}\n```\n\nThe output can be written to a specified file using `--output` or `-o` when `STDOUT` is not desired:\n\n```shell\ntmconfpy --output example/pop3.tmconf.json example/pop3.tmconf\ncat example/pop3.tmconf.json\n```\n\n```json\n{\n    \"ltm profile pop3 pop3\": {\n        \"activation-mode\": \"require\"\n    }\n}\n```\n\ntmconfpy supports multiple output formats of the parsed tmconf data, which can be specified via `--format`.\n\n```shell\n(cat example/imap.tmconf; echo; cat example/pop3.tmconf) | \\\n  tmconfpy --format jsonl\n```\n\n```json\n{\"path\": \"ltm profile imap\", \"name\": \"imap\", \"object\": {\"activation-mode\": \"require\"}}\n{\"path\": \"ltm profile pop3\", \"name\": \"pop3\", \"object\": {\"activation-mode\": \"require\"}}\n```\n\n```shell\n(cat example/imap.tmconf; echo; cat example/pop3.tmconf) | \\\n  tmconfpy --format tabular\n```\n\n```json\n[\n  [\"ltm profile imap\", \"imap\", {\"activation-mode\": \"require\"}],\n  [\"ltm profile pop3\", \"pop3\", {\"activation-mode\": \"require\"}]\n]\n```\n\n```shell\n(cat example/imap.tmconf; echo; cat example/pop3.tmconf) | \\\n  tmconfpy --format tabular_kv\n```\n\n```json\n[\n  {\"path\":\"ltm profile imap\",\"name\":\"imap\",\"object\":{\"activation-mode\":\"require\"}},\n  {\"path\":\"ltm profile pop3\",\"name\":\"pop3\",\"object\":{\"activation-mode\":\"require\"}}\n]\n```\n\nSorting the output is also supported since version 1.1.0. This is helpful when comparing data. tmconfpy uses python `sorted()` and will sort all data within the tmconf (all dicts, and lists).\n\n```shell\ncat \u003c\u003cEOF | tmconfpy --sort | jq \nltm profile profile-type zProfile { }\nltm profile profile-type MyProfile {\n    b {\n        Z { 3 2 A 1 0 }\n        a 1\n        A 2\n    }\n    aaa 0\n    AA { a c b }\n}\nEOF\n```\n\n```json\n{\n  \"ltm profile profile-type MyProfile\": {\n    \"AA\": [ \"a\", \"b\", \"c\" ],\n    \"aaa\": \"0\",\n    \"b\": {\n      \"A\": \"2\",\n      \"Z\": [ \"0\", \"1\", \"2\", \"3\", \"A\" ],\n      \"a\": \"1\"\n    }\n  },\n  \"ltm profile profile-type zProfile\": {}\n}\n```\n\n### Use as python module\n\n```python\n\u003e\u003e\u003e from tmconfpy import Parser\n\u003e\u003e\u003e parsed = Parser('example/imap.tmconf', is_filepath=True)\n\u003e\u003e\u003e parsed.dict\n{'ltm profile imap imap': {'activation-mode': 'require'}}\n\u003e\u003e\u003e tmconf = r\"\"\"\n... ltm profile pop3 pop3 {\n...     activation-mode require\n... }\n... ltm profile imap imap {\n...     activation-mode require\n... }\n... \"\"\"\n\u003e\u003e\u003e parsed = Parser(tmconf)\n\u003e\u003e\u003e parsed.json\n'{\"ltm profile pop3 pop3\": {\"activation-mode\": \"require\"}, \"ltm profile imap imap\": {\"activation-mode\": \"require\"}}'\n\u003e\u003e\u003e parsed.tabular\n[tabularTmconf(path='ltm profile pop3', name='pop3', object={'activation-mode': 'require'}), tabularTmconf(path='ltm profile imap', name='imap', object={'activation-mode': 'require'})]\n\u003e\u003e\u003e parsed.tabular_kv\n[{'path': 'ltm profile pop3',\n  'name': 'pop3',\n  'object': {'activation-mode': 'require'}},\n {'path': 'ltm profile imap',\n  'name': 'imap',\n  'object': {'activation-mode': 'require'}}]\n\u003e\u003e\u003e parsed.tabular_json\n'[[\"ltm profile pop3\", \"pop3\", {\"activation-mode\": \"require\"}], [\"ltm profile imap\", \"imap\", {\"activation-mode\": \"require\"}]]'\n\u003e\u003e\u003e parsed.jsonl\n'{\"path\": \"ltm profile pop3\", \"name\": \"pop3\", \"object\": {\"activation-mode\": \"require\"}}\\n{\"path\": \"ltm profile imap\", \"name\": \"imap\", \"object\": {\"activation-mode\": \"require\"}}'\n```\n\n### Using the (optional) apiserver / container\n\nRun the container, the API listens on port 8000 (http).\n\n```shell\ndocker run --rm -p 8000:8000 simonkowallik/tmconfpy\n```\n\nThe container is also available on [ghcr.io](https://github.com/simonkowallik/tmconfpy/pkgs/container/tmconfpy) as an alternative to docker hub.\n\n```shell\ndocker run --rm -p 8000:8000 ghcr.io/simonkowallik/tmconfpy\n```\n\nThe apiserver can be reached at [http://localhost:8000/](http://localhost:8000/) and offers two endpoints which are described by the OpenAPI specification.\n\nAPI documentation can be reached at [/](http://localhost:8000/) and [/redoc](http://localhost:8000/redoc) for interactive use.\n\nParsing a single file by using POST, note `--data-binary` is required to avoid interpretation of the file content:\n\n```shell\ncurl -X POST -s http://localhost:8000/parser/ \\\n  --data-binary @example/imap.tmconf\n```\n\n```json\n{\"ltm profile imap imap\":{\"activation-mode\":\"require\"}}\n```\n\nParsing multiple files via multipart form:\n\n```shell\ncurl -X POST -s http://localhost:8000/fileparser/ \\\n  -F 'filename=@example/imap.tmconf' \\\n  -F 'filename=@example/pop3.tmconf'\n```\n\n```json\n[\n  {\"filename\":\"imap.tmconf\",\n   \"output\":{\"ltm profile imap imap\":{\"activation-mode\":\"require\"}}\n  },\n  {\"filename\":\"pop3.tmconf\",\n   \"output\":{\"ltm profile pop3 pop3\":{\"activation-mode\":\"require\"}}\n  }\n]\n```\n\n#### JSONL and tabular data\n\nThe `/parser/` api-endpoint also supports returning the parsed tmconf as JSONL or tabular data using the query parameter `?response_format=\u003cformat\u003e`.\n\n```shell\n(cat example/imap.tmconf; echo; cat example/pop3.tmconf) | \\\n  curl -X POST -s http://localhost:8000/parser/?response_format=jsonl \\\n  --data-binary @-\n```\n\n```json\n{\"path\": \"ltm profile imap\", \"name\": \"imap\", \"object\": {\"activation-mode\": \"require\"}}\n{\"path\": \"ltm profile pop3\", \"name\": \"pop3\", \"object\": {\"activation-mode\": \"require\"}}\n```\n\n```shell\n(cat example/imap.tmconf; echo; cat example/pop3.tmconf) | \\\n  curl -X POST -s http://localhost:8000/parser/?response_format=tabular \\\n  --data-binary @-\n```\n\n```json\n[\n  [\"ltm profile imap\",\"imap\",{\"activation-mode\":\"require\"}],\n  [\"ltm profile pop3\",\"pop3\",{\"activation-mode\":\"require\"}]\n]\n```\n\n#### Using the container as a command line tool\n\nUse the `--entrypoint` argument with `tmconfpy` to invoke the tmconfpy tool instead of the apiserver (which is the default). Don't forget to pass `--interactive | -i` to the container.\n\n```shell\ncat example/imap.tmconf | docker run --rm --interactive --entrypoint tmconfpy simonkowallik/tmconfpy\n```\n\n```json\n{\n    \"ltm profile imap imap\": {\n        \"activation-mode\": \"require\"\n    }\n}\n```\n\n**Note** that you can't use `--output | -o` to write the output to a file using the above method unless you mount a volume into the container.\n\n## Disclaimer, Support, License\n\nPlease read and understand the [LICENSE](https://github.com/simonkowallik/tmconfpy/blob/main/LICENSE) first.\n\n\u003e [!NOTE]\n\u003e There is no support on this project.\n\u003e It is maintained on best effort basis without any warranties.\n\u003e For any software or components used in this project, read their own LICENSE and SUPPORT policies.\n\u003e If you decide to use this project, you are solely responsible.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsimonkowallik%2Ftmconfpy","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsimonkowallik%2Ftmconfpy","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsimonkowallik%2Ftmconfpy/lists"}