Skip to content

Commit e04ed3c

Browse files
authored
feat(lb) add support for path-begin route matching (#3082)
* bump sdk go * feat(lb) add support for path-begin route matching * fix
1 parent d48c805 commit e04ed3c

File tree

7 files changed

+2324
-14
lines changed

7 files changed

+2324
-14
lines changed

docs/data-sources/lb_routes.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,4 +40,5 @@ In addition to all arguments above, the following attributes are exported:
4040
- `update_at` - The date on which the route was last updated (RFC 3339 format).
4141
- `match_subdomains` - If true, all subdomains will match.
4242
- `match_sni` - Server Name Indication TLS extension field from an incoming connection made via an SSL/TLS transport layer.
43-
- `match_host_header` - Specifies the host of the server to which the request is being sent.
43+
- `match_host_header` - Specifies the host of the server to which the request is being sent.
44+
- `match_path_begin` - The value to match in the URL beginning path from an incoming request.

docs/resources/lb_route.md

Lines changed: 48 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,50 @@ resource "scaleway_lb_route" "rt01" {
7373
}
7474
```
7575

76+
### With path-begin matching for HTTP backends
77+
78+
```terraform
79+
resource "scaleway_lb_ip" "ip" {}
80+
81+
resource "scaleway_lb" "lb" {
82+
ip_id = scaleway_lb_ip.ip.id
83+
name = "my-lb"
84+
type = "lb-s"
85+
}
86+
87+
resource "scaleway_lb_backend" "app" {
88+
lb_id = scaleway_lb.lb.id
89+
forward_protocol = "http"
90+
forward_port = 80
91+
proxy_protocol = "none"
92+
}
93+
94+
resource "scaleway_lb_backend" "admin" {
95+
lb_id = scaleway_lb.lb.id
96+
forward_protocol = "http"
97+
forward_port = 8080
98+
proxy_protocol = "none"
99+
}
100+
101+
resource "scaleway_lb_frontend" "frontend" {
102+
lb_id = scaleway_lb.lb.id
103+
backend_id = scaleway_lb_backend.app.id
104+
inbound_port = 80
105+
}
106+
107+
resource "scaleway_lb_route" "admin_route" {
108+
frontend_id = scaleway_lb_frontend.frontend.id
109+
backend_id = scaleway_lb_backend.admin.id
110+
match_path_begin = "/admin"
111+
}
112+
113+
resource "scaleway_lb_route" "default_route" {
114+
frontend_id = scaleway_lb_frontend.frontend.id
115+
backend_id = scaleway_lb_backend.app.id
116+
match_path_begin = "/"
117+
}
118+
```
119+
76120
## Argument Reference
77121

78122
The following arguments are supported:
@@ -81,15 +125,17 @@ The following arguments are supported:
81125
- `frontend_id` - (Required) The ID of the frontend the route is associated with.
82126
- `match_subdomains` - (Default: `false`) If true, all subdomains will match.
83127
- `match_sni` - The Server Name Indication (SNI) value to match. Value to match in the Server Name Indication TLS extension (SNI) field from an incoming connection made via an SSL/TLS transport layer.
84-
Only one of `match_sni` and `match_host_header` should be specified.
128+
Only one of `match_sni`, `match_host_header` and `match_path_begin` should be specified.
85129

86130
~> **Important:** This field should be set for routes on TCP Load Balancers.
87131

88132
- `match_host_header` - The HTTP host header to match. Value to match in the HTTP Host request header from an incoming connection.
89-
Only one of `match_sni` and `match_host_header` should be specified.
133+
Only one of `match_sni`, `match_host_header` and `match_path_begin` should be specified.
90134

91135
~> **Important:** This field should be set for routes on HTTP Load Balancers.
92136

137+
- `match_path_begin` - The value to match in the URL beginning path from an incoming request.
138+
Only one of `match_sni`, `match_host_header` and `match_path_begin` should be specified.
93139
- `zone` - (Defaults to [provider](../index.md#zone) `zone`) The [zone](../guides/regions_and_zones.md#zones) in which the Load Balancer was created.
94140

95141
## Attributes Reference

go.mod

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ require (
2727
github.com/nats-io/jwt/v2 v2.7.4
2828
github.com/nats-io/nats.go v1.38.0
2929
github.com/robfig/cron/v3 v3.0.1
30-
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.33.0.20250424152954-b4babe8f214c
30+
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.33.0.20250512145715-0fc65cc3636b
3131
github.com/stretchr/testify v1.10.0
3232
golang.org/x/crypto v0.37.0
3333
gopkg.in/dnaeon/go-vcr.v3 v3.2.0
@@ -135,9 +135,9 @@ require (
135135
golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df // indirect
136136
golang.org/x/mod v0.23.0 // indirect
137137
golang.org/x/net v0.38.0 // indirect
138-
golang.org/x/sync v0.13.0 // indirect
138+
golang.org/x/sync v0.14.0 // indirect
139139
golang.org/x/sys v0.32.0 // indirect
140-
golang.org/x/text v0.24.0 // indirect
140+
golang.org/x/text v0.25.0 // indirect
141141
golang.org/x/time v0.3.0 // indirect
142142
golang.org/x/tools v0.30.0 // indirect
143143
google.golang.org/appengine v1.6.8 // indirect

go.sum

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -298,8 +298,8 @@ github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
298298
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
299299
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
300300
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
301-
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.33.0.20250424152954-b4babe8f214c h1:sjbNFhI3o5ecQuxLZv54Gm/YlqP55Ot5l7ShneWeNg8=
302-
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.33.0.20250424152954-b4babe8f214c/go.mod h1:w4o02EHpO0CBGy2nehzWRaFQKd62G9HIf+Q07PDaUcE=
301+
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.33.0.20250512145715-0fc65cc3636b h1:wzu3hPSNK2PPo7OXBzofeS5hOWqnVRP8xqIXom9ufoc=
302+
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.33.0.20250512145715-0fc65cc3636b/go.mod h1:qiGzapFyNPFwBBLJ+hTFykKSnU95n1zL64+o1ubmwf0=
303303
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8=
304304
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4=
305305
github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
@@ -401,8 +401,8 @@ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJ
401401
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
402402
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
403403
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
404-
golang.org/x/sync v0.13.0 h1:AauUjRAJ9OSnvULf/ARrrVywoJDy0YS2AwQ98I37610=
405-
golang.org/x/sync v0.13.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
404+
golang.org/x/sync v0.14.0 h1:woo0S4Yywslg6hp4eUFjTVOyKt0RookbpAHG4c1HmhQ=
405+
golang.org/x/sync v0.14.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
406406
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
407407
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
408408
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -439,8 +439,8 @@ golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
439439
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
440440
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
441441
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
442-
golang.org/x/text v0.24.0 h1:dd5Bzh4yt5KYA8f9CJHCP4FB4D51c2c6JvN37xJJkJ0=
443-
golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU=
442+
golang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4=
443+
golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA=
444444
golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
445445
golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
446446
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=

internal/services/lb/route.go

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,13 +47,19 @@ func ResourceRoute() *schema.Resource {
4747
Type: schema.TypeString,
4848
Optional: true,
4949
Description: "Server Name Indication TLS extension field from an incoming connection made via an SSL/TLS transport layer",
50-
ConflictsWith: []string{"match_host_header"},
50+
ConflictsWith: []string{"match_host_header", "match_path_begin"},
5151
},
5252
"match_host_header": {
5353
Type: schema.TypeString,
5454
Optional: true,
5555
Description: "Specifies the host of the server to which the request is being sent",
56-
ConflictsWith: []string{"match_sni"},
56+
ConflictsWith: []string{"match_sni", "match_path_begin"},
57+
},
58+
"match_path_begin": {
59+
Type: schema.TypeString,
60+
Optional: true,
61+
Description: "Value to match in the URL beginning path from an incoming request",
62+
ConflictsWith: []string{"match_sni", "match_host_header"},
5763
},
5864
"match_subdomains": {
5965
Type: schema.TypeBool,
@@ -102,6 +108,7 @@ func resourceLbRouteCreate(ctx context.Context, d *schema.ResourceData, m interf
102108
Match: &lbSDK.RouteMatch{
103109
Sni: types.ExpandStringPtr(d.Get("match_sni")),
104110
HostHeader: types.ExpandStringPtr(d.Get("match_host_header")),
111+
PathBegin: types.ExpandStringPtr(d.Get("match_path_begin")),
105112
MatchSubdomains: d.Get("match_subdomains").(bool),
106113
},
107114
}
@@ -140,6 +147,7 @@ func resourceLbRouteRead(ctx context.Context, d *schema.ResourceData, m interfac
140147
_ = d.Set("backend_id", zonal.NewIDString(zone, route.BackendID))
141148
_ = d.Set("match_sni", types.FlattenStringPtr(route.Match.Sni))
142149
_ = d.Set("match_host_header", types.FlattenStringPtr(route.Match.HostHeader))
150+
_ = d.Set("match_path_begin", types.FlattenStringPtr(route.Match.PathBegin))
143151
_ = d.Set("match_subdomains", route.Match.MatchSubdomains)
144152
_ = d.Set("created_at", types.FlattenTime(route.CreatedAt))
145153
_ = d.Set("updated_at", types.FlattenTime(route.UpdatedAt))
@@ -169,6 +177,7 @@ func resourceLbRouteUpdate(ctx context.Context, d *schema.ResourceData, m interf
169177
Match: &lbSDK.RouteMatch{
170178
Sni: types.ExpandStringPtr(d.Get("match_sni")),
171179
HostHeader: types.ExpandStringPtr(d.Get("match_host_header")),
180+
PathBegin: types.ExpandStringPtr(d.Get("match_path_begin")),
172181
MatchSubdomains: d.Get("match_subdomains").(bool),
173182
},
174183
}

internal/services/lb/route_test.go

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,50 @@ func TestAccRoute_WithHostHeader(t *testing.T) {
135135
})
136136
}
137137

138+
func TestAccRoute_WithPathBegin(t *testing.T) {
139+
tt := acctest.NewTestTools(t)
140+
defer tt.Cleanup()
141+
resource.ParallelTest(t, resource.TestCase{
142+
PreCheck: func() { acctest.PreCheck(t) },
143+
ProviderFactories: tt.ProviderFactories,
144+
CheckDestroy: isRouteDestroyed(tt),
145+
Steps: []resource.TestStep{
146+
{
147+
Config: `
148+
resource scaleway_lb_ip ip01 {}
149+
resource scaleway_lb lb01 {
150+
ip_id = scaleway_lb_ip.ip01.id
151+
name = "test-lb"
152+
type = "lb-s"
153+
}
154+
resource scaleway_lb_backend bkd01 {
155+
lb_id = scaleway_lb.lb01.id
156+
forward_protocol = "http"
157+
forward_port = 80
158+
proxy_protocol = "none"
159+
}
160+
resource scaleway_lb_frontend frt01 {
161+
lb_id = scaleway_lb.lb01.id
162+
backend_id = scaleway_lb_backend.bkd01.id
163+
inbound_port = 80
164+
}
165+
resource scaleway_lb_route rt01 {
166+
frontend_id = scaleway_lb_frontend.frt01.id
167+
backend_id = scaleway_lb_backend.bkd01.id
168+
match_path_begin = "/api"
169+
}
170+
`,
171+
Check: resource.ComposeTestCheckFunc(
172+
isRoutePresent(tt, "scaleway_lb_route.rt01"),
173+
resource.TestCheckResourceAttr("scaleway_lb_route.rt01", "match_path_begin", "/api"),
174+
resource.TestCheckResourceAttrSet("scaleway_lb_route.rt01", "created_at"),
175+
resource.TestCheckResourceAttrSet("scaleway_lb_route.rt01", "updated_at"),
176+
),
177+
},
178+
},
179+
})
180+
}
181+
138182
func isRoutePresent(tt *acctest.TestTools, n string) resource.TestCheckFunc {
139183
return func(s *terraform.State) error {
140184
rs, ok := s.RootModule().Resources[n]

0 commit comments

Comments
 (0)