Skip to content

Conversation

@shreddedbacon
Copy link
Member

@shreddedbacon shreddedbacon commented Sep 30, 2025

General Checklist

  • Affected Issues have been mentioned in the Closing issues section
  • Documentation has been written/updated
  • PR title is ready for inclusion in changelog

Database Migrations

  • If your PR contains a database migation, it MUST be the latest in date order alphabetically

Description

Routes defined in the API

This feature adds the ability to add routes to a project, and then associate that route to an environment. This allows users to add and remove routes without needing to modify their .lagoon.yml files.

If a route defined in the API also exists in the .lagoon.yml file, the route in the API will be used, and the one in the .lagoon.yml file will have changes merged on top of the existing configuration (this is handled during the deployment phase). In most cases, the route in the API will have all the required information when sent from the API, which will override whatever was defined in the .lagoon.yml if there is an existing matching route.

To take advantage of routes in the API, a route will need to firstly be created in the project. When creating a route, you can either create it in an attached or unattached state.

If an environment already exists with an appropriate service, you can add the environment and service to the route at creation time, this would be an attached route. You can create a route without having an environment or service defined, this can be useful if an environment doesn't exist yet.

Once a route is added to a project and attached to an environment, a deployment will need to take place to apply the route in the cluster. Without a deployment taking place, the route will not be used.

Advanced features

There are some more advanced features with routes in the API. These are

  • Active / Standy
  • Additional domains
  • Path based routes
  • Annotations

Active / Standby

Active / Stanby environments when using routes in the API become significantly easier to use. Prior to routes in the API, the routes used would need to be defined in both environment .lagoon.yml files. This added some complexity to what is otherwise a relatively simple feature.

With routes in the API, if the project is configured to have a standby production environment, when creating a route you can select if the route be created as an active or standby route and assign it to the necessary environment. You don't need to define it in both environments anymore, when deploying the environments, the API knows which routes it needs to deploy with. When the active/standby switch occurs, the routes get moved in the API to reflect the environment they were moved to accordingly.

Additionally, you can add normal routes to your active/standby environments that are not flagged as active or standby, these will remain attached to the environment during a switch. These can be useful for ensuring you have a route that will always point to an intended environment.

If using routes in the API and the active/standby feature, it is recommended that you remove the production_routes configurations for active/standby from your .lagoon.yml files and only define the routes in the API. Using both API and .lagoon.yml routes at the same time could result in unexpected issues.

Additional domains

Additional domains are a way to add more than 1 domain to a route. One way these would be used is if you have a primary domain, eg example.com, you could add www.example.com as an additional domain to the route. In kubernetes, this will result in a single ingress with multiple host entries, and if LetsEncrypt certificates are used, those domains will be on the same certificate.

This has a hard coded limit of 25 additional domains per route, because LetsEncrypt and potentially others may have different limits on how many domains can be in SAN certificate. This just makes sure the certificate generated isn't too large.

Path based routes

Path base routes are the same idea as described in the docs for .lagoon.yml. These are able to be added and removed using the API on a route.

This also has a hard coded limit of 10 path based routes per route. This is just an arbitrary limit, as I'm not sure how well used this feature is generally. Maybe it could be made it configurable per project (only configurable by a platform level role)

Annotations

Annotations are also available in the API, these also function the same way as described in the docs. The same restrictions apply.

This also has a hard coded limit of 10 annotations per route. This is just an arbitrary limit, as I'm not sure how well used this feature is generally. Maybe it could be made it configurable per project (only configurable by a platform level role)

Usage

The following describes some basic usage of the routes endpoints, the Lagoon UI will support managing routes, but more advanced options may not be immediately available in the UI.

Creating a Route

When creating a route, you can add it directly to an environment, here is an example of creating a generic route on an environment named main pointing to an nginx service. There defaults for fields like tlsAcme and insecure if they aren't provided on creation time.

