How to Build a GitOps Argo CD Sync Mock in Python

Simulate Argo CD-style GitOps deployment sync with Python dataclasses, random success rates, and force-sync retry logic.

Medium Python 3.9+ Aug 9, 2026 Production deployment patterns 13 views 0 copies

Python code

82 lines
Python 3.9+
import random
import time
from dataclasses import dataclass, field
from typing import List, Dict


@dataclass
class Application:
    name: str
    source_repo: str
    target_revision: str
    synced: bool = False
    health_status: str = "Healthy"
    history: List[Dict] = field(default_factory=list)

    def sync(self) -> None:
        """Simulate Argo CD sync operation."""
        print(f"Syncing {self.name}...")
        time.sleep(0.5)  # Simulate network/delay

        success = random.random() > 0.2  # 80% success rate
        self.synced = success

        if success:
            self.health_status = "Healthy"
            print(f"  ✓ {self.name} synced to {self.target_revision}")
        else:
            self.health_status = "Degraded"
            print(f"  ✗ {self.name} sync failed")

        self.history.append({
            "revision": self.target_revision,
            "success": success,
            "timestamp": time.strftime("%Y-%m-%d %H:%M:%S")
        })


def force_sync(apps: List[Application]) -> None:
    """Simulate Argo CD force sync (bypasses hooks)."""
    force_sync_apps = [app for app in apps if not app.synced]
    if not force_sync_apps:
        print("All applications are already in sync.")
        return

    print(f"Force syncing {len(force_sync_apps)} out-of-sync app(s):")
    for app in force_sync_apps:
        app.sync()
        if app.synced:
            print(f"  → {app.name} forced to healthy state")


def main() -> None:
    # Mock GitOps applications
    applications = [
        Application("payment-api", "https://github.com/company/payment-api.git", "v1.4.0"),
        Application("inventory-service", "https://github.com/company/inventory-service.git", "v2.1.0"),
        Application("auth-gateway", "https://github.com/company/auth-gateway.git", "v0.9.1"),
        Application("notification-worker", "https://github.com/company/notification-worker.git", "v1.0.2"),
    ]

    print("=== Argo CD Sync Mock ===")
    print(f"Initial status: {len([a for a in applications if a.synced])}/{len(applications)} synced\n")

    # Simulate sync process
    for app in applications:
        app.sync()
        print()

    print("=== Post-sync status ===")
    for app in applications:
        state = "✓" if app.synced else "✗"
        print(f"{state} {app.name:20} health={app.health_status:8} rev={app.target_revision}")

    # Check for failed syncs
    failed = [app for app in applications if not app.synced]
    if failed:
        print(f"\n{len(failed)} application(s) out of sync. Attempting force sync...")
        force_sync(failed)


if __name__ == "__main__":
    main()

Output

stdout
=== Argo CD Sync Mock ===
Initial status: 0/4 synced

Syncing payment-api...
  ✓ payment-api synced to v1.4.0

Syncing inventory-service...
  ✗ inventory-service sync failed

Syncing auth-gateway...
  ✓ auth-gateway synced to v0.9.1

Syncing notification-worker...
  ✓ notification-worker synced to v1.0.2

=== Post-sync status ===
✓ payment-api         health=Healthy  rev=v1.4.0
✗ inventory-service   health=Degraded rev=v2.1.0
✓ auth-gateway        health=Healthy  rev=v0.9.1
✓ notification-worker health=Healthy  rev=v1.0.2

1 application(s) out of sync. Attempting force sync...
Force syncing 1 out-of-sync app(s):
Syncing inventory-service...
  ✓ inventory-service synced to v2.1.0
  → inventory-service forced to healthy state

How it works

The Application dataclass models the core GitOps state — name, source repo, revision, sync status, and health. The sync() method simulates a deployment with an 80% success rate, appending to history for audit trails. force_sync() implements the retry pattern you'd see in Argo CD's force sync, bypassing hooks for out-of-sync apps. This mock lets you test deployment orchestration logic without touching real infrastructure.

Common mistakes

  • Not setting `field(default_factory=list)` for mutable list attributes in dataclasses
  • Using `random.random() > 0.2` creates flaky tests — seed `random.seed()` for deterministic results
  • Forgetting to clear `history` when forcing a re-sync, causing duplicate audit entries

Variations

  1. Use `enum` for health status instead of strings to catch typos
  2. Add a `rollback()` method that reverts to the previous revision from `history`

Real-world use cases

  • Testing CI/CD pipeline orchestration logic locally without spinning up a real Argo CD cluster.
  • Simulating multi-service deployment rollouts to validate rollback and retry workflows.
  • Building a lightweight demo or training tool that explains GitOps sync mechanics to new team members.

Sponsored

Run this sample

Open the browser IDE to tweak the example and see results without installing anything.

Open editor

More from Production deployment patterns

Related tutorials and quizzes for this topic.