Written by

Sales Engineer at InterSystems
Article Sylvain Guilbaud Β· Jul 18 8m read

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 .log files

πŸ’‘ 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 run deck commands.
  • 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.stdout and sys.stderr to the log file if --log is 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 stdout and stderr and sends them to logger.debug(...).
  • Creates or updates a kong.yaml symlink pointing to the exported file β€” simplifying future imports.
  • Logs and exits on failure.

πŸ“₯ import_kong_config()

  • Checks for the presence of the kong.yaml file (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 --log arguments.
  • 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.log to 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()