The gcp:compute/uRLMap:URLMap resource, part of the Pulumi GCP provider, defines routing rules that direct incoming requests to backend services or backend buckets based on hostname, path, headers, and query parameters. This guide focuses on four capabilities: host and path-based routing, header and query parameter matching, Traffic Director route actions, and custom error responses.
URL maps depend on backend services (with health checks) and backend buckets that must exist before you configure routing. The examples are intentionally small. Combine them with your own backend infrastructure and load balancing configuration.
Route requests across backend services and storage buckets
Most load balancers route 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 array maps hostnames to path matchers. Each pathMatcher defines a defaultService and optional pathRules that route specific paths to different backends. The defaultService handles requests that don’t match any pathRule. This configuration sends requests for /home and /static to a Cloud Storage bucket, while /login goes to a backend service.
Route traffic based on request headers
A/B testing and canary deployments 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
Route rules use matchRules to inspect request properties. The headerMatches array checks header values; here, requests with abtest: a go to service-a, while abtest: b goes to service-b. The priority field determines evaluation order (lower numbers first). Route rules provide more flexibility than path rules, enabling header-based, parameter-based, and metadata-based routing.
Route traffic based on query parameters
Query parameter routing enables feature flags and experimentation by inspecting 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 works like headerMatches but inspects query strings. Requests with ?abtest=a route to service-a, while ?abtest=b routes to service-b. This enables feature toggling without requiring custom headers or cookies.
Configure advanced routing with Traffic Director
Traffic Director enables service mesh capabilities including header manipulation, redirects, and metadata filtering for internal load balancing.
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
Route rules can include headerAction to modify request and response headers, urlRedirect to redirect requests, and metadataFilters to match on service mesh metadata. The headerAction adds or removes headers; urlRedirect specifies the redirect target and response code. This example removes headers, adds new ones, and redirects matching requests to a different host and path.
Apply traffic policies with route actions
Route actions enable sophisticated traffic management including CORS policies, fault injection, request mirroring, retries, and URL rewriting.
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 configures advanced behaviors. The corsPolicy enables cross-origin requests with specific headers and methods. The faultInjectionPolicy simulates failures for testing. The retryPolicy configures automatic retries with backoff. The urlRewrite modifies the request before forwarding. The weightedBackendServices array distributes traffic across backends with weights.
Match and rewrite paths using templates
Path templates enable pattern matching with variable extraction, allowing you to capture URL segments and rewrite them for backend services.
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 a template syntax with wildcards (* for single segment, ** for multiple segments) and named variables ({username=*}). The pathTemplateRewrite property references these variables to construct new paths. This example captures username and cart ID from the URL and rewrites the path to /{username}-{cartid}/ before forwarding to the backend.
Customize error responses at multiple levels
When backend services return errors, you can serve custom error pages from Cloud Storage instead of default error responses.
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 configures error handling at the URL map level. The errorResponseRules array maps response codes to custom error pages. The matchResponseCodes field accepts specific codes or ranges like 4xx and 5xx. The path field specifies the error page location in the errorService backend bucket. You can override this policy at the path matcher and path rule levels for more granular control.
Beyond these examples
These snippets focus on specific URL map features: path and host-based routing, header and query parameter matching, Traffic Director route actions (CORS, fault injection, retries), and custom error responses. They’re intentionally minimal rather than full load balancing configurations.
The examples reference pre-existing infrastructure such as backend services with health checks, backend buckets (Cloud Storage), and load balancing scheme configuration (INTERNAL_SELF_MANAGED or EXTERNAL_MANAGED). They focus on configuring routing rules rather than provisioning the complete load balancing stack.
To keep things focused, common URL map patterns are omitted, including:
- Request mirroring configuration (requestMirrorPolicy with mirrorPercent)
- URL redirect rules (urlRedirect at various levels)
- HTTP filter configurations for service mesh (httpFilterConfigs, httpFilterMetadata)
- Test configuration (tests array for validation)
- Default route actions (defaultRouteAction)
These omissions are intentional: the goal is to illustrate how each routing feature is wired, not provide drop-in load balancing 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
Configuration & Setup
defaultRouteAction specifies weightedBackendServices, you cannot set defaultService. Conversely, if defaultService is set, defaultRouteAction cannot contain weightedBackendServices. Choose one approach for your routing needs.defaultRouteAction or defaultUrlRedirect can be set. Use defaultRouteAction for backend routing or defaultUrlRedirect for redirects, but not both.defaultCustomErrorResponsePolicy) are only supported for global external Application Load Balancers. Verify your load balancer type matches this requirement.Routing Mechanisms
pathRules provide simple path-to-service mapping within a pathMatcher. routeRules offer advanced, priority-based routing with complex matching logic (headers, query parameters, metadata) and actions like URL rewrites and header transformations.routeRules with matchRules containing headerMatches. Set different priorities and services for each variant. For example, route requests with header abtest: a to service A and abtest: b to service B.routeRules with matchRules containing queryParameterMatches. Specify the parameter name and match criteria (exact, present, regex) to route to different backend services.pathTemplateMatch in matchRules with variable placeholders like {username=*} or {cartid=**}. You can extract these variables and rewrite URLs using pathTemplateRewrite in the routeAction.Advanced Features
requestMirrorPolicy: URL map level (defaultRouteAction), path matcher level (defaultRouteAction), individual path rules (routeAction), or route rules. Specify the backendService and mirrorPercent (0-100) at your chosen level.routeAction supports CORS policies, fault injection (delays and aborts), request mirroring, retry policies with configurable conditions, timeouts, URL rewrites (host and path), and weighted backend services for traffic splitting.urlRewrite within routeAction to specify hostRewrite for changing the host and pathPrefixRewrite for modifying the path. For dynamic rewrites, use pathTemplateRewrite with path template variables.Testing & Validation
tests array (max 100). Each test specifies host, path, expected service, and optionally headers, expectedOutputUrl, and expectedRedirectResponseCode. Updates only succeed if all tests pass.Limitations & Constraints
name must be 1-63 characters long, comply with RFC1035, and match the pattern a-z?. It must start with a lowercase letter, contain only lowercase letters, digits, or dashes, and cannot end with a dash. The name is immutable after creation.Using a different cloud?
Explore networking guides for other cloud providers: