Skip to content

tag1consulting/pulumi-lagoon-provider

Pulumi Lagoon Provider

PyPI version npm version Go Reference NuGet version Go Tests License

A Pulumi provider for managing Lagoon resources as infrastructure-as-code.

Documentation Site | Getting Started | Resource Reference

Overview

This provider enables you to manage Lagoon hosting platform resources (projects, environments, variables, deploy targets, notifications, tasks, etc.) using Pulumi, with native SDKs for Python, TypeScript/JavaScript, Go, and .NET/C#.

Status: v0.5.1 — Native Go Provider

Supported Resources

Resource Description
Project Lagoon projects (applications/sites)
Environment Environments (branch/PR deployments)
Variable Project and environment variables
DeployTarget Kubernetes cluster deploy targets
DeployTargetConfig Branch-pattern routing to deploy targets
NotificationSlack Slack deployment notifications
NotificationRocketChat RocketChat deployment notifications
NotificationEmail Email deployment notifications
NotificationMicrosoftTeams Microsoft Teams deployment notifications
ProjectNotification Link notifications to projects
Task Advanced task definitions (command and image types)
Group Groups for organizing projects and users
User Lagoon users (full CRUD)
UserGroupAssignment User-to-group role assignments
UserPlatformRole Platform-level role assignments
Route API-managed routes with annotations, alternative names, and path routing (requires Lagoon v2.29.0+)
ProjectAutogeneratedRouteConfig Project-level autogenerated route configuration (requires Lagoon v2.29.0+)
EnvironmentAutogeneratedRouteConfig Environment-level autogenerated route configuration (requires Lagoon v2.29.0+)

Installation

Python

pip install pulumi-lagoon

TypeScript / JavaScript

npm install @tag1consulting/pulumi-lagoon
# or
yarn add @tag1consulting/pulumi-lagoon

Go

go get github.com/tag1consulting/pulumi-lagoon-provider/sdk/go/lagoon

.NET / C#

dotnet add package Tag1Consulting.Lagoon

Lagoon Compatibility

The table below lists Lagoon versions that have been tested with this provider:

Lagoon Version lagoon-core chart lagoon-remote chart Notes
v2.31.0 1.60.0 0.104.1 Tested (single + multi-cluster)
v2.30.0 1.59.0 0.103.0 Tested; known Knex migrations bug (fixed in v2.31.0)
v2.28.0 1.56.0 0.96.0 Tested
v2.24.1 1.52.0 0.90.0 Tested

Route resources (Route, ProjectAutogeneratedRouteConfig, EnvironmentAutogeneratedRouteConfig) require Lagoon v2.29.0 or later.

Configuration

pulumi config set lagoon:apiUrl https://api.lagoon.example.com/graphql
pulumi config set --secret lagoon:token YOUR_TOKEN
# or use a JWT secret for admin token generation:
pulumi config set --secret lagoon:jwtSecret YOUR_JWT_SECRET

Or via environment variables:

export LAGOON_API_URL=https://api.lagoon.example.com/graphql
export LAGOON_TOKEN=YOUR_TOKEN

Usage

Python

import pulumi
import pulumi_lagoon as lagoon
from pulumi_lagoon import Project, ProjectArgs, Environment, EnvironmentArgs, Variable, VariableArgs
# The submodule path also works: from pulumi_lagoon.lagoon import Project, ...

project = Project("my-site",
    ProjectArgs(
        name="my-drupal-site",
        git_url="git@github.com:org/repo.git",
        deploytarget_id=1,
        production_environment="main",
        branches="^(main|develop|stage)$",
    )
)

# The project's deploy key is available as an output for adding to your Git host
pulumi.export("deploy_key", project.public_key)

prod_env = Environment("production",
    EnvironmentArgs(
        name="main",
        project_id=project.lagoon_id,
        deploy_type="branch",
        deploy_base_ref="main",
        environment_type="production",
    )
)

db_config = Variable("db-host",
    VariableArgs(
        name="DATABASE_HOST",
        value="mysql.production.example.com",
        project_id=project.lagoon_id,
        environment_id=prod_env.lagoon_id,
        scope="runtime",
    )
)

pulumi.export("project_id", project.lagoon_id)
pulumi.export("production_url", prod_env.route)

TypeScript

import * as lagoon from "@tag1consulting/pulumi-lagoon";
// Resources are available directly: lagoon.Project, lagoon.Variable, etc.
// The submodule path also works: lagoon.lagoon.Project

const project = new lagoon.Project("my-site", {
    name: "my-drupal-site",
    gitUrl: "git@github.com:org/repo.git",
    deploytargetId: 1,
    productionEnvironment: "main",
    branches: "^(main|develop|stage)$",
});

export const projectId = project.lagoonId;

Go

import (
    lagoon "github.com/tag1consulting/pulumi-lagoon-provider/sdk/go/lagoon/lagoon"
)

project, err := lagoon.NewProject(ctx, "my-site", &lagoon.ProjectArgs{
    Name:                  pulumi.String("my-drupal-site"),
    GitUrl:                pulumi.String("git@github.com:org/repo.git"),
    DeploytargetId:        pulumi.Int(1),
    ProductionEnvironment: pulumi.String("main"),
})

C#

using System.Collections.Generic;
using Pulumi;
using Tag1Consulting.Lagoon.Lagoon;

return await Deployment.RunAsync(() =>
{
    var project = new Project("my-site", new ProjectArgs
    {
        Name = "my-drupal-site",
        GitUrl = "git@github.com:org/repo.git",
        DeploytargetId = 1,
        ProductionEnvironment = "main",
        Branches = "^(main|develop|stage)$",
    });

    return new Dictionary<string, object?>
    {
        ["projectId"] = project.LagoonId,
    };
});

Examples

See the examples/ directory for complete examples:

  • simple-project/ — Create Lagoon projects, environments, variables, and notifications via the API
  • single-cluster/ — Deploy a complete Lagoon stack to a single Kind cluster
  • multi-cluster/ — Production-like deployment with separate prod/nonprod Kind clusters

Multi-Cluster Example

# Deploy prod + nonprod Kind clusters with full Lagoon stack
make multi-cluster-up

# Verify deployment
make multi-cluster-status

# Tear down
make multi-cluster-down

Importing Existing Resources

Use pulumi import to bring existing Lagoon resources under Pulumi management:

Resource Import ID Format Example
lagoon:lagoon:Project {numeric_id} 123
lagoon:lagoon:DeployTarget {numeric_id} 1
lagoon:lagoon:Environment {project_id}:{env_name} 123:main
lagoon:lagoon:Variable {project_id}:{env_id}:{var_name} 123:456:DATABASE_HOST
lagoon:lagoon:Variable (project-level) {project_id}::{var_name} 123::API_KEY
lagoon:lagoon:DeployTargetConfig {project_id}:{config_id} 123:5
lagoon:lagoon:NotificationSlack {name} deploy-alerts
lagoon:lagoon:NotificationRocketChat {name} deploy-alerts
lagoon:lagoon:NotificationEmail {name} ops-email
lagoon:lagoon:NotificationMicrosoftTeams {name} deploy-alerts
lagoon:lagoon:ProjectNotification {project_name}:{type}:{notification_name} my-project:slack:deploy-alerts
lagoon:lagoon:Task {numeric_id} 456
lagoon:lagoon:Group {name} my-team
lagoon:lagoon:Route {project_name}:{domain} my-project:example.com
lagoon:lagoon:ProjectAutogeneratedRouteConfig {project_name} my-project
lagoon:lagoon:EnvironmentAutogeneratedRouteConfig {project_name}:{env_name} my-project:main
lagoon:lagoon:User {email} user@example.com
lagoon:lagoon:UserGroupAssignment {email}:{group_name} user@example.com:my-team
lagoon:lagoon:UserPlatformRole {email}:{role} user@example.com:OWNER
# Import an existing project (ID 123)
pulumi import lagoon:lagoon:Project my-site 123