mutation {
    addRouteToProject(input:{
        domain: "domain.example.com"
        project: "lagoon-demo"
        environment: "main"
        service: "nginx"
    }){
        id
        domain
        source
        service
        tlsAcme
        insecure
        project {
        	name
        }
        environment{
        	name
        }
    }
}

This returns the created object, and you can see the defaults for tlsAcme and insecure here.

{
	"addRouteToProject": {
		"domain": "domain.example.com",
		"environment": {
			"name": "main"
		},
		"id": 6,
		"insecure": "Redirect",
		"project": {
			"name": "lagoon-demo"
		},
		"service": "nginx",
		"source": "API",
		"tlsAcme": true
	}
}

Updating a route

To change fields on a route, you can update them using the following mutation. In this example, setting tlsAcme to false and disabling https redirects.

mutation {
    updateRouteOnProject(input:{
        domain: "domain.example.com"
        project: "lagoon-demo"
        patch: {
          tlsAcme: false
          insecure: Allow
        }
    }){
        id
        domain
        source
        service
        tlsAcme
        insecure
        project {
        	name
        }
        environment{
        	name
        }
    }
}

And the return we can see those changes are made.

{
	"updateRouteOnProject": {
		"domain": "domain.example.com",
		"environment": {
			"name": "main"
		},
		"id": 6,
		"insecure": "Allow",
		"project": {
			"name": "lagoon-demo"
		},
		"service": "nginx",
		"source": "API",
		"tlsAcme": false
	}
}

Deleting a route

To delete a route, you need the route ID. Then run this mutation

mutation {
    deleteRoute(input:{id: 1})
}

Changing which environment a route is attached to

Its possible to move a route from one environment to another. First you have to remove it from the current environment using removeRouteFromEnvironment like so

mutation {
    removeRouteFromEnvironment(input:{
        domain: "domain.example.com"
        environment: "main"
        project: "lagoon-demo"
    }){
        id
        project{
        	name
        }
        environment{
        	name
        }
    }
}

This will remove the route association from the main environment, and the route will now be in an unattached state.

{
	"removeRouteFromEnvironment": {
		"environment": null,
		"id": 6,
		"project": {
			"name": "lagoon-demo"
		}
	}
}

A deployment of the main environment will need to be performed now to ensure it is removed from the environment before it is added to the other environment.

Once the deployment of the environment is done, you can attach the route to the correct environment using addOrUpdateRouteOnEnvironment like so

mutation {
    addOrUpdateRouteOnEnvironment(input:{
        domain: "domain.example.com"
        service: "nginx"
        environment: "dev"
        project: "lagoon-demo"
    }){
        id
        project{
        	name
        }
        environment{
        	name
        }
    }
}

This route is now attached to the dev environment

{
	"addOrUpdateRouteOnEnvironment": {
		"environment": {
			"name": "dev"
		},
		"id": 6,
		"project": {
			"name": "lagoon-demo"
		}
	}
}

A deployment of the dev environment will need to be performed for the route to be created in the environment.

Autogenerated Routes

By default, autogenerated route configuration on projects and environments is not used. This configuration is only configurable in the .lagoon.yml file. However, as soon as autogenerated route configuration is updated on a project or environment in the API, the autogenerated route config in the .lagoon.yml file is ignored.

Disable autogenerated routes for the project

If you want to disable all autogenerated routes for a project, updating the autogenerated route configuration on a

mutation {
    updateAutogeneratedRouteConfigOnProject(
    	input: {
        project: "lagoon-demo"
        patch: {
        	enabled: false
        }
      }
    ) {
      enabled
    }
}

And we can see that the enabled state is now false.

{
	"updateAutogeneratedRouteConfigOnProject": {
		"enabled": false
	}
}

If you want to then enable them for a specific environment, you update the autogenerated route configuration for that environment to override the project settings

mutation {
    updateAutogeneratedRouteConfigOnEnvironment(
    	input: {
        project: "lagoon-demo"
        environment: "main"
        patch: {
        	enabled: true
        }
      }
    ) {
      enabled
    }
}

