Python tool for exporting/importing InterSystems API Manager configurations
π οΈ Managing InterSystems InterSystems API Manager (IAM = Kong Gateway) configurations in CI/CD
π Context: InterSystems IAM configurations
As part of integrating InterSystems IRIS into a secure and controlled environment, InterSystems IAM relies on Kong Gateway to manage exposed APIs.
Kong acts as a modern API Gateway, capable of handling authentication, security, traffic management, plugins, and more.
However, maintaining consistent Kong configurations (routes, services, plugins, etc.) across different environments (development, testing, production) is a major challenge. This is where tools like deck and this Python script become highly valuable.
βοΈ Overview of kong_config_tool.py
This tool allows you to:
- Export the current configuration of a Kong Gateway into a versionable YAML file.
- Import a YAML configuration into a Kong Gateway (via
deck sync). - Automate full logging (logs, stdout/stderr) for accurate tracking.
- Easily integrate into a CI/CD pipeline.
π― Goals and Benefits
π Consistent Synchronization Across Environments
The tool simplifies propagating Kong configuration between environments. By exporting from dev and importing into staging or prod, you ensure functional parity.
π Traceability and Audits via Logs
With the --log option, all operations (including internal deck commands) are logged:
- Who executed what
- What configuration was applied
- What was Kongβs response (number of resources created, modified, etc.)
π§ͺ CI/CD Pipeline Integration
In GitLab CI, GitHub Actions, or Jenkins:
- The export step can be triggered automatically after API changes.
- The import step can deploy the Kong config on every merge or release.
- The generated YAML files can be version-controlled in Git.
π§° Example GitLab Pipeline
stages:
- export
- deploy
export_kong:
stage: export
script:
- python3 kong_config_tool.py --export --log
artifacts:
paths:
- kong.yaml
- kong_config_tool.log
deploy_kong:
stage: deploy
script:
- python3 kong_config_tool.py --import --log
π‘οΈ Security and Reproducibility
Since InterSystems IAM is often used in sensitive environments (healthcare, finance...), itβs essential to:
- Avoid manual errors using
deck sync - Ensure each deployment applies the exact same configuration
- Maintain a clear audit trail via
.logfiles
π‘ Tool Highlights
| Feature | Description |
|---|---|
--export |
Saves the current config to a file like kong-<timestamp>.yaml |
--import |
Applies the contents of kong.yaml to the Gateway |
--log |
Enables full logging (stdout, stderr, logs) |
| Automatic Symlink | kong.yaml is always a symlink to the latest exported version |
| Easy Integration | No heavy dependencies β relies on standard Python and deck |
π¦ Conclusion
The kong_config_tool.py script is a key component for industrializing Kong configuration management in the context of InterSystems IAM. It enables:
- Better configuration control
- Enhanced traceability
- Smooth integration into CI/CD pipelines
- Compliance with security requirements
π Potential Future Enhancements
- Native GitOps integration (ArgoCD, FluxCD)
- Configuration validation with
deck diff - Error notifications (Slack, Teams)
𧬠Python Code Overview
The kong_config_tool.py script is a Python CLI tool designed to automate configuration exports and imports for KongGateway using deck, while ensuring robust logging.
π General Structure
#!/usr/bin/env python3
import argparse
import subprocess
from datetime import datetime
from pathlib import Path
import sys
import logging
- Uses only standard Python modules.
argparse: to handle command-line options.subprocess: to rundeckcommands.logging: for structured output (console + file).
π§± Logger Initialization
logger = logging.getLogger("kong_config_tool")
- Initializes a named logger, configurable based on whether a log file is requested.
π setup_logging(log_file=None)
This function:
- Creates handlers for both console and/or file.
- Redirects
sys.stdoutandsys.stderrto the log file if--logis provided.
π This captures everything: Python logs, print(), errors, and also output from deck.
π€ export_kong_config()
deck_dir = Path.cwd()
output_file = deck_dir / f"kong-{timestamp}.yaml"
- Executes
deck gateway dump -o ...to export the current configuration. - Captures
stdoutandstderrand sends them tologger.debug(...). - Creates or updates a
kong.yamlsymlink pointing to the exported file β simplifying future imports. - Logs and exits on failure.
π₯ import_kong_config()
- Checks for the presence of the
kong.yamlfile (symlink or actual file). - Runs
deck gateway sync kong.yaml. - Captures and logs full output.
- Handles errors via
CalledProcessError.
π This logic mirrors the export process.
π main()
The main entry point that:
- Handles
--export,--import, and--logarguments. - Calls the appropriate functions.
Example usage:
python kong_config_tool.py --export --log
python kong_config_tool.py --import --log
π‘ If --log is omitted, output goes to console only.
π§ͺ Typical CI/CD Execution
Export
python kong_config_tool.py --export --log
Results:
kong-2025-07-18_12-34-56.yaml(versionable content)kong.yaml(useful symlink for import)kong_config_tool.log(audit log)
Import
python kong_config_tool.py --import --log
Results:
- Applies the configuration to a new gateway (staging, prod, etc.)
kong_config_tool.logto prove what was done
β Code Summary Table
| Feature | Implementation |
|---|---|
| Intuitive CLI Interface | argparse with help descriptions |
| Clean Export | deck gateway dump + timestamp |
| Controlled Import | deck gateway sync kong.yaml |
| Full Logging | logging + stdout/stderr redirection |
| Resilience | Error handling via try/except |
| CI/CD Ready | Simple interface, no external dependencies |
Let me know if you'd like the English version of the actual code too!
kong_config_tool.py
#!/usr/bin/env python3import argparse
import subprocess
from datetime import datetime
from pathlib import Path
import sys
import logging
logger = logging.getLogger("kong_config_tool")
defsetup_logging(log_file=None):
logger.setLevel(logging.DEBUG)
formatter = logging.Formatter("[%(asctime)s] %(levelname)s: %(message)s", "%Y-%m-%d %H:%M:%S")
handlers = []
# Console handler
console_handler = logging.StreamHandler()
console_handler.setFormatter(formatter)
handlers.append(console_handler)
if log_file:
file_handler = logging.FileHandler(log_file)
file_handler.setFormatter(formatter)
handlers.append(file_handler)
# Redirect all stdout and stderr to the log file
log_file_handle = open(log_file, "a")
sys.stdout = log_file_handle
sys.stderr = log_file_handle
for handler in handlers:
logger.addHandler(handler)
defexport_kong_config():
deck_dir = Path.cwd()
current_date = datetime.now().strftime("%Y-%m-%d_%H-%M-%S")
output_file = deck_dir / f"kong-{current_date}.yaml"try:
logger.info(f"Exporting Kong config to: {output_file}")
result = subprocess.run(
["deck", "gateway", "dump", "-o", str(output_file)],
check=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True
)
# Log and print deck output
logger.debug(result.stdout)
logger.debug(result.stderr)
print(result.stdout)
print(result.stderr)
symlink_path = deck_dir / "kong.yaml"if symlink_path.exists() or symlink_path.is_symlink():
symlink_path.unlink()
symlink_path.symlink_to(output_file.name)
logger.info(f"Symlink created/updated: {symlink_path} -> {output_file.name}")
except subprocess.CalledProcessError as e:
logger.error(f"Export failed: {e}")
logger.error(e.stderr)
print(e.stderr)
sys.exit(1)
defimport_kong_config():
deck_file = Path.cwd() / "kong.yaml"ifnot deck_file.exists():
logger.error(f"Configuration file {deck_file} not found.")
sys.exit(1)
try:
logger.info("Syncing kong.yaml to gateway...")
result = subprocess.run(
["deck", "gateway", "sync", str(deck_file)],
check=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True
)
# Log and print deck output
logger.debug(result.stdout)
logger.debug(result.stderr)
# print(result.stdout)# print(result.stderr)
logger.info("Sync completed successfully.")
except subprocess.CalledProcessError as e:
logger.error(f"Sync failed: {e}")
logger.error(e.stderr)
print(e.stderr)
sys.exit(1)
defmain():
parser = argparse.ArgumentParser(
description=(
"Tool to export or import Kong Gateway configuration using deck.\n\n""Exactly one of the options --export or --import is required.\n\n""Examples:\n"" python kong_config_tool.py --export --log\n"" python kong_config_tool.py --import --log\n\n""For help, run:\n"" python kong_config_tool.py --help"
),
formatter_class=argparse.RawTextHelpFormatter
)
group = parser.add_mutually_exclusive_group(required=True)
group.add_argument("-e", "--export", dest="export_config", action="store_true",
help="Export Kong configuration to a timestamped YAML file and create/update kong.yaml symlink.")
group.add_argument("-i", "--import", dest="import_config", action="store_true",
help="Import (sync) Kong configuration from kong.yaml into Kong Gateway.")
parser.add_argument(
"--log",
dest="log_file",
nargs="?",
const="kong_config_tool.log",
help="Enable logging to a file. Use default 'kong_config_tool.log' if no path is given."
)
args = parser.parse_args()
setup_logging(args.log_file)
if args.export_config:
export_kong_config()
elif args.import_config:
import_kong_config()
if __name__ == "__main__":
main()