config: support weighted URLs in To field (#5624)

## Summary
Currently in core we support weighted URLs like this in the config file:

```yaml
to: 
  - https://a.example.com,1
  - https://b.example.com,2
```

However in the protobuf we use a separate `load_balancing_weights`
field:

```proto
message Route {
  repeated string to                     = 3;
  repeated uint32 load_balancing_weights = 37;
}
```

This PR updates the code to convert from protobuf so that it also
supports weights directly in the `to` addresses. The existing
`load_balancing_weights` behavior is preserved and will take precedence
when provided.

## Related issues
-
[ENG-2398](https://linear.app/pomerium/issue/ENG-2398/enterprise-api-upstream-weight-is-not-parsed)

## Checklist
- [x] reference any related issues
- [x] updated unit tests
- [x] add appropriate label (`enhancement`, `bug`, `breaking`,
`dependencies`, `ci`)
- [x] ready for review
This commit is contained in:
Caleb Doxsey 2025-05-20 12:15:10 -06:00 committed by GitHub
parent 7a6d7c5a3c
commit 46865b596e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 29 additions and 13 deletions

View file

@ -4,6 +4,7 @@ import (
"crypto/tls"
"encoding/base64"
"encoding/hex"
"errors"
"fmt"
"net/http"
"net/url"
@ -415,19 +416,16 @@ func NewPolicyFromProto(pb *configpb.Route) (*Policy, error) {
Body: pb.Response.GetBody(),
}
} else {
p.To = make(WeightedURLs, len(pb.To))
for i, u := range pb.To {
u, err := urlutil.ParseAndValidateURL(u)
if err != nil {
return nil, err
var err error
p.To, err = ParseWeightedUrls(pb.To...)
if err != nil && !errors.Is(err, errEmptyUrls) {
return nil, fmt.Errorf("error parsing to URLs: %w", err)
}
if len(pb.LoadBalancingWeights) == len(p.To) {
for i, w := range pb.LoadBalancingWeights {
p.To[i].LbWeight = w
}
w := WeightedURL{
URL: *u,
}
if len(pb.LoadBalancingWeights) == len(pb.To) {
w.LbWeight = pb.LoadBalancingWeights[i]
}
p.To[i] = w
}
}

View file

@ -16,6 +16,7 @@ import (
"github.com/pomerium/pomerium/internal/urlutil"
"github.com/pomerium/pomerium/pkg/cryptutil"
"github.com/pomerium/pomerium/pkg/grpc/config"
)
func Test_PolicyValidate(t *testing.T) {
@ -213,6 +214,23 @@ func TestPolicy_Checksum(t *testing.T) {
}
}
func TestNewPolicyFromProto(t *testing.T) {
t.Parallel()
p, err := NewPolicyFromProto(&config.Route{
To: []string{"http://127.0.0.1:1234,1", "http://127.0.0.1:1234,2"},
})
assert.NoError(t, err)
assert.Equal(t, mustParseWeightedURLs(t, "http://127.0.0.1:1234,1", "http://127.0.0.1:1234,2"), p.To)
p, err = NewPolicyFromProto(&config.Route{
To: []string{"http://127.0.0.1:1234,1", "http://127.0.0.1:1234,2"},
LoadBalancingWeights: []uint32{3, 4},
})
assert.NoError(t, err)
assert.Equal(t, mustParseWeightedURLs(t, "http://127.0.0.1:1234,3", "http://127.0.0.1:1234,4"), p.To)
}
func TestPolicy_FromToPb(t *testing.T) {
t.Parallel()
@ -442,7 +460,7 @@ func TestPolicy_IsTCPUpstream(t *testing.T) {
assert.False(t, p3.IsTCPUpstream())
}
func mustParseWeightedURLs(t testing.TB, urls ...string) []WeightedURL {
func mustParseWeightedURLs(t testing.TB, urls ...string) WeightedURLs {
wu, err := ParseWeightedUrls(urls...)
require.NoError(t, err)
return wu