# Import an environment
pulumi import lagoon:lagoon:Environment prod-env 123:main

# Import a project-level variable
pulumi import lagoon:lagoon:Variable api-key 123::API_KEY

Use the Lagoon CLI to find resource IDs:

lagoon list projects
lagoon get project --project my-project

Development

Prerequisites

  • Go 1.26+
  • Pulumi CLI
  • Docker, Kind, kubectl, jq (for local test clusters)

Build

cd provider
CGO_ENABLED=0 go build ./cmd/pulumi-resource-lagoon/

Test

cd provider
CGO_ENABLED=0 go test ./... -count=1

Makefile Targets

make go-build       # Build the provider binary
make go-test        # Run all Go tests (690+ tests)
make go-schema      # Regenerate provider schema
make go-sdk-all     # Regenerate all language SDKs
make go-sdk-python  # Regenerate Python SDK
make go-sdk-nodejs  # Regenerate TypeScript SDK
make go-sdk-go      # Regenerate Go SDK

Provider Structure

pulumi-lagoon-provider/
├── provider/                    # Native Go provider
│   ├── cmd/pulumi-resource-lagoon/  # Provider binary entrypoint
│   ├── pkg/client/              # Lagoon GraphQL client
│   ├── pkg/config/              # Provider configuration
│   ├── pkg/resources/           # 18 resource implementations
│   └── schema.json              # Pulumi schema
├── sdk/                         # Generated multi-language SDKs
│   ├── python/                  # Python SDK (PyPI: pulumi-lagoon)
│   ├── nodejs/                  # TypeScript SDK (npm: @tag1consulting/pulumi-lagoon)
│   ├── go/lagoon/               # Go SDK
│   └── dotnet/                  # .NET/C# SDK (NuGet: Tag1Consulting.Lagoon)
├── examples/
│   ├── simple-project/          # Provider usage example
│   ├── single-cluster/          # Single Kind cluster deployment
│   └── multi-cluster/           # Production-like multi-cluster deployment
├── scripts/                     # Shared operational scripts
└── docs/                        # Additional documentation

Architecture

A native Go provider using pulumi-go-provider v1.3.0 with the infer package. The provider communicates with the Lagoon GraphQL API and generates multi-language SDKs from a single schema.

Key properties:

  • All sensitive fields (token, jwtSecret, webhook, value) are marked secret and encrypted in state
  • All 18 resources implement Diff with per-field DetailedDiff (Update vs UpdateReplace)
  • All resources support pulumi import
  • JWT token generation is centralized and configurable (jwtAudience config field)

Troubleshooting

Authentication Errors

  • "lagoon authentication required" — Set lagoon:token via pulumi config set --secret lagoon:token <TOKEN> or export LAGOON_TOKEN.
  • Token expired — Lagoon JWT tokens expire after 1 hour. Generate a fresh token or use jwtSecret for automatic renewal.
  • Self-signed certificates — Set lagoon:insecure to true for development instances with self-signed TLS.

Common Issues

  • "not found" on import — Verify the resource exists in Lagoon. Import IDs are case-sensitive. See the import reference table for the correct format.
  • Diff on unchanged resources — If pulumi preview shows unexpected changes after import, ensure all required fields in your code match the Lagoon API values exactly.
  • Provider version mismatch — Run pulumi plugin ls | grep lagoon to verify the installed version matches your SDK version.

Contributing

Contributions, feedback, and bug reports are welcome! See CONTRIBUTING.md for development setup, coding guidelines, and the pull request process.

This project follows a Code of Conduct. By participating, you agree to uphold these standards.

License

Apache License 2.0 — See LICENSE for details.

Resources

Support

About

Pulumi native Go provider for the Lagoon hosting platform. Declaratively manage projects, environments, variables, notifications, and tasks. Multi-language SDKs for Python, TypeScript, and Go.

Topics

Resources

License

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Packages

 
 
 

Contributors