and we can see the main environment has autogenerated routes enabled

{
	"updateAutogeneratedRouteConfigOnEnvironment": {
		"enabled": true
	}
}

Note

There is no inheritance from the project configuration, this means if you have other settings that are configured in the project autogenerated route configuration, you'll need to add these specific changes to the environment configuration too

Tip

All fields and inputs for these resolvers are available in the API spec.

Other

Limits

There are no limits to how many routes can be added per project, maybe there should be?

Autogenerated and Lagoon YAML routes

Phase 2 support for routes in the API would be updating remote-controller and build-deploy-tool to support sending the non-API created routes back to the API to be visualised, then we can look at deprecating the route and routes fields on an environment for apiRoutes directly.

Before/After merge

@github-actions
Copy link

github-actions bot commented Oct 28, 2025

Overview

Image reference testlagoon/api:main lagoon/api:ci-latest
- digest ef34a2bc2fb1 7558542a318b
- tag main ci-latest
- provenance https://github.com/uselagoon/lagoon.git/commit/8448b56a7464d09b7dc8cf93deca398e197dd952
- vulnerabilities critical: 4 high: 8 medium: 12 low: 5 unspecified: 1 critical: 4 high: 8 medium: 12 low: 5 unspecified: 1
- platform linux/amd64 linux/amd64
- size 146 MB 176 MB (+29 MB)
- packages 1525 1525
Base Image node:22-alpine
also known as:
22-alpine3.22
22.21-alpine
22.21-alpine3.22
22.21.1-alpine
22.21.1-alpine3.22
jod-alpine
jod-alpine3.22
node:22-alpine
also known as:
22-alpine3.22
22.21-alpine
22.21-alpine3.22
22.21.1-alpine
22.21.1-alpine3.22
jod-alpine
jod-alpine3.22
- vulnerabilities critical: 0 high: 0 medium: 0 low: 2 critical: 0 high: 0 medium: 0 low: 2

@bomoko bomoko requested a review from Copilot October 29, 2025 00:33
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This pull request adds comprehensive API routes functionality to Lagoon, enabling users to manage routing configurations through the API instead of solely via YAML files. This is a beta feature that introduces database-backed route management with support for various route types, alternative domains, annotations, and path-based routing.

Key changes include:

  • New GraphQL API endpoints for CRUD operations on routes
  • Database schema additions with new routes, routes_alternate_domain, and routes_annotations tables
  • Keycloak permission setup for route management
  • Integration with active/standby environment switching
  • Test suite additions for API route functionality

Reviewed Changes

Copilot reviewed 26 out of 26 changed files in this pull request and generated 13 comments.

Show a summary per file
File Description
services/api/src/typeDefs.js Adds GraphQL schema definitions for Route types, mutations, and queries
services/api/src/resources/routes/resolvers.ts Implements route CRUD operations and field resolvers
services/api/src/resources/routes/sql.ts Database query builders for route operations
services/api/src/resources/routes/helpers.ts Helper functions for route management and path route manipulation
services/api/database/migrations/20250925000000_routes.js Database migration for routes tables and related columns
services/keycloak/startup-scripts/00-configure-lagoon.sh Configures Keycloak permissions for route operations
services/keycloak/lagoon-realm-base-import.json Adds route resource and permissions to Keycloak realm
node-packages/commons/src/tasks.ts Handles route configuration in build/deploy tasks
services/actions-handler/handler/controller_tasks.go Updates active/standby routes after environment switches
tests/tests/api-routes/ Test suite for API routes functionality

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@bomoko bomoko requested a review from Copilot October 29, 2025 02:39
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

Copilot reviewed 26 out of 26 changed files in this pull request and generated 9 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copy link
Contributor

@bomoko bomoko left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changes all make sense.

@rocketeerbkw rocketeerbkw merged commit 6f09633 into main Nov 4, 2025
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants