The gcp:compute/uRLMap:URLMap resource, part of the Pulumi GCP provider, defines routing rules that direct incoming HTTP(S) requests to backend services or Cloud Storage based on hostname, path, headers, and query parameters. This guide focuses on five capabilities: host and path-based routing, header and query parameter matching, request transformation and traffic policies, path template matching and URL rewriting, and custom error page handling.
URL maps route to backend services and backend buckets that must exist separately, along with their health checks and Cloud Storage buckets. The examples are intentionally small. Combine them with your own backend infrastructure and load balancer configuration.
Route requests across backend services and storage buckets
Most load balancers start by routing traffic to different backends based on hostname and path, directing requests to backend services for dynamic content or backend buckets for static assets.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
const _default = new gcp.compute.HttpHealthCheck("default", {
name: "health-check",
requestPath: "/",
checkIntervalSec: 1,
timeoutSec: 1,
});
const login = new gcp.compute.BackendService("login", {
name: "login",
portName: "http",
protocol: "HTTP",
timeoutSec: 10,
healthChecks: _default.id,
});
const staticBucket = new gcp.storage.Bucket("static", {
name: "static-asset-bucket",
location: "US",
});
const static = new gcp.compute.BackendBucket("static", {
name: "static-asset-backend-bucket",
bucketName: staticBucket.name,
enableCdn: true,
});
const urlmap = new gcp.compute.URLMap("urlmap", {
name: "urlmap",
description: "a description",
defaultService: static.id,
hostRules: [
{
hosts: ["mysite.com"],
pathMatcher: "mysite",
},
{
hosts: ["myothersite.com"],
pathMatcher: "otherpaths",
},
],
pathMatchers: [
{
name: "mysite",
defaultService: static.id,
pathRules: [
{
paths: ["/home"],
service: static.id,
},
{
paths: ["/login"],
service: login.id,
},
{
paths: ["/static"],
service: static.id,
},
],
},
{
name: "otherpaths",
defaultService: static.id,
},
],
tests: [{
service: static.id,
host: "example.com",
path: "/home",
}],
});
import pulumi
import pulumi_gcp as gcp
default = gcp.compute.HttpHealthCheck("default",
name="health-check",
request_path="/",
check_interval_sec=1,
timeout_sec=1)
login = gcp.compute.BackendService("login",
name="login",
port_name="http",
protocol="HTTP",
timeout_sec=10,
health_checks=default.id)
static_bucket = gcp.storage.Bucket("static",
name="static-asset-bucket",
location="US")
static = gcp.compute.BackendBucket("static",
name="static-asset-backend-bucket",
bucket_name=static_bucket.name,
enable_cdn=True)
urlmap = gcp.compute.URLMap("urlmap",
name="urlmap",
description="a description",
default_service=static.id,
host_rules=[
{
"hosts": ["mysite.com"],
"path_matcher": "mysite",
},
{
"hosts": ["myothersite.com"],
"path_matcher": "otherpaths",
},
],
path_matchers=[
{
"name": "mysite",
"default_service": static.id,
"path_rules": [
{
"paths": ["/home"],
"service": static.id,
},
{
"paths": ["/login"],
"service": login.id,
},
{
"paths": ["/static"],
"service": static.id,
},
],
},
{
"name": "otherpaths",
"default_service": static.id,
},
],
tests=[{
"service": static.id,
"host": "example.com",
"path": "/home",
}])
package main
import (
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/compute"
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/storage"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_default, err := compute.NewHttpHealthCheck(ctx, "default", &compute.HttpHealthCheckArgs{
Name: pulumi.String("health-check"),
RequestPath: pulumi.String("/"),
CheckIntervalSec: pulumi.Int(1),
TimeoutSec: pulumi.Int(1),
})
if err != nil {
return err
}
login, err := compute.NewBackendService(ctx, "login", &compute.BackendServiceArgs{
Name: pulumi.String("login"),
PortName: pulumi.String("http"),
Protocol: pulumi.String("HTTP"),
TimeoutSec: pulumi.Int(10),
HealthChecks: _default.ID(),
})
if err != nil {
return err
}
staticBucket, err := storage.NewBucket(ctx, "static", &storage.BucketArgs{
Name: pulumi.String("static-asset-bucket"),
Location: pulumi.String("US"),
})
if err != nil {
return err
}
static, err := compute.NewBackendBucket(ctx, "static", &compute.BackendBucketArgs{
Name: pulumi.String("static-asset-backend-bucket"),
BucketName: staticBucket.Name,
EnableCdn: pulumi.Bool(true),
})
if err != nil {
return err
}
_, err = compute.NewURLMap(ctx, "urlmap", &compute.URLMapArgs{
Name: pulumi.String("urlmap"),
Description: pulumi.String("a description"),
DefaultService: static.ID(),
HostRules: compute.URLMapHostRuleArray{
&compute.URLMapHostRuleArgs{
Hosts: pulumi.StringArray{
pulumi.String("mysite.com"),
},
PathMatcher: pulumi.String("mysite"),
},
&compute.URLMapHostRuleArgs{
Hosts: pulumi.StringArray{
pulumi.String("myothersite.com"),
},
PathMatcher: pulumi.String("otherpaths"),
},
},
PathMatchers: compute.URLMapPathMatcherArray{
&compute.URLMapPathMatcherArgs{
Name: pulumi.String("mysite"),
DefaultService: static.ID(),
PathRules: compute.URLMapPathMatcherPathRuleArray{
&compute.URLMapPathMatcherPathRuleArgs{
Paths: pulumi.StringArray{
pulumi.String("/home"),
},
Service: static.ID(),
},
&compute.URLMapPathMatcherPathRuleArgs{
Paths: pulumi.StringArray{
pulumi.String("/login"),
},
Service: login.ID(),
},
&compute.URLMapPathMatcherPathRuleArgs{
Paths: pulumi.StringArray{
pulumi.String("/static"),
},
Service: static.ID(),
},
},
},
&compute.URLMapPathMatcherArgs{
Name: pulumi.String("otherpaths"),
DefaultService: static.ID(),
},
},
Tests: compute.URLMapTestArray{
&compute.URLMapTestArgs{
Service: static.ID(),
Host: pulumi.String("example.com"),
Path: pulumi.String("/home"),
},
},
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Gcp = Pulumi.Gcp;
return await Deployment.RunAsync(() =>
{
var @default = new Gcp.Compute.HttpHealthCheck("default", new()
{
Name = "health-check",
RequestPath = "/",
CheckIntervalSec = 1,
TimeoutSec = 1,
});
var login = new Gcp.Compute.BackendService("login", new()
{
Name = "login",
PortName = "http",
Protocol = "HTTP",
TimeoutSec = 10,
HealthChecks = @default.Id,
});
var staticBucket = new Gcp.Storage.Bucket("static", new()
{
Name = "static-asset-bucket",
Location = "US",
});
var @static = new Gcp.Compute.BackendBucket("static", new()
{
Name = "static-asset-backend-bucket",
BucketName = staticBucket.Name,
EnableCdn = true,
});
var urlmap = new Gcp.Compute.URLMap("urlmap", new()
{
Name = "urlmap",
Description = "a description",
DefaultService = @static.Id,
HostRules = new[]
{
new Gcp.Compute.Inputs.URLMapHostRuleArgs
{
Hosts = new[]
{
"mysite.com",
},
PathMatcher = "mysite",
},
new Gcp.Compute.Inputs.URLMapHostRuleArgs
{
Hosts = new[]
{
"myothersite.com",
},
PathMatcher = "otherpaths",
},
},
PathMatchers = new[]
{
new Gcp.Compute.Inputs.URLMapPathMatcherArgs
{
Name = "mysite",
DefaultService = @static.Id,
PathRules = new[]
{
new Gcp.Compute.Inputs.URLMapPathMatcherPathRuleArgs
{
Paths = new[]
{
"/home",
},
Service = @static.Id,
},
new Gcp.Compute.Inputs.URLMapPathMatcherPathRuleArgs
{
Paths = new[]
{
"/login",
},
Service = login.Id,
},
new Gcp.Compute.Inputs.URLMapPathMatcherPathRuleArgs
{
Paths = new[]
{
"/static",
},
Service = @static.Id,
},
},
},
new Gcp.Compute.Inputs.URLMapPathMatcherArgs
{
Name = "otherpaths",
DefaultService = @static.Id,
},
},
Tests = new[]
{
new Gcp.Compute.Inputs.URLMapTestArgs
{
Service = @static.Id,
Host = "example.com",
Path = "/home",
},
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.compute.HttpHealthCheck;
import com.pulumi.gcp.compute.HttpHealthCheckArgs;
import com.pulumi.gcp.compute.BackendService;
import com.pulumi.gcp.compute.BackendServiceArgs;
import com.pulumi.gcp.storage.Bucket;
import com.pulumi.gcp.storage.BucketArgs;
import com.pulumi.gcp.compute.BackendBucket;
import com.pulumi.gcp.compute.BackendBucketArgs;
import com.pulumi.gcp.compute.URLMap;
import com.pulumi.gcp.compute.URLMapArgs;
import com.pulumi.gcp.compute.inputs.URLMapHostRuleArgs;
import com.pulumi.gcp.compute.inputs.URLMapPathMatcherArgs;
import com.pulumi.gcp.compute.inputs.URLMapTestArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
public class App {
public static void main(String[] args) {
Pulumi.run(App::stack);
}
public static void stack(Context ctx) {
var default_ = new HttpHealthCheck("default", HttpHealthCheckArgs.builder()
.name("health-check")
.requestPath("/")
.checkIntervalSec(1)
.timeoutSec(1)
.build());
var login = new BackendService("login", BackendServiceArgs.builder()
.name("login")
.portName("http")
.protocol("HTTP")
.timeoutSec(10)
.healthChecks(default_.id())
.build());
var staticBucket = new Bucket("staticBucket", BucketArgs.builder()
.name("static-asset-bucket")
.location("US")
.build());
var static_ = new BackendBucket("static", BackendBucketArgs.builder()
.name("static-asset-backend-bucket")
.bucketName(staticBucket.name())
.enableCdn(true)
.build());
var urlmap = new URLMap("urlmap", URLMapArgs.builder()
.name("urlmap")
.description("a description")
.defaultService(static_.id())
.hostRules(
URLMapHostRuleArgs.builder()
.hosts("mysite.com")
.pathMatcher("mysite")
.build(),
URLMapHostRuleArgs.builder()
.hosts("myothersite.com")
.pathMatcher("otherpaths")
.build())
.pathMatchers(
URLMapPathMatcherArgs.builder()
.name("mysite")
.defaultService(static_.id())
.pathRules(
URLMapPathMatcherPathRuleArgs.builder()
.paths("/home")
.service(static_.id())
.build(),
URLMapPathMatcherPathRuleArgs.builder()
.paths("/login")
.service(login.id())
.build(),
URLMapPathMatcherPathRuleArgs.builder()
.paths("/static")
.service(static_.id())
.build())
.build(),
URLMapPathMatcherArgs.builder()
.name("otherpaths")
.defaultService(static_.id())
.build())
.tests(URLMapTestArgs.builder()
.service(static_.id())
.host("example.com")
.path("/home")
.build())
.build());
}
}
resources:
urlmap:
type: gcp:compute:URLMap
properties:
name: urlmap
description: a description
defaultService: ${static.id}
hostRules:
- hosts:
- mysite.com
pathMatcher: mysite
- hosts:
- myothersite.com
pathMatcher: otherpaths
pathMatchers:
- name: mysite
defaultService: ${static.id}
pathRules:
- paths:
- /home
service: ${static.id}
- paths:
- /login
service: ${login.id}
- paths:
- /static
service: ${static.id}
- name: otherpaths
defaultService: ${static.id}
tests:
- service: ${static.id}
host: example.com
path: /home
login:
type: gcp:compute:BackendService
properties:
name: login
portName: http
protocol: HTTP
timeoutSec: 10
healthChecks: ${default.id}
default:
type: gcp:compute:HttpHealthCheck
properties:
name: health-check
requestPath: /
checkIntervalSec: 1
timeoutSec: 1
static:
type: gcp:compute:BackendBucket
properties:
name: static-asset-backend-bucket
bucketName: ${staticBucket.name}
enableCdn: true
staticBucket:
type: gcp:storage:Bucket
name: static
properties:
name: static-asset-bucket
location: US
The hostRules property maps hostnames to path matchers. Each pathMatcher defines a defaultService and pathRules that route specific paths to different backends. The paths array specifies URL patterns, and service points to the backend that handles matching requests. This configuration routes /home and /static to Cloud Storage while sending /login to a backend service.
Route traffic based on HTTP headers
A/B testing and canary deployments often route users to different backend services based on request headers.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
const defaultHttpHealthCheck = new gcp.compute.HttpHealthCheck("default", {
name: "health-check",
requestPath: "/",
checkIntervalSec: 1,
timeoutSec: 1,
});
const _default = new gcp.compute.BackendService("default", {
name: "default",
portName: "http",
protocol: "HTTP",
timeoutSec: 10,
healthChecks: defaultHttpHealthCheck.id,
});
const service_a = new gcp.compute.BackendService("service-a", {
name: "service-a",
portName: "http",
protocol: "HTTP",
timeoutSec: 10,
healthChecks: defaultHttpHealthCheck.id,
});
const service_b = new gcp.compute.BackendService("service-b", {
name: "service-b",
portName: "http",
protocol: "HTTP",
timeoutSec: 10,
healthChecks: defaultHttpHealthCheck.id,
});
const urlmap = new gcp.compute.URLMap("urlmap", {
name: "urlmap",
description: "header-based routing example",
defaultService: _default.id,
hostRules: [{
hosts: ["*"],
pathMatcher: "allpaths",
}],
pathMatchers: [{
name: "allpaths",
defaultService: _default.id,
routeRules: [
{
priority: 1,
service: service_a.id,
matchRules: [{
prefixMatch: "/",
ignoreCase: true,
headerMatches: [{
headerName: "abtest",
exactMatch: "a",
}],
}],
},
{
priority: 2,
service: service_b.id,
matchRules: [{
ignoreCase: true,
prefixMatch: "/",
headerMatches: [{
headerName: "abtest",
exactMatch: "b",
}],
}],
},
],
}],
});
import pulumi
import pulumi_gcp as gcp
default_http_health_check = gcp.compute.HttpHealthCheck("default",
name="health-check",
request_path="/",
check_interval_sec=1,
timeout_sec=1)
default = gcp.compute.BackendService("default",
name="default",
port_name="http",
protocol="HTTP",
timeout_sec=10,
health_checks=default_http_health_check.id)
service_a = gcp.compute.BackendService("service-a",
name="service-a",
port_name="http",
protocol="HTTP",
timeout_sec=10,
health_checks=default_http_health_check.id)
service_b = gcp.compute.BackendService("service-b",
name="service-b",
port_name="http",
protocol="HTTP",
timeout_sec=10,
health_checks=default_http_health_check.id)
urlmap = gcp.compute.URLMap("urlmap",
name="urlmap",
description="header-based routing example",
default_service=default.id,
host_rules=[{
"hosts": ["*"],
"path_matcher": "allpaths",
}],
path_matchers=[{
"name": "allpaths",
"default_service": default.id,
"route_rules": [
{
"priority": 1,
"service": service_a.id,
"match_rules": [{
"prefix_match": "/",
"ignore_case": True,
"header_matches": [{
"header_name": "abtest",
"exact_match": "a",
}],
}],
},
{
"priority": 2,
"service": service_b.id,
"match_rules": [{
"ignore_case": True,
"prefix_match": "/",
"header_matches": [{
"header_name": "abtest",
"exact_match": "b",
}],
}],
},
],
}])
package main
import (
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/compute"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
defaultHttpHealthCheck, err := compute.NewHttpHealthCheck(ctx, "default", &compute.HttpHealthCheckArgs{
Name: pulumi.String("health-check"),
RequestPath: pulumi.String("/"),
CheckIntervalSec: pulumi.Int(1),
TimeoutSec: pulumi.Int(1),
})
if err != nil {
return err
}
_default, err := compute.NewBackendService(ctx, "default", &compute.BackendServiceArgs{
Name: pulumi.String("default"),
PortName: pulumi.String("http"),
Protocol: pulumi.String("HTTP"),
TimeoutSec: pulumi.Int(10),
HealthChecks: defaultHttpHealthCheck.ID(),
})
if err != nil {
return err
}
service_a, err := compute.NewBackendService(ctx, "service-a", &compute.BackendServiceArgs{
Name: pulumi.String("service-a"),
PortName: pulumi.String("http"),
Protocol: pulumi.String("HTTP"),
TimeoutSec: pulumi.Int(10),
HealthChecks: defaultHttpHealthCheck.ID(),
})
if err != nil {
return err
}
service_b, err := compute.NewBackendService(ctx, "service-b", &compute.BackendServiceArgs{
Name: pulumi.String("service-b"),
PortName: pulumi.String("http"),
Protocol: pulumi.String("HTTP"),
TimeoutSec: pulumi.Int(10),
HealthChecks: defaultHttpHealthCheck.ID(),
})
if err != nil {
return err
}
_, err = compute.NewURLMap(ctx, "urlmap", &compute.URLMapArgs{
Name: pulumi.String("urlmap"),
Description: pulumi.String("header-based routing example"),
DefaultService: _default.ID(),
HostRules: compute.URLMapHostRuleArray{
&compute.URLMapHostRuleArgs{
Hosts: pulumi.StringArray{
pulumi.String("*"),
},
PathMatcher: pulumi.String("allpaths"),
},
},
PathMatchers: compute.URLMapPathMatcherArray{
&compute.URLMapPathMatcherArgs{
Name: pulumi.String("allpaths"),
DefaultService: _default.ID(),
RouteRules: compute.URLMapPathMatcherRouteRuleArray{
&compute.URLMapPathMatcherRouteRuleArgs{
Priority: pulumi.Int(1),
Service: service_a.ID(),
MatchRules: compute.URLMapPathMatcherRouteRuleMatchRuleArray{
&compute.URLMapPathMatcherRouteRuleMatchRuleArgs{
PrefixMatch: pulumi.String("/"),
IgnoreCase: pulumi.Bool(true),
HeaderMatches: compute.URLMapPathMatcherRouteRuleMatchRuleHeaderMatchArray{
&compute.URLMapPathMatcherRouteRuleMatchRuleHeaderMatchArgs{
HeaderName: pulumi.String("abtest"),
ExactMatch: pulumi.String("a"),
},
},
},
},
},
&compute.URLMapPathMatcherRouteRuleArgs{
Priority: pulumi.Int(2),
Service: service_b.ID(),
MatchRules: compute.URLMapPathMatcherRouteRuleMatchRuleArray{
&compute.URLMapPathMatcherRouteRuleMatchRuleArgs{
IgnoreCase: pulumi.Bool(true),
PrefixMatch: pulumi.String("/"),
HeaderMatches: compute.URLMapPathMatcherRouteRuleMatchRuleHeaderMatchArray{
&compute.URLMapPathMatcherRouteRuleMatchRuleHeaderMatchArgs{
HeaderName: pulumi.String("abtest"),
ExactMatch: pulumi.String("b"),
},
},
},
},
},
},
},
},
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Gcp = Pulumi.Gcp;
return await Deployment.RunAsync(() =>
{
var defaultHttpHealthCheck = new Gcp.Compute.HttpHealthCheck("default", new()
{
Name = "health-check",
RequestPath = "/",
CheckIntervalSec = 1,
TimeoutSec = 1,
});
var @default = new Gcp.Compute.BackendService("default", new()
{
Name = "default",
PortName = "http",
Protocol = "HTTP",
TimeoutSec = 10,
HealthChecks = defaultHttpHealthCheck.Id,
});
var service_a = new Gcp.Compute.BackendService("service-a", new()
{
Name = "service-a",
PortName = "http",
Protocol = "HTTP",
TimeoutSec = 10,
HealthChecks = defaultHttpHealthCheck.Id,
});
var service_b = new Gcp.Compute.BackendService("service-b", new()
{
Name = "service-b",
PortName = "http",
Protocol = "HTTP",
TimeoutSec = 10,
HealthChecks = defaultHttpHealthCheck.Id,
});
var urlmap = new Gcp.Compute.URLMap("urlmap", new()
{
Name = "urlmap",
Description = "header-based routing example",
DefaultService = @default.Id,
HostRules = new[]
{
new Gcp.Compute.Inputs.URLMapHostRuleArgs
{
Hosts = new[]
{
"*",
},
PathMatcher = "allpaths",
},
},
PathMatchers = new[]
{
new Gcp.Compute.Inputs.URLMapPathMatcherArgs
{
Name = "allpaths",
DefaultService = @default.Id,
RouteRules = new[]
{
new Gcp.Compute.Inputs.URLMapPathMatcherRouteRuleArgs
{
Priority = 1,
Service = service_a.Id,
MatchRules = new[]
{
new Gcp.Compute.Inputs.URLMapPathMatcherRouteRuleMatchRuleArgs
{
PrefixMatch = "/",
IgnoreCase = true,
HeaderMatches = new[]
{
new Gcp.Compute.Inputs.URLMapPathMatcherRouteRuleMatchRuleHeaderMatchArgs
{
HeaderName = "abtest",
ExactMatch = "a",
},
},
},
},
},
new Gcp.Compute.Inputs.URLMapPathMatcherRouteRuleArgs
{
Priority = 2,
Service = service_b.Id,
MatchRules = new[]
{
new Gcp.Compute.Inputs.URLMapPathMatcherRouteRuleMatchRuleArgs
{
IgnoreCase = true,
PrefixMatch = "/",
HeaderMatches = new[]
{
new Gcp.Compute.Inputs.URLMapPathMatcherRouteRuleMatchRuleHeaderMatchArgs
{
HeaderName = "abtest",
ExactMatch = "b",
},
},
},
},
},
},
},
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.compute.HttpHealthCheck;
import com.pulumi.gcp.compute.HttpHealthCheckArgs;
import com.pulumi.gcp.compute.BackendService;
import com.pulumi.gcp.compute.BackendServiceArgs;
import com.pulumi.gcp.compute.URLMap;
import com.pulumi.gcp.compute.URLMapArgs;
import com.pulumi.gcp.compute.inputs.URLMapHostRuleArgs;
import com.pulumi.gcp.compute.inputs.URLMapPathMatcherArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
public class App {
public static void main(String[] args) {
Pulumi.run(App::stack);
}
public static void stack(Context ctx) {
var defaultHttpHealthCheck = new HttpHealthCheck("defaultHttpHealthCheck", HttpHealthCheckArgs.builder()
.name("health-check")
.requestPath("/")
.checkIntervalSec(1)
.timeoutSec(1)
.build());
var default_ = new BackendService("default", BackendServiceArgs.builder()
.name("default")
.portName("http")
.protocol("HTTP")
.timeoutSec(10)
.healthChecks(defaultHttpHealthCheck.id())
.build());
var service_a = new BackendService("service-a", BackendServiceArgs.builder()
.name("service-a")
.portName("http")
.protocol("HTTP")
.timeoutSec(10)
.healthChecks(defaultHttpHealthCheck.id())
.build());
var service_b = new BackendService("service-b", BackendServiceArgs.builder()
.name("service-b")
.portName("http")
.protocol("HTTP")
.timeoutSec(10)
.healthChecks(defaultHttpHealthCheck.id())
.build());
var urlmap = new URLMap("urlmap", URLMapArgs.builder()
.name("urlmap")
.description("header-based routing example")
.defaultService(default_.id())
.hostRules(URLMapHostRuleArgs.builder()
.hosts("*")
.pathMatcher("allpaths")
.build())
.pathMatchers(URLMapPathMatcherArgs.builder()
.name("allpaths")
.defaultService(default_.id())
.routeRules(
URLMapPathMatcherRouteRuleArgs.builder()
.priority(1)
.service(service_a.id())
.matchRules(URLMapPathMatcherRouteRuleMatchRuleArgs.builder()
.prefixMatch("/")
.ignoreCase(true)
.headerMatches(URLMapPathMatcherRouteRuleMatchRuleHeaderMatchArgs.builder()
.headerName("abtest")
.exactMatch("a")
.build())
.build())
.build(),
URLMapPathMatcherRouteRuleArgs.builder()
.priority(2)
.service(service_b.id())
.matchRules(URLMapPathMatcherRouteRuleMatchRuleArgs.builder()
.ignoreCase(true)
.prefixMatch("/")
.headerMatches(URLMapPathMatcherRouteRuleMatchRuleHeaderMatchArgs.builder()
.headerName("abtest")
.exactMatch("b")
.build())
.build())
.build())
.build())
.build());
}
}
resources:
urlmap:
type: gcp:compute:URLMap
properties:
name: urlmap
description: header-based routing example
defaultService: ${default.id}
hostRules:
- hosts:
- '*'
pathMatcher: allpaths
pathMatchers:
- name: allpaths
defaultService: ${default.id}
routeRules:
- priority: 1
service: ${["service-a"].id}
matchRules:
- prefixMatch: /
ignoreCase: true
headerMatches:
- headerName: abtest
exactMatch: a
- priority: 2
service: ${["service-b"].id}
matchRules:
- ignoreCase: true
prefixMatch: /
headerMatches:
- headerName: abtest
exactMatch: b
default:
type: gcp:compute:BackendService
properties:
name: default
portName: http
protocol: HTTP
timeoutSec: 10
healthChecks: ${defaultHttpHealthCheck.id}
service-a:
type: gcp:compute:BackendService
properties:
name: service-a
portName: http
protocol: HTTP
timeoutSec: 10
healthChecks: ${defaultHttpHealthCheck.id}
service-b:
type: gcp:compute:BackendService
properties:
name: service-b
portName: http
protocol: HTTP
timeoutSec: 10
healthChecks: ${defaultHttpHealthCheck.id}
defaultHttpHealthCheck:
type: gcp:compute:HttpHealthCheck
name: default
properties:
name: health-check
requestPath: /
checkIntervalSec: 1
timeoutSec: 1
The routeRules property defines ordered routing logic. Each rule has a priority (lower numbers evaluate first) and matchRules that inspect request properties. The headerMatches array checks header values; when the abtest header equals a, traffic goes to service_a. The prefixMatch ensures the rule applies to all paths starting with /.
Route traffic based on query parameters
Similar to header-based routing, query parameters can control which backend receives a request, enabling feature flags and gradual rollouts controlled via URL parameters.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
const defaultHttpHealthCheck = new gcp.compute.HttpHealthCheck("default", {
name: "health-check",
requestPath: "/",
checkIntervalSec: 1,
timeoutSec: 1,
});
const _default = new gcp.compute.BackendService("default", {
name: "default",
portName: "http",
protocol: "HTTP",
timeoutSec: 10,
healthChecks: defaultHttpHealthCheck.id,
});
const service_a = new gcp.compute.BackendService("service-a", {
name: "service-a",
portName: "http",
protocol: "HTTP",
timeoutSec: 10,
healthChecks: defaultHttpHealthCheck.id,
});
const service_b = new gcp.compute.BackendService("service-b", {
name: "service-b",
portName: "http",
protocol: "HTTP",
timeoutSec: 10,
healthChecks: defaultHttpHealthCheck.id,
});
const urlmap = new gcp.compute.URLMap("urlmap", {
name: "urlmap",
description: "parameter-based routing example",
defaultService: _default.id,
hostRules: [{
hosts: ["*"],
pathMatcher: "allpaths",
}],
pathMatchers: [{
name: "allpaths",
defaultService: _default.id,
routeRules: [
{
priority: 1,
service: service_a.id,
matchRules: [{
prefixMatch: "/",
ignoreCase: true,
queryParameterMatches: [{
name: "abtest",
exactMatch: "a",
}],
}],
},
{
priority: 2,
service: service_b.id,
matchRules: [{
ignoreCase: true,
prefixMatch: "/",
queryParameterMatches: [{
name: "abtest",
exactMatch: "b",
}],
}],
},
],
}],
});
import pulumi
import pulumi_gcp as gcp
default_http_health_check = gcp.compute.HttpHealthCheck("default",
name="health-check",
request_path="/",
check_interval_sec=1,
timeout_sec=1)
default = gcp.compute.BackendService("default",
name="default",
port_name="http",
protocol="HTTP",
timeout_sec=10,
health_checks=default_http_health_check.id)
service_a = gcp.compute.BackendService("service-a",
name="service-a",
port_name="http",
protocol="HTTP",
timeout_sec=10,
health_checks=default_http_health_check.id)
service_b = gcp.compute.BackendService("service-b",
name="service-b",
port_name="http",
protocol="HTTP",
timeout_sec=10,
health_checks=default_http_health_check.id)
urlmap = gcp.compute.URLMap("urlmap",
name="urlmap",
description="parameter-based routing example",
default_service=default.id,
host_rules=[{
"hosts": ["*"],
"path_matcher": "allpaths",
}],
path_matchers=[{
"name": "allpaths",
"default_service": default.id,
"route_rules": [
{
"priority": 1,
"service": service_a.id,
"match_rules": [{
"prefix_match": "/",
"ignore_case": True,
"query_parameter_matches": [{
"name": "abtest",
"exact_match": "a",
}],
}],
},
{
"priority": 2,
"service": service_b.id,
"match_rules": [{
"ignore_case": True,
"prefix_match": "/",
"query_parameter_matches": [{
"name": "abtest",
"exact_match": "b",
}],
}],
},
],
}])
package main
import (
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/compute"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
defaultHttpHealthCheck, err := compute.NewHttpHealthCheck(ctx, "default", &compute.HttpHealthCheckArgs{
Name: pulumi.String("health-check"),
RequestPath: pulumi.String("/"),
CheckIntervalSec: pulumi.Int(1),
TimeoutSec: pulumi.Int(1),
})
if err != nil {
return err
}
_default, err := compute.NewBackendService(ctx, "default", &compute.BackendServiceArgs{
Name: pulumi.String("default"),
PortName: pulumi.String("http"),
Protocol: pulumi.String("HTTP"),
TimeoutSec: pulumi.Int(10),
HealthChecks: defaultHttpHealthCheck.ID(),
})
if err != nil {
return err
}
service_a, err := compute.NewBackendService(ctx, "service-a", &compute.BackendServiceArgs{
Name: pulumi.String("service-a"),
PortName: pulumi.String("http"),
Protocol: pulumi.String("HTTP"),
TimeoutSec: pulumi.Int(10),
HealthChecks: defaultHttpHealthCheck.ID(),
})
if err != nil {
return err
}
service_b, err := compute.NewBackendService(ctx, "service-b", &compute.BackendServiceArgs{
Name: pulumi.String("service-b"),
PortName: pulumi.String("http"),
Protocol: pulumi.String("HTTP"),
TimeoutSec: pulumi.Int(10),
HealthChecks: defaultHttpHealthCheck.ID(),
})
if err != nil {
return err
}
_, err = compute.NewURLMap(ctx, "urlmap", &compute.URLMapArgs{
Name: pulumi.String("urlmap"),
Description: pulumi.String("parameter-based routing example"),
DefaultService: _default.ID(),
HostRules: compute.URLMapHostRuleArray{
&compute.URLMapHostRuleArgs{
Hosts: pulumi.StringArray{
pulumi.String("*"),
},
PathMatcher: pulumi.String("allpaths"),
},
},
PathMatchers: compute.URLMapPathMatcherArray{
&compute.URLMapPathMatcherArgs{
Name: pulumi.String("allpaths"),
DefaultService: _default.ID(),
RouteRules: compute.URLMapPathMatcherRouteRuleArray{
&compute.URLMapPathMatcherRouteRuleArgs{
Priority: pulumi.Int(1),
Service: service_a.ID(),
MatchRules: compute.URLMapPathMatcherRouteRuleMatchRuleArray{
&compute.URLMapPathMatcherRouteRuleMatchRuleArgs{
PrefixMatch: pulumi.String("/"),
IgnoreCase: pulumi.Bool(true),
QueryParameterMatches: compute.URLMapPathMatcherRouteRuleMatchRuleQueryParameterMatchArray{
&compute.URLMapPathMatcherRouteRuleMatchRuleQueryParameterMatchArgs{
Name: pulumi.String("abtest"),
ExactMatch: pulumi.String("a"),
},
},
},
},
},
&compute.URLMapPathMatcherRouteRuleArgs{
Priority: pulumi.Int(2),
Service: service_b.ID(),
MatchRules: compute.URLMapPathMatcherRouteRuleMatchRuleArray{
&compute.URLMapPathMatcherRouteRuleMatchRuleArgs{
IgnoreCase: pulumi.Bool(true),
PrefixMatch: pulumi.String("/"),
QueryParameterMatches: compute.URLMapPathMatcherRouteRuleMatchRuleQueryParameterMatchArray{
&compute.URLMapPathMatcherRouteRuleMatchRuleQueryParameterMatchArgs{
Name: pulumi.String("abtest"),
ExactMatch: pulumi.String("b"),
},
},
},
},
},
},
},
},
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Gcp = Pulumi.Gcp;
return await Deployment.RunAsync(() =>
{
var defaultHttpHealthCheck = new Gcp.Compute.HttpHealthCheck("default", new()
{
Name = "health-check",
RequestPath = "/",
CheckIntervalSec = 1,
TimeoutSec = 1,
});
var @default = new Gcp.Compute.BackendService("default", new()
{
Name = "default",
PortName = "http",
Protocol = "HTTP",
TimeoutSec = 10,
HealthChecks = defaultHttpHealthCheck.Id,
});
var service_a = new Gcp.Compute.BackendService("service-a", new()
{
Name = "service-a",
PortName = "http",
Protocol = "HTTP",
TimeoutSec = 10,
HealthChecks = defaultHttpHealthCheck.Id,
});
var service_b = new Gcp.Compute.BackendService("service-b", new()
{
Name = "service-b",
PortName = "http",
Protocol = "HTTP",
TimeoutSec = 10,
HealthChecks = defaultHttpHealthCheck.Id,
});
var urlmap = new Gcp.Compute.URLMap("urlmap", new()
{
Name = "urlmap",
Description = "parameter-based routing example",
DefaultService = @default.Id,
HostRules = new[]
{
new Gcp.Compute.Inputs.URLMapHostRuleArgs
{
Hosts = new[]
{
"*",
},
PathMatcher = "allpaths",
},
},
PathMatchers = new[]
{
new Gcp.Compute.Inputs.URLMapPathMatcherArgs
{
Name = "allpaths",
DefaultService = @default.Id,
RouteRules = new[]
{
new Gcp.Compute.Inputs.URLMapPathMatcherRouteRuleArgs
{
Priority = 1,
Service = service_a.Id,
MatchRules = new[]
{
new Gcp.Compute.Inputs.URLMapPathMatcherRouteRuleMatchRuleArgs
{
PrefixMatch = "/",
IgnoreCase = true,
QueryParameterMatches = new[]
{
new Gcp.Compute.Inputs.URLMapPathMatcherRouteRuleMatchRuleQueryParameterMatchArgs
{
Name = "abtest",
ExactMatch = "a",
},
},
},
},
},
new Gcp.Compute.Inputs.URLMapPathMatcherRouteRuleArgs
{
Priority = 2,
Service = service_b.Id,
MatchRules = new[]
{
new Gcp.Compute.Inputs.URLMapPathMatcherRouteRuleMatchRuleArgs
{
IgnoreCase = true,
PrefixMatch = "/",
QueryParameterMatches = new[]
{
new Gcp.Compute.Inputs.URLMapPathMatcherRouteRuleMatchRuleQueryParameterMatchArgs
{
Name = "abtest",
ExactMatch = "b",
},
},
},
},
},
},
},
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.compute.HttpHealthCheck;
import com.pulumi.gcp.compute.HttpHealthCheckArgs;
import com.pulumi.gcp.compute.BackendService;
import com.pulumi.gcp.compute.BackendServiceArgs;
import com.pulumi.gcp.compute.URLMap;
import com.pulumi.gcp.compute.URLMapArgs;
import com.pulumi.gcp.compute.inputs.URLMapHostRuleArgs;
import com.pulumi.gcp.compute.inputs.URLMapPathMatcherArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
public class App {
public static void main(String[] args) {
Pulumi.run(App::stack);
}
public static void stack(Context ctx) {
var defaultHttpHealthCheck = new HttpHealthCheck("defaultHttpHealthCheck", HttpHealthCheckArgs.builder()
.name("health-check")
.requestPath("/")
.checkIntervalSec(1)
.timeoutSec(1)
.build());
var default_ = new BackendService("default", BackendServiceArgs.builder()
.name("default")
.portName("http")
.protocol("HTTP")
.timeoutSec(10)
.healthChecks(defaultHttpHealthCheck.id())
.build());
var service_a = new BackendService("service-a", BackendServiceArgs.builder()
.name("service-a")
.portName("http")
.protocol("HTTP")
.timeoutSec(10)
.healthChecks(defaultHttpHealthCheck.id())
.build());
var service_b = new BackendService("service-b", BackendServiceArgs.builder()
.name("service-b")
.portName("http")
.protocol("HTTP")
.timeoutSec(10)
.healthChecks(defaultHttpHealthCheck.id())
.build());
var urlmap = new URLMap("urlmap", URLMapArgs.builder()
.name("urlmap")
.description("parameter-based routing example")
.defaultService(default_.id())
.hostRules(URLMapHostRuleArgs.builder()
.hosts("*")
.pathMatcher("allpaths")
.build())
.pathMatchers(URLMapPathMatcherArgs.builder()
.name("allpaths")
.defaultService(default_.id())
.routeRules(
URLMapPathMatcherRouteRuleArgs.builder()
.priority(1)
.service(service_a.id())
.matchRules(URLMapPathMatcherRouteRuleMatchRuleArgs.builder()
.prefixMatch("/")
.ignoreCase(true)
.queryParameterMatches(URLMapPathMatcherRouteRuleMatchRuleQueryParameterMatchArgs.builder()
.name("abtest")
.exactMatch("a")
.build())
.build())
.build(),
URLMapPathMatcherRouteRuleArgs.builder()
.priority(2)
.service(service_b.id())
.matchRules(URLMapPathMatcherRouteRuleMatchRuleArgs.builder()
.ignoreCase(true)
.prefixMatch("/")
.queryParameterMatches(URLMapPathMatcherRouteRuleMatchRuleQueryParameterMatchArgs.builder()
.name("abtest")
.exactMatch("b")
.build())
.build())
.build())
.build())
.build());
}
}
resources:
urlmap:
type: gcp:compute:URLMap
properties:
name: urlmap
description: parameter-based routing example
defaultService: ${default.id}
hostRules:
- hosts:
- '*'
pathMatcher: allpaths
pathMatchers:
- name: allpaths
defaultService: ${default.id}
routeRules:
- priority: 1
service: ${["service-a"].id}
matchRules:
- prefixMatch: /
ignoreCase: true
queryParameterMatches:
- name: abtest
exactMatch: a
- priority: 2
service: ${["service-b"].id}
matchRules:
- ignoreCase: true
prefixMatch: /
queryParameterMatches:
- name: abtest
exactMatch: b
default:
type: gcp:compute:BackendService
properties:
name: default
portName: http
protocol: HTTP
timeoutSec: 10
healthChecks: ${defaultHttpHealthCheck.id}
service-a:
type: gcp:compute:BackendService
properties:
name: service-a
portName: http
protocol: HTTP
timeoutSec: 10
healthChecks: ${defaultHttpHealthCheck.id}
service-b:
type: gcp:compute:BackendService
properties:
name: service-b
portName: http
protocol: HTTP
timeoutSec: 10
healthChecks: ${defaultHttpHealthCheck.id}
defaultHttpHealthCheck:
type: gcp:compute:HttpHealthCheck
name: default
properties:
name: health-check
requestPath: /
checkIntervalSec: 1
timeoutSec: 1
The queryParameterMatches array inspects URL query strings. When the abtest parameter equals a, the load balancer routes to service_a. This provides an alternative to header-based routing that users can control directly through URLs.
Transform requests with header manipulation and redirects
Traffic Director configurations often need to modify requests in flight, adding or removing headers before forwarding to backends or redirecting to different URLs.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
const _default = new gcp.compute.HealthCheck("default", {
name: "health-check",
httpHealthCheck: {
port: 80,
},
});
const home = new gcp.compute.BackendService("home", {
name: "home",
portName: "http",
protocol: "HTTP",
timeoutSec: 10,
healthChecks: _default.id,
loadBalancingScheme: "INTERNAL_SELF_MANAGED",
});
const urlmap = new gcp.compute.URLMap("urlmap", {
name: "urlmap",
description: "a description",
defaultService: home.id,
hostRules: [{
hosts: ["mysite.com"],
pathMatcher: "allpaths",
}],
pathMatchers: [{
name: "allpaths",
defaultService: home.id,
routeRules: [{
priority: 1,
headerAction: {
requestHeadersToRemoves: ["RemoveMe2"],
requestHeadersToAdds: [{
headerName: "AddSomethingElse",
headerValue: "MyOtherValue",
replace: true,
}],
responseHeadersToRemoves: ["RemoveMe3"],
responseHeadersToAdds: [{
headerName: "AddMe",
headerValue: "MyValue",
replace: false,
}],
},
matchRules: [{
fullPathMatch: "a full path",
headerMatches: [{
headerName: "someheader",
exactMatch: "match this exactly",
invertMatch: true,
}],
ignoreCase: true,
metadataFilters: [{
filterMatchCriteria: "MATCH_ANY",
filterLabels: [{
name: "PLANET",
value: "MARS",
}],
}],
queryParameterMatches: [{
name: "a query parameter",
presentMatch: true,
}],
}],
urlRedirect: {
hostRedirect: "A host",
httpsRedirect: false,
pathRedirect: "some/path",
redirectResponseCode: "TEMPORARY_REDIRECT",
stripQuery: true,
},
}],
}],
tests: [{
service: home.id,
host: "hi.com",
path: "/home",
}],
});
import pulumi
import pulumi_gcp as gcp
default = gcp.compute.HealthCheck("default",
name="health-check",
http_health_check={
"port": 80,
})
home = gcp.compute.BackendService("home",
name="home",
port_name="http",
protocol="HTTP",
timeout_sec=10,
health_checks=default.id,
load_balancing_scheme="INTERNAL_SELF_MANAGED")
urlmap = gcp.compute.URLMap("urlmap",
name="urlmap",
description="a description",
default_service=home.id,
host_rules=[{
"hosts": ["mysite.com"],
"path_matcher": "allpaths",
}],
path_matchers=[{
"name": "allpaths",
"default_service": home.id,
"route_rules": [{
"priority": 1,
"header_action": {
"request_headers_to_removes": ["RemoveMe2"],
"request_headers_to_adds": [{
"header_name": "AddSomethingElse",
"header_value": "MyOtherValue",
"replace": True,
}],
"response_headers_to_removes": ["RemoveMe3"],
"response_headers_to_adds": [{
"header_name": "AddMe",
"header_value": "MyValue",
"replace": False,
}],
},
"match_rules": [{
"full_path_match": "a full path",
"header_matches": [{
"header_name": "someheader",
"exact_match": "match this exactly",
"invert_match": True,
}],
"ignore_case": True,
"metadata_filters": [{
"filter_match_criteria": "MATCH_ANY",
"filter_labels": [{
"name": "PLANET",
"value": "MARS",
}],
}],
"query_parameter_matches": [{
"name": "a query parameter",
"present_match": True,
}],
}],
"url_redirect": {
"host_redirect": "A host",
"https_redirect": False,
"path_redirect": "some/path",
"redirect_response_code": "TEMPORARY_REDIRECT",
"strip_query": True,
},
}],
}],
tests=[{
"service": home.id,
"host": "hi.com",
"path": "/home",
}])
package main
import (
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/compute"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_default, err := compute.NewHealthCheck(ctx, "default", &compute.HealthCheckArgs{
Name: pulumi.String("health-check"),
HttpHealthCheck: &compute.HealthCheckHttpHealthCheckArgs{
Port: pulumi.Int(80),
},
})
if err != nil {
return err
}
home, err := compute.NewBackendService(ctx, "home", &compute.BackendServiceArgs{
Name: pulumi.String("home"),
PortName: pulumi.String("http"),
Protocol: pulumi.String("HTTP"),
TimeoutSec: pulumi.Int(10),
HealthChecks: _default.ID(),
LoadBalancingScheme: pulumi.String("INTERNAL_SELF_MANAGED"),
})
if err != nil {
return err
}
_, err = compute.NewURLMap(ctx, "urlmap", &compute.URLMapArgs{
Name: pulumi.String("urlmap"),
Description: pulumi.String("a description"),
DefaultService: home.ID(),
HostRules: compute.URLMapHostRuleArray{
&compute.URLMapHostRuleArgs{
Hosts: pulumi.StringArray{
pulumi.String("mysite.com"),
},
PathMatcher: pulumi.String("allpaths"),
},
},
PathMatchers: compute.URLMapPathMatcherArray{
&compute.URLMapPathMatcherArgs{
Name: pulumi.String("allpaths"),
DefaultService: home.ID(),
RouteRules: compute.URLMapPathMatcherRouteRuleArray{
&compute.URLMapPathMatcherRouteRuleArgs{
Priority: pulumi.Int(1),
HeaderAction: &compute.URLMapPathMatcherRouteRuleHeaderActionArgs{
RequestHeadersToRemoves: pulumi.StringArray{
pulumi.String("RemoveMe2"),
},
RequestHeadersToAdds: compute.URLMapPathMatcherRouteRuleHeaderActionRequestHeadersToAddArray{
&compute.URLMapPathMatcherRouteRuleHeaderActionRequestHeadersToAddArgs{
HeaderName: pulumi.String("AddSomethingElse"),
HeaderValue: pulumi.String("MyOtherValue"),
Replace: pulumi.Bool(true),
},
},
ResponseHeadersToRemoves: pulumi.StringArray{
pulumi.String("RemoveMe3"),
},
ResponseHeadersToAdds: compute.URLMapPathMatcherRouteRuleHeaderActionResponseHeadersToAddArray{
&compute.URLMapPathMatcherRouteRuleHeaderActionResponseHeadersToAddArgs{
HeaderName: pulumi.String("AddMe"),
HeaderValue: pulumi.String("MyValue"),
Replace: pulumi.Bool(false),
},
},
},
MatchRules: compute.URLMapPathMatcherRouteRuleMatchRuleArray{
&compute.URLMapPathMatcherRouteRuleMatchRuleArgs{
FullPathMatch: pulumi.String("a full path"),
HeaderMatches: compute.URLMapPathMatcherRouteRuleMatchRuleHeaderMatchArray{
&compute.URLMapPathMatcherRouteRuleMatchRuleHeaderMatchArgs{
HeaderName: pulumi.String("someheader"),
ExactMatch: pulumi.String("match this exactly"),
InvertMatch: pulumi.Bool(true),
},
},
IgnoreCase: pulumi.Bool(true),
MetadataFilters: compute.URLMapPathMatcherRouteRuleMatchRuleMetadataFilterArray{
&compute.URLMapPathMatcherRouteRuleMatchRuleMetadataFilterArgs{
FilterMatchCriteria: pulumi.String("MATCH_ANY"),
FilterLabels: compute.URLMapPathMatcherRouteRuleMatchRuleMetadataFilterFilterLabelArray{
&compute.URLMapPathMatcherRouteRuleMatchRuleMetadataFilterFilterLabelArgs{
Name: pulumi.String("PLANET"),
Value: pulumi.String("MARS"),
},
},
},
},
QueryParameterMatches: compute.URLMapPathMatcherRouteRuleMatchRuleQueryParameterMatchArray{
&compute.URLMapPathMatcherRouteRuleMatchRuleQueryParameterMatchArgs{
Name: pulumi.String("a query parameter"),
PresentMatch: pulumi.Bool(true),
},
},
},
},
UrlRedirect: &compute.URLMapPathMatcherRouteRuleUrlRedirectArgs{
HostRedirect: pulumi.String("A host"),
HttpsRedirect: pulumi.Bool(false),
PathRedirect: pulumi.String("some/path"),
RedirectResponseCode: pulumi.String("TEMPORARY_REDIRECT"),
StripQuery: pulumi.Bool(true),
},
},
},
},
},
Tests: compute.URLMapTestArray{
&compute.URLMapTestArgs{
Service: home.ID(),
Host: pulumi.String("hi.com"),
Path: pulumi.String("/home"),
},
},
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Gcp = Pulumi.Gcp;
return await Deployment.RunAsync(() =>
{
var @default = new Gcp.Compute.HealthCheck("default", new()
{
Name = "health-check",
HttpHealthCheck = new Gcp.Compute.Inputs.HealthCheckHttpHealthCheckArgs
{
Port = 80,
},
});
var home = new Gcp.Compute.BackendService("home", new()
{
Name = "home",
PortName = "http",
Protocol = "HTTP",
TimeoutSec = 10,
HealthChecks = @default.Id,
LoadBalancingScheme = "INTERNAL_SELF_MANAGED",
});
var urlmap = new Gcp.Compute.URLMap("urlmap", new()
{
Name = "urlmap",
Description = "a description",
DefaultService = home.Id,
HostRules = new[]
{
new Gcp.Compute.Inputs.URLMapHostRuleArgs
{
Hosts = new[]
{
"mysite.com",
},
PathMatcher = "allpaths",
},
},
PathMatchers = new[]
{
new Gcp.Compute.Inputs.URLMapPathMatcherArgs
{
Name = "allpaths",
DefaultService = home.Id,
RouteRules = new[]
{
new Gcp.Compute.Inputs.URLMapPathMatcherRouteRuleArgs
{
Priority = 1,
HeaderAction = new Gcp.Compute.Inputs.URLMapPathMatcherRouteRuleHeaderActionArgs
{
RequestHeadersToRemoves = new[]
{
"RemoveMe2",
},
RequestHeadersToAdds = new[]
{
new Gcp.Compute.Inputs.URLMapPathMatcherRouteRuleHeaderActionRequestHeadersToAddArgs
{
HeaderName = "AddSomethingElse",
HeaderValue = "MyOtherValue",
Replace = true,
},
},
ResponseHeadersToRemoves = new[]
{
"RemoveMe3",
},
ResponseHeadersToAdds = new[]
{
new Gcp.Compute.Inputs.URLMapPathMatcherRouteRuleHeaderActionResponseHeadersToAddArgs
{
HeaderName = "AddMe",
HeaderValue = "MyValue",
Replace = false,
},
},
},
MatchRules = new[]
{
new Gcp.Compute.Inputs.URLMapPathMatcherRouteRuleMatchRuleArgs
{
FullPathMatch = "a full path",
HeaderMatches = new[]
{
new Gcp.Compute.Inputs.URLMapPathMatcherRouteRuleMatchRuleHeaderMatchArgs
{
HeaderName = "someheader",
ExactMatch = "match this exactly",
InvertMatch = true,
},
},
IgnoreCase = true,
MetadataFilters = new[]
{
new Gcp.Compute.Inputs.URLMapPathMatcherRouteRuleMatchRuleMetadataFilterArgs
{
FilterMatchCriteria = "MATCH_ANY",
FilterLabels = new[]
{
new Gcp.Compute.Inputs.URLMapPathMatcherRouteRuleMatchRuleMetadataFilterFilterLabelArgs
{
Name = "PLANET",
Value = "MARS",
},
},
},
},
QueryParameterMatches = new[]
{
new Gcp.Compute.Inputs.URLMapPathMatcherRouteRuleMatchRuleQueryParameterMatchArgs
{
Name = "a query parameter",
PresentMatch = true,
},
},
},
},
UrlRedirect = new Gcp.Compute.Inputs.URLMapPathMatcherRouteRuleUrlRedirectArgs
{
HostRedirect = "A host",
HttpsRedirect = false,
PathRedirect = "some/path",
RedirectResponseCode = "TEMPORARY_REDIRECT",
StripQuery = true,
},
},
},
},
},
Tests = new[]
{
new Gcp.Compute.Inputs.URLMapTestArgs
{
Service = home.Id,
Host = "hi.com",
Path = "/home",
},
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.compute.HealthCheck;
import com.pulumi.gcp.compute.HealthCheckArgs;
import com.pulumi.gcp.compute.inputs.HealthCheckHttpHealthCheckArgs;
import com.pulumi.gcp.compute.BackendService;
import com.pulumi.gcp.compute.BackendServiceArgs;
import com.pulumi.gcp.compute.URLMap;
import com.pulumi.gcp.compute.URLMapArgs;
import com.pulumi.gcp.compute.inputs.URLMapHostRuleArgs;
import com.pulumi.gcp.compute.inputs.URLMapPathMatcherArgs;
import com.pulumi.gcp.compute.inputs.URLMapTestArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
public class App {
public static void main(String[] args) {
Pulumi.run(App::stack);
}
public static void stack(Context ctx) {
var default_ = new HealthCheck("default", HealthCheckArgs.builder()
.name("health-check")
.httpHealthCheck(HealthCheckHttpHealthCheckArgs.builder()
.port(80)
.build())
.build());
var home = new BackendService("home", BackendServiceArgs.builder()
.name("home")
.portName("http")
.protocol("HTTP")
.timeoutSec(10)
.healthChecks(default_.id())
.loadBalancingScheme("INTERNAL_SELF_MANAGED")
.build());
var urlmap = new URLMap("urlmap", URLMapArgs.builder()
.name("urlmap")
.description("a description")
.defaultService(home.id())
.hostRules(URLMapHostRuleArgs.builder()
.hosts("mysite.com")
.pathMatcher("allpaths")
.build())
.pathMatchers(URLMapPathMatcherArgs.builder()
.name("allpaths")
.defaultService(home.id())
.routeRules(URLMapPathMatcherRouteRuleArgs.builder()
.priority(1)
.headerAction(URLMapPathMatcherRouteRuleHeaderActionArgs.builder()
.requestHeadersToRemoves("RemoveMe2")
.requestHeadersToAdds(URLMapPathMatcherRouteRuleHeaderActionRequestHeadersToAddArgs.builder()
.headerName("AddSomethingElse")
.headerValue("MyOtherValue")
.replace(true)
.build())
.responseHeadersToRemoves("RemoveMe3")
.responseHeadersToAdds(URLMapPathMatcherRouteRuleHeaderActionResponseHeadersToAddArgs.builder()
.headerName("AddMe")
.headerValue("MyValue")
.replace(false)
.build())
.build())
.matchRules(URLMapPathMatcherRouteRuleMatchRuleArgs.builder()
.fullPathMatch("a full path")
.headerMatches(URLMapPathMatcherRouteRuleMatchRuleHeaderMatchArgs.builder()
.headerName("someheader")
.exactMatch("match this exactly")
.invertMatch(true)
.build())
.ignoreCase(true)
.metadataFilters(URLMapPathMatcherRouteRuleMatchRuleMetadataFilterArgs.builder()
.filterMatchCriteria("MATCH_ANY")
.filterLabels(URLMapPathMatcherRouteRuleMatchRuleMetadataFilterFilterLabelArgs.builder()
.name("PLANET")
.value("MARS")
.build())
.build())
.queryParameterMatches(URLMapPathMatcherRouteRuleMatchRuleQueryParameterMatchArgs.builder()
.name("a query parameter")
.presentMatch(true)
.build())
.build())
.urlRedirect(URLMapPathMatcherRouteRuleUrlRedirectArgs.builder()
.hostRedirect("A host")
.httpsRedirect(false)
.pathRedirect("some/path")
.redirectResponseCode("TEMPORARY_REDIRECT")
.stripQuery(true)
.build())
.build())
.build())
.tests(URLMapTestArgs.builder()
.service(home.id())
.host("hi.com")
.path("/home")
.build())
.build());
}
}
resources:
urlmap:
type: gcp:compute:URLMap
properties:
name: urlmap
description: a description
defaultService: ${home.id}
hostRules:
- hosts:
- mysite.com
pathMatcher: allpaths
pathMatchers:
- name: allpaths
defaultService: ${home.id}
routeRules:
- priority: 1
headerAction:
requestHeadersToRemoves:
- RemoveMe2
requestHeadersToAdds:
- headerName: AddSomethingElse
headerValue: MyOtherValue
replace: true
responseHeadersToRemoves:
- RemoveMe3
responseHeadersToAdds:
- headerName: AddMe
headerValue: MyValue
replace: false
matchRules:
- fullPathMatch: a full path
headerMatches:
- headerName: someheader
exactMatch: match this exactly
invertMatch: true
ignoreCase: true
metadataFilters:
- filterMatchCriteria: MATCH_ANY
filterLabels:
- name: PLANET
value: MARS
queryParameterMatches:
- name: a query parameter
presentMatch: true
urlRedirect:
hostRedirect: A host
httpsRedirect: false
pathRedirect: some/path
redirectResponseCode: TEMPORARY_REDIRECT
stripQuery: true
tests:
- service: ${home.id}
host: hi.com
path: /home
home:
type: gcp:compute:BackendService
properties:
name: home
portName: http
protocol: HTTP
timeoutSec: 10
healthChecks: ${default.id}
loadBalancingScheme: INTERNAL_SELF_MANAGED
default:
type: gcp:compute:HealthCheck
properties:
name: health-check
httpHealthCheck:
port: 80
The headerAction property modifies requests and responses. The requestHeadersToAdds array adds headers to backend requests; requestHeadersToRemoves strips headers. The responseHeadersToAdds and responseHeadersToRemoves arrays modify responses before returning to clients. The urlRedirect property sends HTTP redirects instead of proxying to a backend. The matchRules property controls when these actions apply, checking fullPathMatch, headerMatches, and queryParameterMatches.
Apply advanced routing policies to specific paths
Production traffic often requires sophisticated handling: CORS policies for browser requests, fault injection for testing, request mirroring for validation, and retry logic for resilience.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
const _default = new gcp.compute.HealthCheck("default", {
name: "health-check",
httpHealthCheck: {
port: 80,
},
});
const home = new gcp.compute.BackendService("home", {
name: "home",
portName: "http",
protocol: "HTTP",
timeoutSec: 10,
healthChecks: _default.id,
loadBalancingScheme: "INTERNAL_SELF_MANAGED",
});
const urlmap = new gcp.compute.URLMap("urlmap", {
name: "urlmap",
description: "a description",
defaultService: home.id,
hostRules: [{
hosts: ["mysite.com"],
pathMatcher: "allpaths",
}],
pathMatchers: [{
name: "allpaths",
defaultService: home.id,
pathRules: [{
paths: ["/home"],
routeAction: {
corsPolicy: {
allowCredentials: true,
allowHeaders: ["Allowed content"],
allowMethods: ["GET"],
allowOriginRegexes: ["abc.*"],
allowOrigins: ["Allowed origin"],
exposeHeaders: ["Exposed header"],
maxAge: 30,
disabled: false,
},
faultInjectionPolicy: {
abort: {
httpStatus: 234,
percentage: 5.6,
},
delay: {
fixedDelay: {
seconds: "0",
nanos: 50000,
},
percentage: 7.8,
},
},
requestMirrorPolicy: {
backendService: home.id,
},
retryPolicy: {
numRetries: 4,
perTryTimeout: {
seconds: "30",
},
retryConditions: [
"5xx",
"deadline-exceeded",
],
},
timeout: {
seconds: "20",
nanos: 750000000,
},
urlRewrite: {
hostRewrite: "dev.example.com",
pathPrefixRewrite: "/v1/api/",
},
weightedBackendServices: [{
backendService: home.id,
weight: 400,
headerAction: {
requestHeadersToRemoves: ["RemoveMe"],
requestHeadersToAdds: [{
headerName: "AddMe",
headerValue: "MyValue",
replace: true,
}],
responseHeadersToRemoves: ["RemoveMe"],
responseHeadersToAdds: [{
headerName: "AddMe",
headerValue: "MyValue",
replace: false,
}],
},
}],
},
}],
}],
tests: [{
service: home.id,
host: "hi.com",
path: "/home",
}],
});
import pulumi
import pulumi_gcp as gcp
default = gcp.compute.HealthCheck("default",
name="health-check",
http_health_check={
"port": 80,
})
home = gcp.compute.BackendService("home",
name="home",
port_name="http",
protocol="HTTP",
timeout_sec=10,
health_checks=default.id,
load_balancing_scheme="INTERNAL_SELF_MANAGED")
urlmap = gcp.compute.URLMap("urlmap",
name="urlmap",
description="a description",
default_service=home.id,
host_rules=[{
"hosts": ["mysite.com"],
"path_matcher": "allpaths",
}],
path_matchers=[{
"name": "allpaths",
"default_service": home.id,
"path_rules": [{
"paths": ["/home"],
"route_action": {
"cors_policy": {
"allow_credentials": True,
"allow_headers": ["Allowed content"],
"allow_methods": ["GET"],
"allow_origin_regexes": ["abc.*"],
"allow_origins": ["Allowed origin"],
"expose_headers": ["Exposed header"],
"max_age": 30,
"disabled": False,
},
"fault_injection_policy": {
"abort": {
"http_status": 234,
"percentage": 5.6,
},
"delay": {
"fixed_delay": {
"seconds": "0",
"nanos": 50000,
},
"percentage": 7.8,
},
},
"request_mirror_policy": {
"backend_service": home.id,
},
"retry_policy": {
"num_retries": 4,
"per_try_timeout": {
"seconds": "30",
},
"retry_conditions": [
"5xx",
"deadline-exceeded",
],
},
"timeout": {
"seconds": "20",
"nanos": 750000000,
},
"url_rewrite": {
"host_rewrite": "dev.example.com",
"path_prefix_rewrite": "/v1/api/",
},
"weighted_backend_services": [{
"backend_service": home.id,
"weight": 400,
"header_action": {
"request_headers_to_removes": ["RemoveMe"],
"request_headers_to_adds": [{
"header_name": "AddMe",
"header_value": "MyValue",
"replace": True,
}],
"response_headers_to_removes": ["RemoveMe"],
"response_headers_to_adds": [{
"header_name": "AddMe",
"header_value": "MyValue",
"replace": False,
}],
},
}],
},
}],
}],
tests=[{
"service": home.id,
"host": "hi.com",
"path": "/home",
}])
package main
import (
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/compute"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_default, err := compute.NewHealthCheck(ctx, "default", &compute.HealthCheckArgs{
Name: pulumi.String("health-check"),
HttpHealthCheck: &compute.HealthCheckHttpHealthCheckArgs{
Port: pulumi.Int(80),
},
})
if err != nil {
return err
}
home, err := compute.NewBackendService(ctx, "home", &compute.BackendServiceArgs{
Name: pulumi.String("home"),
PortName: pulumi.String("http"),
Protocol: pulumi.String("HTTP"),
TimeoutSec: pulumi.Int(10),
HealthChecks: _default.ID(),
LoadBalancingScheme: pulumi.String("INTERNAL_SELF_MANAGED"),
})
if err != nil {
return err
}
_, err = compute.NewURLMap(ctx, "urlmap", &compute.URLMapArgs{
Name: pulumi.String("urlmap"),
Description: pulumi.String("a description"),
DefaultService: home.ID(),
HostRules: compute.URLMapHostRuleArray{
&compute.URLMapHostRuleArgs{
Hosts: pulumi.StringArray{
pulumi.String("mysite.com"),
},
PathMatcher: pulumi.String("allpaths"),
},
},
PathMatchers: compute.URLMapPathMatcherArray{
&compute.URLMapPathMatcherArgs{
Name: pulumi.String("allpaths"),
DefaultService: home.ID(),
PathRules: compute.URLMapPathMatcherPathRuleArray{
&compute.URLMapPathMatcherPathRuleArgs{
Paths: pulumi.StringArray{
pulumi.String("/home"),
},
RouteAction: &compute.URLMapPathMatcherPathRuleRouteActionArgs{
CorsPolicy: &compute.URLMapPathMatcherPathRuleRouteActionCorsPolicyArgs{
AllowCredentials: pulumi.Bool(true),
AllowHeaders: pulumi.StringArray{
pulumi.String("Allowed content"),
},
AllowMethods: pulumi.StringArray{
pulumi.String("GET"),
},
AllowOriginRegexes: pulumi.StringArray{
pulumi.String("abc.*"),
},
AllowOrigins: pulumi.StringArray{
pulumi.String("Allowed origin"),
},
ExposeHeaders: pulumi.StringArray{
pulumi.String("Exposed header"),
},
MaxAge: pulumi.Int(30),
Disabled: pulumi.Bool(false),
},
FaultInjectionPolicy: &compute.URLMapPathMatcherPathRuleRouteActionFaultInjectionPolicyArgs{
Abort: &compute.URLMapPathMatcherPathRuleRouteActionFaultInjectionPolicyAbortArgs{
HttpStatus: pulumi.Int(234),
Percentage: pulumi.Float64(5.6),
},
Delay: &compute.URLMapPathMatcherPathRuleRouteActionFaultInjectionPolicyDelayArgs{
FixedDelay: &compute.URLMapPathMatcherPathRuleRouteActionFaultInjectionPolicyDelayFixedDelayArgs{
Seconds: pulumi.String("0"),
Nanos: pulumi.Int(50000),
},
Percentage: pulumi.Float64(7.8),
},
},
RequestMirrorPolicy: &compute.URLMapPathMatcherPathRuleRouteActionRequestMirrorPolicyArgs{
BackendService: home.ID(),
},
RetryPolicy: &compute.URLMapPathMatcherPathRuleRouteActionRetryPolicyArgs{
NumRetries: pulumi.Int(4),
PerTryTimeout: &compute.URLMapPathMatcherPathRuleRouteActionRetryPolicyPerTryTimeoutArgs{
Seconds: pulumi.String("30"),
},
RetryConditions: pulumi.StringArray{
pulumi.String("5xx"),
pulumi.String("deadline-exceeded"),
},
},
Timeout: &compute.URLMapPathMatcherPathRuleRouteActionTimeoutArgs{
Seconds: pulumi.String("20"),
Nanos: pulumi.Int(750000000),
},
UrlRewrite: &compute.URLMapPathMatcherPathRuleRouteActionUrlRewriteArgs{
HostRewrite: pulumi.String("dev.example.com"),
PathPrefixRewrite: pulumi.String("/v1/api/"),
},
WeightedBackendServices: compute.URLMapPathMatcherPathRuleRouteActionWeightedBackendServiceArray{
&compute.URLMapPathMatcherPathRuleRouteActionWeightedBackendServiceArgs{
BackendService: home.ID(),
Weight: pulumi.Int(400),
HeaderAction: &compute.URLMapPathMatcherPathRuleRouteActionWeightedBackendServiceHeaderActionArgs{
RequestHeadersToRemoves: pulumi.StringArray{
pulumi.String("RemoveMe"),
},
RequestHeadersToAdds: compute.URLMapPathMatcherPathRuleRouteActionWeightedBackendServiceHeaderActionRequestHeadersToAddArray{
&compute.URLMapPathMatcherPathRuleRouteActionWeightedBackendServiceHeaderActionRequestHeadersToAddArgs{
HeaderName: pulumi.String("AddMe"),
HeaderValue: pulumi.String("MyValue"),
Replace: pulumi.Bool(true),
},
},
ResponseHeadersToRemoves: pulumi.StringArray{
pulumi.String("RemoveMe"),
},
ResponseHeadersToAdds: compute.URLMapPathMatcherPathRuleRouteActionWeightedBackendServiceHeaderActionResponseHeadersToAddArray{
&compute.URLMapPathMatcherPathRuleRouteActionWeightedBackendServiceHeaderActionResponseHeadersToAddArgs{
HeaderName: pulumi.String("AddMe"),
HeaderValue: pulumi.String("MyValue"),
Replace: pulumi.Bool(false),
},
},
},
},
},
},
},
},
},
},
Tests: compute.URLMapTestArray{
&compute.URLMapTestArgs{
Service: home.ID(),
Host: pulumi.String("hi.com"),
Path: pulumi.String("/home"),
},
},
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Gcp = Pulumi.Gcp;
return await Deployment.RunAsync(() =>
{
var @default = new Gcp.Compute.HealthCheck("default", new()
{
Name = "health-check",
HttpHealthCheck = new Gcp.Compute.Inputs.HealthCheckHttpHealthCheckArgs
{
Port = 80,
},
});
var home = new Gcp.Compute.BackendService("home", new()
{
Name = "home",
PortName = "http",
Protocol = "HTTP",
TimeoutSec = 10,
HealthChecks = @default.Id,
LoadBalancingScheme = "INTERNAL_SELF_MANAGED",
});
var urlmap = new Gcp.Compute.URLMap("urlmap", new()
{
Name = "urlmap",
Description = "a description",
DefaultService = home.Id,
HostRules = new[]
{
new Gcp.Compute.Inputs.URLMapHostRuleArgs
{
Hosts = new[]
{
"mysite.com",
},
PathMatcher = "allpaths",
},
},
PathMatchers = new[]
{
new Gcp.Compute.Inputs.URLMapPathMatcherArgs
{
Name = "allpaths",
DefaultService = home.Id,
PathRules = new[]
{
new Gcp.Compute.Inputs.URLMapPathMatcherPathRuleArgs
{
Paths = new[]
{
"/home",
},
RouteAction = new Gcp.Compute.Inputs.URLMapPathMatcherPathRuleRouteActionArgs
{
CorsPolicy = new Gcp.Compute.Inputs.URLMapPathMatcherPathRuleRouteActionCorsPolicyArgs
{
AllowCredentials = true,
AllowHeaders = new[]
{
"Allowed content",
},
AllowMethods = new[]
{
"GET",
},
AllowOriginRegexes = new[]
{
"abc.*",
},
AllowOrigins = new[]
{
"Allowed origin",
},
ExposeHeaders = new[]
{
"Exposed header",
},
MaxAge = 30,
Disabled = false,
},
FaultInjectionPolicy = new Gcp.Compute.Inputs.URLMapPathMatcherPathRuleRouteActionFaultInjectionPolicyArgs
{
Abort = new Gcp.Compute.Inputs.URLMapPathMatcherPathRuleRouteActionFaultInjectionPolicyAbortArgs
{
HttpStatus = 234,
Percentage = 5.6,
},
Delay = new Gcp.Compute.Inputs.URLMapPathMatcherPathRuleRouteActionFaultInjectionPolicyDelayArgs
{
FixedDelay = new Gcp.Compute.Inputs.URLMapPathMatcherPathRuleRouteActionFaultInjectionPolicyDelayFixedDelayArgs
{
Seconds = "0",
Nanos = 50000,
},
Percentage = 7.8,
},
},
RequestMirrorPolicy = new Gcp.Compute.Inputs.URLMapPathMatcherPathRuleRouteActionRequestMirrorPolicyArgs
{
BackendService = home.Id,
},
RetryPolicy = new Gcp.Compute.Inputs.URLMapPathMatcherPathRuleRouteActionRetryPolicyArgs
{
NumRetries = 4,
PerTryTimeout = new Gcp.Compute.Inputs.URLMapPathMatcherPathRuleRouteActionRetryPolicyPerTryTimeoutArgs
{
Seconds = "30",
},
RetryConditions = new[]
{
"5xx",
"deadline-exceeded",
},
},
Timeout = new Gcp.Compute.Inputs.URLMapPathMatcherPathRuleRouteActionTimeoutArgs
{
Seconds = "20",
Nanos = 750000000,
},
UrlRewrite = new Gcp.Compute.Inputs.URLMapPathMatcherPathRuleRouteActionUrlRewriteArgs
{
HostRewrite = "dev.example.com",
PathPrefixRewrite = "/v1/api/",
},
WeightedBackendServices = new[]
{
new Gcp.Compute.Inputs.URLMapPathMatcherPathRuleRouteActionWeightedBackendServiceArgs
{
BackendService = home.Id,
Weight = 400,
HeaderAction = new Gcp.Compute.Inputs.URLMapPathMatcherPathRuleRouteActionWeightedBackendServiceHeaderActionArgs
{
RequestHeadersToRemoves = new[]
{
"RemoveMe",
},
RequestHeadersToAdds = new[]
{
new Gcp.Compute.Inputs.URLMapPathMatcherPathRuleRouteActionWeightedBackendServiceHeaderActionRequestHeadersToAddArgs
{
HeaderName = "AddMe",
HeaderValue = "MyValue",
Replace = true,
},
},
ResponseHeadersToRemoves = new[]
{
"RemoveMe",
},
ResponseHeadersToAdds = new[]
{
new Gcp.Compute.Inputs.URLMapPathMatcherPathRuleRouteActionWeightedBackendServiceHeaderActionResponseHeadersToAddArgs
{
HeaderName = "AddMe",
HeaderValue = "MyValue",
Replace = false,
},
},
},
},
},
},
},
},
},
},
Tests = new[]
{
new Gcp.Compute.Inputs.URLMapTestArgs
{
Service = home.Id,
Host = "hi.com",
Path = "/home",
},
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.compute.HealthCheck;
import com.pulumi.gcp.compute.HealthCheckArgs;
import com.pulumi.gcp.compute.inputs.HealthCheckHttpHealthCheckArgs;
import com.pulumi.gcp.compute.BackendService;
import com.pulumi.gcp.compute.BackendServiceArgs;
import com.pulumi.gcp.compute.URLMap;
import com.pulumi.gcp.compute.URLMapArgs;
import com.pulumi.gcp.compute.inputs.URLMapHostRuleArgs;
import com.pulumi.gcp.compute.inputs.URLMapPathMatcherArgs;
import com.pulumi.gcp.compute.inputs.URLMapTestArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
public class App {
public static void main(String[] args) {
Pulumi.run(App::stack);
}
public static void stack(Context ctx) {
var default_ = new HealthCheck("default", HealthCheckArgs.builder()
.name("health-check")
.httpHealthCheck(HealthCheckHttpHealthCheckArgs.builder()
.port(80)
.build())
.build());
var home = new BackendService("home", BackendServiceArgs.builder()
.name("home")
.portName("http")
.protocol("HTTP")
.timeoutSec(10)
.healthChecks(default_.id())
.loadBalancingScheme("INTERNAL_SELF_MANAGED")
.build());
var urlmap = new URLMap("urlmap", URLMapArgs.builder()
.name("urlmap")
.description("a description")
.defaultService(home.id())
.hostRules(URLMapHostRuleArgs.builder()
.hosts("mysite.com")
.pathMatcher("allpaths")
.build())
.pathMatchers(URLMapPathMatcherArgs.builder()
.name("allpaths")
.defaultService(home.id())
.pathRules(URLMapPathMatcherPathRuleArgs.builder()
.paths("/home")
.routeAction(URLMapPathMatcherPathRuleRouteActionArgs.builder()
.corsPolicy(URLMapPathMatcherPathRuleRouteActionCorsPolicyArgs.builder()
.allowCredentials(true)
.allowHeaders("Allowed content")
.allowMethods("GET")
.allowOriginRegexes("abc.*")
.allowOrigins("Allowed origin")
.exposeHeaders("Exposed header")
.maxAge(30)
.disabled(false)
.build())
.faultInjectionPolicy(URLMapPathMatcherPathRuleRouteActionFaultInjectionPolicyArgs.builder()
.abort(URLMapPathMatcherPathRuleRouteActionFaultInjectionPolicyAbortArgs.builder()
.httpStatus(234)
.percentage(5.6)
.build())
.delay(URLMapPathMatcherPathRuleRouteActionFaultInjectionPolicyDelayArgs.builder()
.fixedDelay(URLMapPathMatcherPathRuleRouteActionFaultInjectionPolicyDelayFixedDelayArgs.builder()
.seconds("0")
.nanos(50000)
.build())
.percentage(7.8)
.build())
.build())
.requestMirrorPolicy(URLMapPathMatcherPathRuleRouteActionRequestMirrorPolicyArgs.builder()
.backendService(home.id())
.build())
.retryPolicy(URLMapPathMatcherPathRuleRouteActionRetryPolicyArgs.builder()
.numRetries(4)
.perTryTimeout(URLMapPathMatcherPathRuleRouteActionRetryPolicyPerTryTimeoutArgs.builder()
.seconds("30")
.build())
.retryConditions(
"5xx",
"deadline-exceeded")
.build())
.timeout(URLMapPathMatcherPathRuleRouteActionTimeoutArgs.builder()
.seconds("20")
.nanos(750000000)
.build())
.urlRewrite(URLMapPathMatcherPathRuleRouteActionUrlRewriteArgs.builder()
.hostRewrite("dev.example.com")
.pathPrefixRewrite("/v1/api/")
.build())
.weightedBackendServices(URLMapPathMatcherPathRuleRouteActionWeightedBackendServiceArgs.builder()
.backendService(home.id())
.weight(400)
.headerAction(URLMapPathMatcherPathRuleRouteActionWeightedBackendServiceHeaderActionArgs.builder()
.requestHeadersToRemoves("RemoveMe")
.requestHeadersToAdds(URLMapPathMatcherPathRuleRouteActionWeightedBackendServiceHeaderActionRequestHeadersToAddArgs.builder()
.headerName("AddMe")
.headerValue("MyValue")
.replace(true)
.build())
.responseHeadersToRemoves("RemoveMe")
.responseHeadersToAdds(URLMapPathMatcherPathRuleRouteActionWeightedBackendServiceHeaderActionResponseHeadersToAddArgs.builder()
.headerName("AddMe")
.headerValue("MyValue")
.replace(false)
.build())
.build())
.build())
.build())
.build())
.build())
.tests(URLMapTestArgs.builder()
.service(home.id())
.host("hi.com")
.path("/home")
.build())
.build());
}
}
resources:
urlmap:
type: gcp:compute:URLMap
properties:
name: urlmap
description: a description
defaultService: ${home.id}
hostRules:
- hosts:
- mysite.com
pathMatcher: allpaths
pathMatchers:
- name: allpaths
defaultService: ${home.id}
pathRules:
- paths:
- /home
routeAction:
corsPolicy:
allowCredentials: true
allowHeaders:
- Allowed content
allowMethods:
- GET
allowOriginRegexes:
- abc.*
allowOrigins:
- Allowed origin
exposeHeaders:
- Exposed header
maxAge: 30
disabled: false
faultInjectionPolicy:
abort:
httpStatus: 234
percentage: 5.6
delay:
fixedDelay:
seconds: 0
nanos: 50000
percentage: 7.8
requestMirrorPolicy:
backendService: ${home.id}
retryPolicy:
numRetries: 4
perTryTimeout:
seconds: 30
retryConditions:
- 5xx
- deadline-exceeded
timeout:
seconds: 20
nanos: 7.5e+08
urlRewrite:
hostRewrite: dev.example.com
pathPrefixRewrite: /v1/api/
weightedBackendServices:
- backendService: ${home.id}
weight: 400
headerAction:
requestHeadersToRemoves:
- RemoveMe
requestHeadersToAdds:
- headerName: AddMe
headerValue: MyValue
replace: true
responseHeadersToRemoves:
- RemoveMe
responseHeadersToAdds:
- headerName: AddMe
headerValue: MyValue
replace: false
tests:
- service: ${home.id}
host: hi.com
path: /home
home:
type: gcp:compute:BackendService
properties:
name: home
portName: http
protocol: HTTP
timeoutSec: 10
healthChecks: ${default.id}
loadBalancingScheme: INTERNAL_SELF_MANAGED
default:
type: gcp:compute:HealthCheck
properties:
name: health-check
httpHealthCheck:
port: 80
The routeAction property on pathRules enables advanced traffic management. The corsPolicy configures cross-origin resource sharing for browser requests. The faultInjectionPolicy injects delays and errors for chaos testing. The requestMirrorPolicy duplicates traffic to a second backend for validation. The retryPolicy configures automatic retries with backoff. The weightedBackendServices array distributes traffic across multiple backends with specified weights.
Match and rewrite URLs using path templates
RESTful APIs often need to extract path segments and transform them. Path templates capture variables from incoming URLs and rewrite them into different formats.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
const _default = new gcp.compute.HttpHealthCheck("default", {
name: "health-check",
requestPath: "/",
checkIntervalSec: 1,
timeoutSec: 1,
});
const cart_backend = new gcp.compute.BackendService("cart-backend", {
name: "cart-service",
portName: "http",
protocol: "HTTP",
timeoutSec: 10,
loadBalancingScheme: "EXTERNAL_MANAGED",
healthChecks: _default.id,
});
const user_backend = new gcp.compute.BackendService("user-backend", {
name: "user-service",
portName: "http",
protocol: "HTTP",
timeoutSec: 10,
loadBalancingScheme: "EXTERNAL_MANAGED",
healthChecks: _default.id,
});
const staticBucket = new gcp.storage.Bucket("static", {
name: "static-asset-bucket",
location: "US",
});
const static = new gcp.compute.BackendBucket("static", {
name: "static-asset-backend-bucket",
bucketName: staticBucket.name,
enableCdn: true,
});
const urlmap = new gcp.compute.URLMap("urlmap", {
name: "urlmap",
description: "a description",
defaultService: static.id,
hostRules: [{
hosts: ["mysite.com"],
pathMatcher: "mysite",
}],
pathMatchers: [{
name: "mysite",
defaultService: static.id,
routeRules: [
{
matchRules: [{
pathTemplateMatch: "/xyzwebservices/v2/xyz/users/{username=*}/carts/{cartid=**}",
}],
service: cart_backend.id,
priority: 1,
routeAction: {
urlRewrite: {
pathTemplateRewrite: "/{username}-{cartid}/",
},
},
},
{
matchRules: [{
pathTemplateMatch: "/xyzwebservices/v2/xyz/users/*/accountinfo/*",
}],
service: user_backend.id,
priority: 2,
},
],
}],
});
import pulumi
import pulumi_gcp as gcp
default = gcp.compute.HttpHealthCheck("default",
name="health-check",
request_path="/",
check_interval_sec=1,
timeout_sec=1)
cart_backend = gcp.compute.BackendService("cart-backend",
name="cart-service",
port_name="http",
protocol="HTTP",
timeout_sec=10,
load_balancing_scheme="EXTERNAL_MANAGED",
health_checks=default.id)
user_backend = gcp.compute.BackendService("user-backend",
name="user-service",
port_name="http",
protocol="HTTP",
timeout_sec=10,
load_balancing_scheme="EXTERNAL_MANAGED",
health_checks=default.id)
static_bucket = gcp.storage.Bucket("static",
name="static-asset-bucket",
location="US")
static = gcp.compute.BackendBucket("static",
name="static-asset-backend-bucket",
bucket_name=static_bucket.name,
enable_cdn=True)
urlmap = gcp.compute.URLMap("urlmap",
name="urlmap",
description="a description",
default_service=static.id,
host_rules=[{
"hosts": ["mysite.com"],
"path_matcher": "mysite",
}],
path_matchers=[{
"name": "mysite",
"default_service": static.id,
"route_rules": [
{
"match_rules": [{
"path_template_match": "/xyzwebservices/v2/xyz/users/{username=*}/carts/{cartid=**}",
}],
"service": cart_backend.id,
"priority": 1,
"route_action": {
"url_rewrite": {
"path_template_rewrite": "/{username}-{cartid}/",
},
},
},
{
"match_rules": [{
"path_template_match": "/xyzwebservices/v2/xyz/users/*/accountinfo/*",
}],
"service": user_backend.id,
"priority": 2,
},
],
}])
package main
import (
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/compute"
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/storage"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_default, err := compute.NewHttpHealthCheck(ctx, "default", &compute.HttpHealthCheckArgs{
Name: pulumi.String("health-check"),
RequestPath: pulumi.String("/"),
CheckIntervalSec: pulumi.Int(1),
TimeoutSec: pulumi.Int(1),
})
if err != nil {
return err
}
cart_backend, err := compute.NewBackendService(ctx, "cart-backend", &compute.BackendServiceArgs{
Name: pulumi.String("cart-service"),
PortName: pulumi.String("http"),
Protocol: pulumi.String("HTTP"),
TimeoutSec: pulumi.Int(10),
LoadBalancingScheme: pulumi.String("EXTERNAL_MANAGED"),
HealthChecks: _default.ID(),
})
if err != nil {
return err
}
user_backend, err := compute.NewBackendService(ctx, "user-backend", &compute.BackendServiceArgs{
Name: pulumi.String("user-service"),
PortName: pulumi.String("http"),
Protocol: pulumi.String("HTTP"),
TimeoutSec: pulumi.Int(10),
LoadBalancingScheme: pulumi.String("EXTERNAL_MANAGED"),
HealthChecks: _default.ID(),
})
if err != nil {
return err
}
staticBucket, err := storage.NewBucket(ctx, "static", &storage.BucketArgs{
Name: pulumi.String("static-asset-bucket"),
Location: pulumi.String("US"),
})
if err != nil {
return err
}
static, err := compute.NewBackendBucket(ctx, "static", &compute.BackendBucketArgs{
Name: pulumi.String("static-asset-backend-bucket"),
BucketName: staticBucket.Name,
EnableCdn: pulumi.Bool(true),
})
if err != nil {
return err
}
_, err = compute.NewURLMap(ctx, "urlmap", &compute.URLMapArgs{
Name: pulumi.String("urlmap"),
Description: pulumi.String("a description"),
DefaultService: static.ID(),
HostRules: compute.URLMapHostRuleArray{
&compute.URLMapHostRuleArgs{
Hosts: pulumi.StringArray{
pulumi.String("mysite.com"),
},
PathMatcher: pulumi.String("mysite"),
},
},
PathMatchers: compute.URLMapPathMatcherArray{
&compute.URLMapPathMatcherArgs{
Name: pulumi.String("mysite"),
DefaultService: static.ID(),
RouteRules: compute.URLMapPathMatcherRouteRuleArray{
&compute.URLMapPathMatcherRouteRuleArgs{
MatchRules: compute.URLMapPathMatcherRouteRuleMatchRuleArray{
&compute.URLMapPathMatcherRouteRuleMatchRuleArgs{
PathTemplateMatch: pulumi.String("/xyzwebservices/v2/xyz/users/{username=*}/carts/{cartid=**}"),
},
},
Service: cart_backend.ID(),
Priority: pulumi.Int(1),
RouteAction: &compute.URLMapPathMatcherRouteRuleRouteActionArgs{
UrlRewrite: &compute.URLMapPathMatcherRouteRuleRouteActionUrlRewriteArgs{
PathTemplateRewrite: pulumi.String("/{username}-{cartid}/"),
},
},
},
&compute.URLMapPathMatcherRouteRuleArgs{
MatchRules: compute.URLMapPathMatcherRouteRuleMatchRuleArray{
&compute.URLMapPathMatcherRouteRuleMatchRuleArgs{
PathTemplateMatch: pulumi.String("/xyzwebservices/v2/xyz/users/*/accountinfo/*"),
},
},
Service: user_backend.ID(),
Priority: pulumi.Int(2),
},
},
},
},
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Gcp = Pulumi.Gcp;
return await Deployment.RunAsync(() =>
{
var @default = new Gcp.Compute.HttpHealthCheck("default", new()
{
Name = "health-check",
RequestPath = "/",
CheckIntervalSec = 1,
TimeoutSec = 1,
});
var cart_backend = new Gcp.Compute.BackendService("cart-backend", new()
{
Name = "cart-service",
PortName = "http",
Protocol = "HTTP",
TimeoutSec = 10,
LoadBalancingScheme = "EXTERNAL_MANAGED",
HealthChecks = @default.Id,
});
var user_backend = new Gcp.Compute.BackendService("user-backend", new()
{
Name = "user-service",
PortName = "http",
Protocol = "HTTP",
TimeoutSec = 10,
LoadBalancingScheme = "EXTERNAL_MANAGED",
HealthChecks = @default.Id,
});
var staticBucket = new Gcp.Storage.Bucket("static", new()
{
Name = "static-asset-bucket",
Location = "US",
});
var @static = new Gcp.Compute.BackendBucket("static", new()
{
Name = "static-asset-backend-bucket",
BucketName = staticBucket.Name,
EnableCdn = true,
});
var urlmap = new Gcp.Compute.URLMap("urlmap", new()
{
Name = "urlmap",
Description = "a description",
DefaultService = @static.Id,
HostRules = new[]
{
new Gcp.Compute.Inputs.URLMapHostRuleArgs
{
Hosts = new[]
{
"mysite.com",
},
PathMatcher = "mysite",
},
},
PathMatchers = new[]
{
new Gcp.Compute.Inputs.URLMapPathMatcherArgs
{
Name = "mysite",
DefaultService = @static.Id,
RouteRules = new[]
{
new Gcp.Compute.Inputs.URLMapPathMatcherRouteRuleArgs
{
MatchRules = new[]
{
new Gcp.Compute.Inputs.URLMapPathMatcherRouteRuleMatchRuleArgs
{
PathTemplateMatch = "/xyzwebservices/v2/xyz/users/{username=*}/carts/{cartid=**}",
},
},
Service = cart_backend.Id,
Priority = 1,
RouteAction = new Gcp.Compute.Inputs.URLMapPathMatcherRouteRuleRouteActionArgs
{
UrlRewrite = new Gcp.Compute.Inputs.URLMapPathMatcherRouteRuleRouteActionUrlRewriteArgs
{
PathTemplateRewrite = "/{username}-{cartid}/",
},
},
},
new Gcp.Compute.Inputs.URLMapPathMatcherRouteRuleArgs
{
MatchRules = new[]
{
new Gcp.Compute.Inputs.URLMapPathMatcherRouteRuleMatchRuleArgs
{
PathTemplateMatch = "/xyzwebservices/v2/xyz/users/*/accountinfo/*",
},
},
Service = user_backend.Id,
Priority = 2,
},
},
},
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.compute.HttpHealthCheck;
import com.pulumi.gcp.compute.HttpHealthCheckArgs;
import com.pulumi.gcp.compute.BackendService;
import com.pulumi.gcp.compute.BackendServiceArgs;
import com.pulumi.gcp.storage.Bucket;
import com.pulumi.gcp.storage.BucketArgs;
import com.pulumi.gcp.compute.BackendBucket;
import com.pulumi.gcp.compute.BackendBucketArgs;
import com.pulumi.gcp.compute.URLMap;
import com.pulumi.gcp.compute.URLMapArgs;
import com.pulumi.gcp.compute.inputs.URLMapHostRuleArgs;
import com.pulumi.gcp.compute.inputs.URLMapPathMatcherArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
public class App {
public static void main(String[] args) {
Pulumi.run(App::stack);
}
public static void stack(Context ctx) {
var default_ = new HttpHealthCheck("default", HttpHealthCheckArgs.builder()
.name("health-check")
.requestPath("/")
.checkIntervalSec(1)
.timeoutSec(1)
.build());
var cart_backend = new BackendService("cart-backend", BackendServiceArgs.builder()
.name("cart-service")
.portName("http")
.protocol("HTTP")
.timeoutSec(10)
.loadBalancingScheme("EXTERNAL_MANAGED")
.healthChecks(default_.id())
.build());
var user_backend = new BackendService("user-backend", BackendServiceArgs.builder()
.name("user-service")
.portName("http")
.protocol("HTTP")
.timeoutSec(10)
.loadBalancingScheme("EXTERNAL_MANAGED")
.healthChecks(default_.id())
.build());
var staticBucket = new Bucket("staticBucket", BucketArgs.builder()
.name("static-asset-bucket")
.location("US")
.build());
var static_ = new BackendBucket("static", BackendBucketArgs.builder()
.name("static-asset-backend-bucket")
.bucketName(staticBucket.name())
.enableCdn(true)
.build());
var urlmap = new URLMap("urlmap", URLMapArgs.builder()
.name("urlmap")
.description("a description")
.defaultService(static_.id())
.hostRules(URLMapHostRuleArgs.builder()
.hosts("mysite.com")
.pathMatcher("mysite")
.build())
.pathMatchers(URLMapPathMatcherArgs.builder()
.name("mysite")
.defaultService(static_.id())
.routeRules(
URLMapPathMatcherRouteRuleArgs.builder()
.matchRules(URLMapPathMatcherRouteRuleMatchRuleArgs.builder()
.pathTemplateMatch("/xyzwebservices/v2/xyz/users/{username=*}/carts/{cartid=**}")
.build())
.service(cart_backend.id())
.priority(1)
.routeAction(URLMapPathMatcherRouteRuleRouteActionArgs.builder()
.urlRewrite(URLMapPathMatcherRouteRuleRouteActionUrlRewriteArgs.builder()
.pathTemplateRewrite("/{username}-{cartid}/")
.build())
.build())
.build(),
URLMapPathMatcherRouteRuleArgs.builder()
.matchRules(URLMapPathMatcherRouteRuleMatchRuleArgs.builder()
.pathTemplateMatch("/xyzwebservices/v2/xyz/users/*/accountinfo/*")
.build())
.service(user_backend.id())
.priority(2)
.build())
.build())
.build());
}
}
resources:
urlmap:
type: gcp:compute:URLMap
properties:
name: urlmap
description: a description
defaultService: ${static.id}
hostRules:
- hosts:
- mysite.com
pathMatcher: mysite
pathMatchers:
- name: mysite
defaultService: ${static.id}
routeRules:
- matchRules:
- pathTemplateMatch: /xyzwebservices/v2/xyz/users/{username=*}/carts/{cartid=**}
service: ${["cart-backend"].id}
priority: 1
routeAction:
urlRewrite:
pathTemplateRewrite: /{username}-{cartid}/
- matchRules:
- pathTemplateMatch: /xyzwebservices/v2/xyz/users/*/accountinfo/*
service: ${["user-backend"].id}
priority: 2
cart-backend:
type: gcp:compute:BackendService
properties:
name: cart-service
portName: http
protocol: HTTP
timeoutSec: 10
loadBalancingScheme: EXTERNAL_MANAGED
healthChecks: ${default.id}
user-backend:
type: gcp:compute:BackendService
properties:
name: user-service
portName: http
protocol: HTTP
timeoutSec: 10
loadBalancingScheme: EXTERNAL_MANAGED
healthChecks: ${default.id}
default:
type: gcp:compute:HttpHealthCheck
properties:
name: health-check
requestPath: /
checkIntervalSec: 1
timeoutSec: 1
static:
type: gcp:compute:BackendBucket
properties:
name: static-asset-backend-bucket
bucketName: ${staticBucket.name}
enableCdn: true
staticBucket:
type: gcp:storage:Bucket
name: static
properties:
name: static-asset-bucket
location: US
The pathTemplateMatch property uses curly braces to capture path segments as variables. Single asterisks (*) match one segment; double asterisks (**) match multiple segments. The pathTemplateRewrite property reconstructs URLs using captured variables. In this example, /xyzwebservices/v2/xyz/users/john/carts/abc123 becomes /john-abc123/ before reaching the backend.
Serve custom error pages from Cloud Storage
When backend services return errors, load balancers can serve custom error pages from Cloud Storage instead of exposing raw error responses to users.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
const _default = new gcp.compute.HttpHealthCheck("default", {
name: "health-check",
requestPath: "/",
checkIntervalSec: 1,
timeoutSec: 1,
});
const example = new gcp.compute.BackendService("example", {
name: "login",
portName: "http",
protocol: "HTTP",
timeoutSec: 10,
loadBalancingScheme: "EXTERNAL_MANAGED",
healthChecks: _default.id,
});
const errorBucket = new gcp.storage.Bucket("error", {
name: "static-asset-bucket",
location: "US",
});
const error = new gcp.compute.BackendBucket("error", {
name: "error-backend-bucket",
bucketName: errorBucket.name,
enableCdn: true,
});
const urlmap = new gcp.compute.URLMap("urlmap", {
name: "urlmap",
description: "a description",
defaultService: example.id,
defaultCustomErrorResponsePolicy: {
errorResponseRules: [{
matchResponseCodes: ["5xx"],
path: "/internal_error.html",
overrideResponseCode: 502,
}],
errorService: error.id,
},
hostRules: [{
hosts: ["mysite.com"],
pathMatcher: "mysite",
}],
pathMatchers: [{
name: "mysite",
defaultService: example.id,
defaultCustomErrorResponsePolicy: {
errorResponseRules: [
{
matchResponseCodes: [
"4xx",
"5xx",
],
path: "/login_error.html",
overrideResponseCode: 404,
},
{
matchResponseCodes: ["503"],
path: "/bad_gateway.html",
overrideResponseCode: 502,
},
],
errorService: error.id,
},
pathRules: [{
paths: ["/private/*"],
service: example.id,
customErrorResponsePolicy: {
errorResponseRules: [{
matchResponseCodes: ["4xx"],
path: "/login.html",
overrideResponseCode: 401,
}],
errorService: error.id,
},
}],
}],
});
import pulumi
import pulumi_gcp as gcp
default = gcp.compute.HttpHealthCheck("default",
name="health-check",
request_path="/",
check_interval_sec=1,
timeout_sec=1)
example = gcp.compute.BackendService("example",
name="login",
port_name="http",
protocol="HTTP",
timeout_sec=10,
load_balancing_scheme="EXTERNAL_MANAGED",
health_checks=default.id)
error_bucket = gcp.storage.Bucket("error",
name="static-asset-bucket",
location="US")
error = gcp.compute.BackendBucket("error",
name="error-backend-bucket",
bucket_name=error_bucket.name,
enable_cdn=True)
urlmap = gcp.compute.URLMap("urlmap",
name="urlmap",
description="a description",
default_service=example.id,
default_custom_error_response_policy={
"error_response_rules": [{
"match_response_codes": ["5xx"],
"path": "/internal_error.html",
"override_response_code": 502,
}],
"error_service": error.id,
},
host_rules=[{
"hosts": ["mysite.com"],
"path_matcher": "mysite",
}],
path_matchers=[{
"name": "mysite",
"default_service": example.id,
"default_custom_error_response_policy": {
"error_response_rules": [
{
"match_response_codes": [
"4xx",
"5xx",
],
"path": "/login_error.html",
"override_response_code": 404,
},
{
"match_response_codes": ["503"],
"path": "/bad_gateway.html",
"override_response_code": 502,
},
],
"error_service": error.id,
},
"path_rules": [{
"paths": ["/private/*"],
"service": example.id,
"custom_error_response_policy": {
"error_response_rules": [{
"match_response_codes": ["4xx"],
"path": "/login.html",
"override_response_code": 401,
}],
"error_service": error.id,
},
}],
}])
package main
import (
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/compute"
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/storage"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_default, err := compute.NewHttpHealthCheck(ctx, "default", &compute.HttpHealthCheckArgs{
Name: pulumi.String("health-check"),
RequestPath: pulumi.String("/"),
CheckIntervalSec: pulumi.Int(1),
TimeoutSec: pulumi.Int(1),
})
if err != nil {
return err
}
example, err := compute.NewBackendService(ctx, "example", &compute.BackendServiceArgs{
Name: pulumi.String("login"),
PortName: pulumi.String("http"),
Protocol: pulumi.String("HTTP"),
TimeoutSec: pulumi.Int(10),
LoadBalancingScheme: pulumi.String("EXTERNAL_MANAGED"),
HealthChecks: _default.ID(),
})
if err != nil {
return err
}
errorBucket, err := storage.NewBucket(ctx, "error", &storage.BucketArgs{
Name: pulumi.String("static-asset-bucket"),
Location: pulumi.String("US"),
})
if err != nil {
return err
}
error, err := compute.NewBackendBucket(ctx, "error", &compute.BackendBucketArgs{
Name: pulumi.String("error-backend-bucket"),
BucketName: errorBucket.Name,
EnableCdn: pulumi.Bool(true),
})
if err != nil {
return err
}
_, err = compute.NewURLMap(ctx, "urlmap", &compute.URLMapArgs{
Name: pulumi.String("urlmap"),
Description: pulumi.String("a description"),
DefaultService: example.ID(),
DefaultCustomErrorResponsePolicy: &compute.URLMapDefaultCustomErrorResponsePolicyArgs{
ErrorResponseRules: compute.URLMapDefaultCustomErrorResponsePolicyErrorResponseRuleArray{
&compute.URLMapDefaultCustomErrorResponsePolicyErrorResponseRuleArgs{
MatchResponseCodes: pulumi.StringArray{
pulumi.String("5xx"),
},
Path: pulumi.String("/internal_error.html"),
OverrideResponseCode: pulumi.Int(502),
},
},
ErrorService: error.ID(),
},
HostRules: compute.URLMapHostRuleArray{
&compute.URLMapHostRuleArgs{
Hosts: pulumi.StringArray{
pulumi.String("mysite.com"),
},
PathMatcher: pulumi.String("mysite"),
},
},
PathMatchers: compute.URLMapPathMatcherArray{
&compute.URLMapPathMatcherArgs{
Name: pulumi.String("mysite"),
DefaultService: example.ID(),
DefaultCustomErrorResponsePolicy: &compute.URLMapPathMatcherDefaultCustomErrorResponsePolicyArgs{
ErrorResponseRules: compute.URLMapPathMatcherDefaultCustomErrorResponsePolicyErrorResponseRuleArray{
&compute.URLMapPathMatcherDefaultCustomErrorResponsePolicyErrorResponseRuleArgs{
MatchResponseCodes: pulumi.StringArray{
pulumi.String("4xx"),
pulumi.String("5xx"),
},
Path: pulumi.String("/login_error.html"),
OverrideResponseCode: pulumi.Int(404),
},
&compute.URLMapPathMatcherDefaultCustomErrorResponsePolicyErrorResponseRuleArgs{
MatchResponseCodes: pulumi.StringArray{
pulumi.String("503"),
},
Path: pulumi.String("/bad_gateway.html"),
OverrideResponseCode: pulumi.Int(502),
},
},
ErrorService: error.ID(),
},
PathRules: compute.URLMapPathMatcherPathRuleArray{
&compute.URLMapPathMatcherPathRuleArgs{
Paths: pulumi.StringArray{
pulumi.String("/private/*"),
},
Service: example.ID(),
CustomErrorResponsePolicy: &compute.URLMapPathMatcherPathRuleCustomErrorResponsePolicyArgs{
ErrorResponseRules: compute.URLMapPathMatcherPathRuleCustomErrorResponsePolicyErrorResponseRuleArray{
&compute.URLMapPathMatcherPathRuleCustomErrorResponsePolicyErrorResponseRuleArgs{
MatchResponseCodes: pulumi.StringArray{
pulumi.String("4xx"),
},
Path: pulumi.String("/login.html"),
OverrideResponseCode: pulumi.Int(401),
},
},
ErrorService: error.ID(),
},
},
},
},
},
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Gcp = Pulumi.Gcp;
return await Deployment.RunAsync(() =>
{
var @default = new Gcp.Compute.HttpHealthCheck("default", new()
{
Name = "health-check",
RequestPath = "/",
CheckIntervalSec = 1,
TimeoutSec = 1,
});
var example = new Gcp.Compute.BackendService("example", new()
{
Name = "login",
PortName = "http",
Protocol = "HTTP",
TimeoutSec = 10,
LoadBalancingScheme = "EXTERNAL_MANAGED",
HealthChecks = @default.Id,
});
var errorBucket = new Gcp.Storage.Bucket("error", new()
{
Name = "static-asset-bucket",
Location = "US",
});
var error = new Gcp.Compute.BackendBucket("error", new()
{
Name = "error-backend-bucket",
BucketName = errorBucket.Name,
EnableCdn = true,
});
var urlmap = new Gcp.Compute.URLMap("urlmap", new()
{
Name = "urlmap",
Description = "a description",
DefaultService = example.Id,
DefaultCustomErrorResponsePolicy = new Gcp.Compute.Inputs.URLMapDefaultCustomErrorResponsePolicyArgs
{
ErrorResponseRules = new[]
{
new Gcp.Compute.Inputs.URLMapDefaultCustomErrorResponsePolicyErrorResponseRuleArgs
{
MatchResponseCodes = new[]
{
"5xx",
},
Path = "/internal_error.html",
OverrideResponseCode = 502,
},
},
ErrorService = error.Id,
},
HostRules = new[]
{
new Gcp.Compute.Inputs.URLMapHostRuleArgs
{
Hosts = new[]
{
"mysite.com",
},
PathMatcher = "mysite",
},
},
PathMatchers = new[]
{
new Gcp.Compute.Inputs.URLMapPathMatcherArgs
{
Name = "mysite",
DefaultService = example.Id,
DefaultCustomErrorResponsePolicy = new Gcp.Compute.Inputs.URLMapPathMatcherDefaultCustomErrorResponsePolicyArgs
{
ErrorResponseRules = new[]
{
new Gcp.Compute.Inputs.URLMapPathMatcherDefaultCustomErrorResponsePolicyErrorResponseRuleArgs
{
MatchResponseCodes = new[]
{
"4xx",
"5xx",
},
Path = "/login_error.html",
OverrideResponseCode = 404,
},
new Gcp.Compute.Inputs.URLMapPathMatcherDefaultCustomErrorResponsePolicyErrorResponseRuleArgs
{
MatchResponseCodes = new[]
{
"503",
},
Path = "/bad_gateway.html",
OverrideResponseCode = 502,
},
},
ErrorService = error.Id,
},
PathRules = new[]
{
new Gcp.Compute.Inputs.URLMapPathMatcherPathRuleArgs
{
Paths = new[]
{
"/private/*",
},
Service = example.Id,
CustomErrorResponsePolicy = new Gcp.Compute.Inputs.URLMapPathMatcherPathRuleCustomErrorResponsePolicyArgs
{
ErrorResponseRules = new[]
{
new Gcp.Compute.Inputs.URLMapPathMatcherPathRuleCustomErrorResponsePolicyErrorResponseRuleArgs
{
MatchResponseCodes = new[]
{
"4xx",
},
Path = "/login.html",
OverrideResponseCode = 401,
},
},
ErrorService = error.Id,
},
},
},
},
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.compute.HttpHealthCheck;
import com.pulumi.gcp.compute.HttpHealthCheckArgs;
import com.pulumi.gcp.compute.BackendService;
import com.pulumi.gcp.compute.BackendServiceArgs;
import com.pulumi.gcp.storage.Bucket;
import com.pulumi.gcp.storage.BucketArgs;
import com.pulumi.gcp.compute.BackendBucket;
import com.pulumi.gcp.compute.BackendBucketArgs;
import com.pulumi.gcp.compute.URLMap;
import com.pulumi.gcp.compute.URLMapArgs;
import com.pulumi.gcp.compute.inputs.URLMapDefaultCustomErrorResponsePolicyArgs;
import com.pulumi.gcp.compute.inputs.URLMapHostRuleArgs;
import com.pulumi.gcp.compute.inputs.URLMapPathMatcherArgs;
import com.pulumi.gcp.compute.inputs.URLMapPathMatcherDefaultCustomErrorResponsePolicyArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
public class App {
public static void main(String[] args) {
Pulumi.run(App::stack);
}
public static void stack(Context ctx) {
var default_ = new HttpHealthCheck("default", HttpHealthCheckArgs.builder()
.name("health-check")
.requestPath("/")
.checkIntervalSec(1)
.timeoutSec(1)
.build());
var example = new BackendService("example", BackendServiceArgs.builder()
.name("login")
.portName("http")
.protocol("HTTP")
.timeoutSec(10)
.loadBalancingScheme("EXTERNAL_MANAGED")
.healthChecks(default_.id())
.build());
var errorBucket = new Bucket("errorBucket", BucketArgs.builder()
.name("static-asset-bucket")
.location("US")
.build());
var error = new BackendBucket("error", BackendBucketArgs.builder()
.name("error-backend-bucket")
.bucketName(errorBucket.name())
.enableCdn(true)
.build());
var urlmap = new URLMap("urlmap", URLMapArgs.builder()
.name("urlmap")
.description("a description")
.defaultService(example.id())
.defaultCustomErrorResponsePolicy(URLMapDefaultCustomErrorResponsePolicyArgs.builder()
.errorResponseRules(URLMapDefaultCustomErrorResponsePolicyErrorResponseRuleArgs.builder()
.matchResponseCodes("5xx")
.path("/internal_error.html")
.overrideResponseCode(502)
.build())
.errorService(error.id())
.build())
.hostRules(URLMapHostRuleArgs.builder()
.hosts("mysite.com")
.pathMatcher("mysite")
.build())
.pathMatchers(URLMapPathMatcherArgs.builder()
.name("mysite")
.defaultService(example.id())
.defaultCustomErrorResponsePolicy(URLMapPathMatcherDefaultCustomErrorResponsePolicyArgs.builder()
.errorResponseRules(
URLMapPathMatcherDefaultCustomErrorResponsePolicyErrorResponseRuleArgs.builder()
.matchResponseCodes(
"4xx",
"5xx")
.path("/login_error.html")
.overrideResponseCode(404)
.build(),
URLMapPathMatcherDefaultCustomErrorResponsePolicyErrorResponseRuleArgs.builder()
.matchResponseCodes("503")
.path("/bad_gateway.html")
.overrideResponseCode(502)
.build())
.errorService(error.id())
.build())
.pathRules(URLMapPathMatcherPathRuleArgs.builder()
.paths("/private/*")
.service(example.id())
.customErrorResponsePolicy(URLMapPathMatcherPathRuleCustomErrorResponsePolicyArgs.builder()
.errorResponseRules(URLMapPathMatcherPathRuleCustomErrorResponsePolicyErrorResponseRuleArgs.builder()
.matchResponseCodes("4xx")
.path("/login.html")
.overrideResponseCode(401)
.build())
.errorService(error.id())
.build())
.build())
.build())
.build());
}
}
resources:
urlmap:
type: gcp:compute:URLMap
properties:
name: urlmap
description: a description
defaultService: ${example.id}
defaultCustomErrorResponsePolicy:
errorResponseRules:
- matchResponseCodes:
- 5xx
path: /internal_error.html
overrideResponseCode: 502
errorService: ${error.id}
hostRules:
- hosts:
- mysite.com
pathMatcher: mysite
pathMatchers:
- name: mysite
defaultService: ${example.id}
defaultCustomErrorResponsePolicy:
errorResponseRules:
- matchResponseCodes:
- 4xx
- 5xx
path: /login_error.html
overrideResponseCode: 404
- matchResponseCodes:
- '503'
path: /bad_gateway.html
overrideResponseCode: 502
errorService: ${error.id}
pathRules:
- paths:
- /private/*
service: ${example.id}
customErrorResponsePolicy:
errorResponseRules:
- matchResponseCodes:
- 4xx
path: /login.html
overrideResponseCode: 401
errorService: ${error.id}
example:
type: gcp:compute:BackendService
properties:
name: login
portName: http
protocol: HTTP
timeoutSec: 10
loadBalancingScheme: EXTERNAL_MANAGED
healthChecks: ${default.id}
default:
type: gcp:compute:HttpHealthCheck
properties:
name: health-check
requestPath: /
checkIntervalSec: 1
timeoutSec: 1
error:
type: gcp:compute:BackendBucket
properties:
name: error-backend-bucket
bucketName: ${errorBucket.name}
enableCdn: true
errorBucket:
type: gcp:storage:Bucket
name: error
properties:
name: static-asset-bucket
location: US
The defaultCustomErrorResponsePolicy property defines error handling at the URL map level. The errorResponseRules array maps response codes to custom pages. The matchResponseCodes array accepts specific codes or ranges like 4xx and 5xx. The path property points to an HTML file in the errorService backend bucket. The overrideResponseCode changes the HTTP status code returned to clients. Path matchers can override these defaults with their own customErrorResponsePolicy.
Beyond these examples
These snippets focus on specific URL map features: path and host-based routing, header and query parameter matching, request transformation and traffic mirroring, and custom error handling. They’re intentionally minimal rather than full load balancer configurations.
The examples reference pre-existing infrastructure such as backend services with health checks, backend buckets for static content or error pages, and Cloud Storage buckets. They focus on configuring the URL map rather than provisioning the complete load balancing stack.
To keep things focused, common URL map patterns are omitted, including:
- Default route actions and URL redirects (defaultRouteAction, defaultUrlRedirect)
- Traffic mirroring percentage controls across different scopes
- HTTP filter configurations for service mesh (httpFilterConfigs, httpFilterMetadatas)
- Test validation with headers and expected outputs (tests property)
These omissions are intentional: the goal is to illustrate how each routing feature is wired, not provide drop-in load balancer modules. See the URL Map resource reference for all available configuration options.
Let's configure GCP URL Maps for Load Balancing
Get started with Pulumi Cloud, then follow our quick setup guide to deploy this infrastructure.
Try Pulumi Cloud for FREEFrequently Asked Questions
Core Routing & Configuration
pathRules provide simple path-based routing to services using a paths array. routeRules offer advanced routing with explicit priority, header/query parameter matching, and complex actions like URL rewrites and fault injection.defaultRouteAction specifies weightedBackendServices, you cannot set defaultService. Conversely, if defaultService is set, defaultRouteAction cannot contain weightedBackendServices.defaultRouteAction or defaultUrlRedirect can be set. Use defaultRouteAction for backend routing or defaultUrlRedirect for redirects.hostRules map incoming hostnames to named pathMatchers. Each pathMatcher contains the routing rules (pathRules or routeRules) that apply to requests matching those hosts.INTERNAL_SELF_MANAGED (for Traffic Director), EXTERNAL_MANAGED (for Application Load Balancers), and standard external load balancing. Some features like custom error response policies require EXTERNAL_MANAGED.Advanced Routing & Matching
routeRule must have an explicit priority value. For example, a rule with priority: 1 is evaluated before priority: 2.routeRules with matchRules containing headerMatches. For example, route A/B test traffic by matching the abtest header with exactMatch: "a" or exactMatch: "b".routeRules with matchRules containing queryParameterMatches. You can match on parameter name and value, or check for parameter presence with presentMatch: true.pathTemplateMatch with wildcards (* for single segment, ** for multiple segments) to capture URL parts, then use pathTemplateRewrite to transform them. For example, /users/{username=*}/carts/{cartid=**} can be rewritten to /{username}-{cartid}/.Error Handling & Resilience
requestMirrorPolicy can be configured at four levels: defaultRouteAction, pathMatcher defaultRouteAction, pathRule routeAction, and routeRule. Each level can specify a different mirrorPercent.Configuration Constraints & Validation
name must be 1-63 characters long, start with a lowercase letter, contain only lowercase letters, digits, or dashes, and cannot end with a dash. The name is immutable after creation.tests property validates routing behavior. Updates fail if any test doesn’t pass. You can specify up to 100 tests with host, path, expected service, and optional headers, expectedOutputUrl, or expectedRedirectResponseCode.headers for custom request headers, expectedOutputUrl for redirect validation, and expectedRedirectResponseCode for verifying redirect status codes (e.g., 301, 302).Using a different cloud?
Explore networking guides for other cloud providers: