A Pulumi dynamic provider for managing Lagoon resources
Project description
Pulumi Lagoon Provider
A Pulumi dynamic provider for managing Lagoon resources as infrastructure-as-code.
Overview
This provider enables you to manage Lagoon hosting platform resources (projects, environments, variables, etc.) using Pulumi, bringing infrastructure-as-code practices to your Lagoon workflows.
Status: ๐ง Early Development
Features
- Declarative Configuration: Manage Lagoon resources alongside your AWS/Kubernetes infrastructure
- State Management: Pulumi tracks resource state and detects drift
- Type Safety: Python type hints for better IDE support
- GitOps Ready: Version control your Lagoon configurations
Supported Resources
Core Resources (Complete)
LagoonProject- Manage Lagoon projectsLagoonEnvironment- Manage environments (branches/PRs)LagoonVariable- Manage project and environment variables
Deploy Target Resources (Complete)
LagoonDeployTarget- Manage Kubernetes cluster deploy targetsLagoonDeployTargetConfig- Configure project deployment routing to specific clusters based on branch patterns
Notification Resources (Complete)
LagoonNotificationSlack- Manage Slack notificationsLagoonNotificationRocketChat- Manage RocketChat notificationsLagoonNotificationEmail- Manage Email notificationsLagoonNotificationMicrosoftTeams- Manage Microsoft Teams notificationsLagoonProjectNotification- Link notifications to projects
Task Resources (Complete)
LagoonTask- Manage advanced task definitions (on-demand commands and container-based tasks)
Planned
LagoonGroup- Manage user groups and permissions
Quick Start - Complete Test Environment
Set up a complete local development environment with Kind cluster, Lagoon, and the provider:
# Clone the repository
git clone https://github.com/tag1consulting/pulumi-lagoon-provider.git
cd pulumi-lagoon-provider
# Option 1: Use the setup script (recommended)
./scripts/setup-complete.sh
# Option 2: Use Make
make setup-all
# After setup, deploy the example project
make example-up
What gets created:
- Kind Kubernetes cluster (
lagoon) - Lagoon Core (API, UI, Keycloak, RabbitMQ, databases)
- Harbor container registry
- Ingress controller with TLS
- Python virtual environment with provider installed
- Example project ready to deploy
Total setup time: ~15-20 minutes
Installation
From PyPI (Recommended)
pip install pulumi-lagoon
From Source (Development)
# Clone the repository
git clone https://github.com/tag1consulting/pulumi-lagoon-provider.git
cd pulumi-lagoon-provider
# Create virtual environment
python3 -m venv venv
source venv/bin/activate
# Install in development mode
pip install -e .
Configuration
For the local test cluster (after running setup):
# The example project handles this automatically via the run-pulumi.sh wrapper
cd examples/simple-project
./scripts/run-pulumi.sh up
For external Lagoon instances, use environment variables (recommended for dynamic providers):
export LAGOON_API_URL=https://api.lagoon.example.com/graphql
export LAGOON_TOKEN=YOUR_TOKEN
Note: Dynamic providers run in a subprocess and cannot access Pulumi config secrets.
Always use environment variables for LAGOON_TOKEN.
Usage
import pulumi
import pulumi_lagoon as lagoon
# Create a Lagoon project
project = lagoon.LagoonProject("my-drupal-site",
name="my-drupal-site",
git_url="git@github.com:org/repo.git",
deploytarget_id=1,
production_environment="main",
branches="^(main|develop|stage)$",
pullrequests="^(PR-.*)",
)
# Create production environment
prod_env = lagoon.LagoonEnvironment("production",
project_id=project.id,
name="main",
environment_type="production",
deploy_type="branch",
)
# Add environment variable
db_config = lagoon.LagoonVariable("database-host",
project_id=project.id,
environment_id=prod_env.id,
name="DATABASE_HOST",
value="mysql.production.example.com",
scope="runtime",
)
# Create a Slack notification
slack_alerts = lagoon.LagoonNotificationSlack("deploy-alerts",
lagoon.LagoonNotificationSlackArgs(
name="deploy-alerts",
webhook="https://hooks.slack.com/services/xxx/yyy/zzz",
channel="#deployments",
)
)
# Link the notification to the project
project_notification = lagoon.LagoonProjectNotification("project-slack",
lagoon.LagoonProjectNotificationArgs(
project_name=project.name,
notification_type="slack",
notification_name=slack_alerts.name,
),
opts=pulumi.ResourceOptions(depends_on=[project, slack_alerts])
)
# Export project details
pulumi.export("project_id", project.id)
pulumi.export("production_url", prod_env.route)
Examples
See the examples/ directory for complete examples:
simple-project/- Use the Lagoon provider to create projects/environments/variables via APIsingle-cluster/- Deploy complete Lagoon stack to a single Kind clustermulti-cluster/- Production-like deployment with separate prod/nonprod Kind clusters
Multi-Cluster Example
The multi-cluster example demonstrates a production-like Lagoon deployment with:
- Production cluster (
lagoon-prod): Lagoon core services, Harbor registry, and production workloads - Non-production cluster (
lagoon-nonprod): Development/staging workloads that connect to prod core - Deploy Target Configs: Route deployments to the appropriate cluster based on branch patterns
mainbranch โ production clusterdevelop,feature/*branches โ non-production cluster- Pull requests โ non-production cluster
# Deploy the multi-cluster environment
make multi-cluster-deploy
# Verify deployment
make multi-cluster-verify
# Access information (URLs, credentials)
cd examples/multi-cluster && make show-access-info
The example creates a complete Drupal project with multi-cluster routing configured automatically.
Importing Existing Resources
You can import existing Lagoon resources into Pulumi state using pulumi import. This is useful when adopting infrastructure-as-code for existing Lagoon projects.
Import ID Formats
| Resource | Import ID Format | Example |
|---|---|---|
LagoonProject |
{numeric_id} |
pulumi import lagoon:index:Project my-project 123 |
LagoonDeployTarget |
{numeric_id} |
pulumi import lagoon:index:DeployTarget my-target 1 |
LagoonEnvironment |
{project_id}:{env_name} |
pulumi import lagoon:index:Environment my-env 123:main |
LagoonVariable |
{project_id}:{env_id}:{var_name} |
pulumi import lagoon:index:Variable my-var 123:456:DATABASE_HOST |
LagoonVariable (project-level) |
{project_id}::{var_name} |
pulumi import lagoon:index:Variable my-var 123::API_KEY |
LagoonDeployTargetConfig |
{project_id}:{config_id} |
pulumi import lagoon:index:DeployTargetConfig my-config 123:5 |
LagoonNotificationSlack |
{name} |
pulumi import lagoon:index:NotificationSlack my-slack deploy-alerts |
LagoonNotificationRocketChat |
{name} |
pulumi import lagoon:index:NotificationRocketChat my-rc team-chat |
LagoonNotificationEmail |
{name} |
pulumi import lagoon:index:NotificationEmail my-email ops-team |
LagoonNotificationMicrosoftTeams |
{name} |
pulumi import lagoon:index:NotificationMicrosoftTeams my-teams teams-alerts |
LagoonProjectNotification |
{project}:{type}:{name} |
pulumi import lagoon:index:ProjectNotification my-assoc my-project:slack:deploy-alerts |
LagoonTask |
{numeric_id} |
pulumi import lagoon:index:Task my-task 123 |
Finding Resource IDs
Use the Lagoon CLI to find resource IDs:
# List projects and their IDs
lagoon list projects
# Get project details including environment IDs
lagoon get project --project my-project
# List variables for a project
lagoon list variables --project my-project
Import Examples
# Import an existing project (ID 123)
pulumi import lagoon:index:Project my-site 123
# Import an environment named "main" from project 123
pulumi import lagoon:index:Environment prod-env 123:main
# Import a project-level variable
pulumi import lagoon:index:Variable api-key 123::API_KEY
# Import an environment-level variable (project 123, environment 456)
pulumi import lagoon:index:Variable db-host 123:456:DATABASE_HOST
# Import a deploy target config
pulumi import lagoon:index:DeployTargetConfig routing-config 123:5
# Import a Slack notification
pulumi import lagoon:index:NotificationSlack my-slack deploy-alerts
# Import a project notification association
pulumi import lagoon:index:ProjectNotification my-assoc my-project:slack:deploy-alerts
# Import an advanced task definition
pulumi import lagoon:index:Task yarn-audit 456
After importing, you'll need to add the corresponding resource definition to your Pulumi code.
Development
Prerequisites
- Python 3.8 or later
- Pulumi CLI
- Docker (for local test cluster)
- kind CLI (for local test cluster)
- kubectl
Quick Setup
# Complete automated setup (creates Kind cluster, installs Lagoon, provider)
make setup-all
# Or just install the provider for use with existing Lagoon
make venv provider-install
Make Targets
# Setup
make setup-all # Complete setup: venv, provider, Kind cluster, Lagoon, user, deploy target
make venv # Create Python virtual environment
make provider-install # Install provider in development mode
make cluster-up # Create Kind cluster + deploy Lagoon via Pulumi
make cluster-down # Destroy Kind cluster and Lagoon resources
# Lagoon Setup (called by setup-all)
make ensure-lagoon-admin # Create lagoonadmin user in Keycloak
make ensure-deploy-target # Create deploy target in Lagoon + set Pulumi config
# Example Project (simple-project)
make example-setup # Initialize example Pulumi stack
make example-preview # Preview changes (auto token refresh)
make example-up # Deploy example resources (auto token refresh)
make example-down # Destroy example resources
make example-output # Show stack outputs
# Multi-cluster Example
make multi-cluster-up # Create prod + nonprod Kind clusters with full Lagoon stack:
# - prod cluster: lagoon-core + lagoon-remote + Harbor
# - nonprod cluster: lagoon-remote only (connects to prod core)
make multi-cluster-down # Destroy multi-cluster environment
make multi-cluster-preview # Preview multi-cluster changes
make multi-cluster-status # Show multi-cluster stack outputs
make multi-cluster-clusters # List all Kind clusters
# Cleanup
make clean # Kill port-forwards, remove temp files
make clean-all # Full cleanup: clean + destroy cluster + remove venvs
# Status
make cluster-status # Show cluster and Lagoon status
make help # Show all available targets
Note: All targets that interact with Lagoon automatically handle:
- Port-forward setup (temporary, cleaned up after)
- Token refresh (5-minute token expiration handled)
- Direct Access Grants enablement in Keycloak
- User and deploy target creation (if needed)
Manual Setup
# Create virtual environment
python3 -m venv venv
source venv/bin/activate
# Install dependencies
pip install -r requirements.txt
# Install in development mode
pip install -e .
# Run tests
pytest tests/
Project Structure
pulumi-lagoon-provider/
โโโ pulumi_lagoon/ # Main provider package
โ โโโ __init__.py # Package exports
โ โโโ client.py # Lagoon GraphQL API client
โ โโโ config.py # Provider configuration
โ โโโ exceptions.py # Custom exceptions
โ โโโ validators.py # Input validation
โ โโโ project.py # LagoonProject resource
โ โโโ environment.py # LagoonEnvironment resource
โ โโโ variable.py # LagoonVariable resource
โ โโโ task.py # LagoonTask resource
โ โโโ deploytarget.py # LagoonDeployTarget resource
โ โโโ deploytarget_config.py # LagoonDeployTargetConfig resource
โ โโโ notification_slack.py # LagoonNotificationSlack resource
โ โโโ notification_rocketchat.py # LagoonNotificationRocketChat resource
โ โโโ notification_email.py # LagoonNotificationEmail resource
โ โโโ notification_microsoftteams.py # LagoonNotificationMicrosoftTeams resource
โ โโโ project_notification.py # LagoonProjectNotification resource
โโโ examples/
โ โโโ simple-project/ # API usage example (assumes Lagoon exists)
โ โ โโโ __main__.py # Creates projects/environments/variables
โ โ โโโ scripts/ # Helper scripts
โ โโโ single-cluster/ # Single Kind cluster deployment
โ โ โโโ __main__.py # Deploys full Lagoon stack
โ โ โโโ (symlinks) # Reuses multi-cluster modules
โ โโโ multi-cluster/ # Production-like multi-cluster deployment
โ โโโ __main__.py # Two-cluster deployment
โ โโโ clusters/ # Kind cluster management
โ โโโ infrastructure/ # Ingress, cert-manager, CoreDNS
โ โโโ lagoon/ # Lagoon core and remote
โ โโโ registry/ # Harbor installation
โ โโโ tests/ # Unit tests for multi-cluster config (39 tests)
โโโ scripts/ # Shared operational scripts
โโโ tests/ # Unit and integration tests
โโโ memory-bank/ # Planning and architecture docs
โโโ Makefile # Top-level automation
โโโ README.md # This file
Architecture
This is a Pulumi dynamic provider written in Python. It communicates with the Lagoon GraphQL API to perform CRUD operations on resources.
Key components:
- Resource Definitions: User-facing classes (e.g.,
LagoonProject) - Provider Implementations: CRUD logic for each resource type
- GraphQL Client: Handles API communication
- Configuration: Manages API credentials and settings
For detailed architecture information, see memory-bank/architecture.md.
Roadmap
Phase 1: MVP (Complete)
- Project setup and structure
- GraphQL client implementation
- Core resources (Project, Environment, Variable)
- Basic examples with automation scripts
- Test cluster setup via Pulumi (Kind + Lagoon)
- Documentation
Phase 2: Deploy Targets & Multi-Cluster (Complete)
- Comprehensive error handling
- Unit tests (300+ tests, 95% coverage)
- Integration test framework
- CI/CD pipeline (GitHub Actions)
- DeployTarget resource for Kubernetes cluster management
- DeployTargetConfig resource for branch-based deployment routing
- Multi-cluster example (prod/nonprod separation)
- Two-phase deployment pattern (infrastructure first, then API-dependent resources)
- CORS and TLS configuration for browser access with self-signed certificates
- Comprehensive documentation for browser access setup
Phase 3: Production Ready (Current)
- PyPI package publishing
- Notification resources (Slack, RocketChat, Email, Microsoft Teams)
- Project notification associations
- Additional resources (Group)
- Advanced examples
- Community feedback integration
Phase 4: Native Provider (Future)
- Go implementation
- Multi-language SDK generation (Python, TypeScript, Go)
- Enhanced performance
Contributing
This project is in early development. Contributions, feedback, and bug reports are welcome!
- Fork the repository
- Create a feature branch
- Make your changes
- Add tests
- Submit a pull request
License
Apache License 2.0 - See LICENSE for details.
Resources
Support
For issues and questions:
- GitHub Issues: Create an issue
- Lagoon Community: Slack
Acknowledgments
Built for the Lagoon community by infrastructure engineers who believe in infrastructure-as-code.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file pulumi_lagoon-0.1.1.tar.gz.
File metadata
- Download URL: pulumi_lagoon-0.1.1.tar.gz
- Upload date:
- Size: 50.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
446cdb8ef3455b52b17d8101745b74fcbf0d231d74866657884a5d3b1ce6e793
|
|
| MD5 |
c4a1b67aae5740bd805c0097a7a8ad8c
|
|
| BLAKE2b-256 |
9a1d76348dcad906ddc6c5063447766a4d92e92c2affbc1188b0b6ed5f1d9b74
|
Provenance
The following attestation bundles were made for pulumi_lagoon-0.1.1.tar.gz:
Publisher:
publish.yml on tag1consulting/pulumi-lagoon-provider
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pulumi_lagoon-0.1.1.tar.gz -
Subject digest:
446cdb8ef3455b52b17d8101745b74fcbf0d231d74866657884a5d3b1ce6e793 - Sigstore transparency entry: 907009149
- Sigstore integration time:
-
Permalink:
tag1consulting/pulumi-lagoon-provider@a48c625f3010bbc88a1c1adadb95d3a3108b808c -
Branch / Tag:
refs/tags/v0.1.1 - Owner: https://github.com/tag1consulting
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@a48c625f3010bbc88a1c1adadb95d3a3108b808c -
Trigger Event:
release
-
Statement type:
File details
Details for the file pulumi_lagoon-0.1.1-py3-none-any.whl.
File metadata
- Download URL: pulumi_lagoon-0.1.1-py3-none-any.whl
- Upload date:
- Size: 56.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0a3ffd73858003258d4debcd71ae84926a7a4dbc5ef0a25305f0c6e31953571c
|
|
| MD5 |
e20b95826fba414d56d14e052fc794a9
|
|
| BLAKE2b-256 |
bc5e25ba31797bd70b3663982d4cb0897250b2c6ea87ad326446b42af43fd0ae
|
Provenance
The following attestation bundles were made for pulumi_lagoon-0.1.1-py3-none-any.whl:
Publisher:
publish.yml on tag1consulting/pulumi-lagoon-provider
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pulumi_lagoon-0.1.1-py3-none-any.whl -
Subject digest:
0a3ffd73858003258d4debcd71ae84926a7a4dbc5ef0a25305f0c6e31953571c - Sigstore transparency entry: 907009196
- Sigstore integration time:
-
Permalink:
tag1consulting/pulumi-lagoon-provider@a48c625f3010bbc88a1c1adadb95d3a3108b808c -
Branch / Tag:
refs/tags/v0.1.1 - Owner: https://github.com/tag1consulting
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@a48c625f3010bbc88a1c1adadb95d3a3108b808c -
Trigger Event:
release
-
Statement type: