diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 000000000000..deb08ca9c794 --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,4 @@ +Thank you for your PR. Please read and follow +https://github.com/grpc/grpc-go/blob/master/CONTRIBUTING.md, especially the +"Guidelines for Pull Requests" section, and then delete this text before +entering your PR description. diff --git a/.github/workflows/testing.yml b/.github/workflows/testing.yml index 51dd0c9e4123..7440e36c35b7 100644 --- a/.github/workflows/testing.yml +++ b/.github/workflows/testing.yml @@ -27,7 +27,7 @@ jobs: - name: Setup Go uses: actions/setup-go@v5 with: - go-version: '1.24' + go-version: '1.25' cache-dependency-path: "**/go.sum" # Run the vet-proto checks. @@ -45,32 +45,32 @@ jobs: matrix: include: - type: vet - goversion: '1.23' + goversion: '1.24' - type: extras - goversion: '1.24' + goversion: '1.25' - type: tests - goversion: '1.24' + goversion: '1.25' - type: tests - goversion: '1.24' + goversion: '1.25' testflags: -race - type: tests - goversion: '1.24' + goversion: '1.25' goarch: 386 - type: tests - goversion: '1.24' + goversion: '1.25' goarch: arm64 runner: ubuntu-24.04-arm - type: tests - goversion: '1.23' + goversion: '1.24' - type: tests - goversion: '1.24' + goversion: '1.25' testflags: -race grpcenv: 'GRPC_EXPERIMENTAL_ENABLE_NEW_PICK_FIRST=false' @@ -125,7 +125,7 @@ jobs: echo -e "\n-- Running Interop Test --" interop/interop_test.sh echo -e "\n-- Running xDS E2E Test --" - xds/internal/test/e2e/run.sh + internal/xds/test/e2e/run.sh echo -e "\n-- Running protoc-gen-go-grpc test --" ./scripts/vet-proto.sh -install cmd/protoc-gen-go-grpc/protoc-gen-go-grpc_test.sh diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 1de0ce66691d..2079de7b0ed8 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -33,17 +33,21 @@ guidelines, there may be valid reasons to do so, but it should be rare. ## Guidelines for Pull Requests -How to get your contributions merged smoothly and quickly: +Please read the following carefully to ensure your contributions can be merged +smoothly and quickly. + +### PR Contents - Create **small PRs** that are narrowly focused on **addressing a single concern**. We often receive PRs that attempt to fix several things at the same time, and if one part of the PR has a problem, that will hold up the entire PR. -- For **speculative changes**, consider opening an issue and discussing it - first. If you are suggesting a behavioral or API change, consider starting - with a [gRFC proposal](https://github.com/grpc/proposal). Many new features - that are not bug fixes will require cross-language agreement. +- If your change does not address an **open issue** with an **agreed + resolution**, consider opening an issue and discussing it first. If you are + suggesting a behavioral or API change, consider starting with a [gRFC + proposal](https://github.com/grpc/proposal). Many new features that are not + bug fixes will require cross-language agreement. - If you want to fix **formatting or style**, consider whether your changes are an obvious improvement or might be considered a personal preference. If a @@ -56,16 +60,6 @@ How to get your contributions merged smoothly and quickly: often written as "iff". Please do not make spelling correction changes unless you are certain they are misspellings. -- Provide a good **PR description** as a record of **what** change is being made - and **why** it was made. Link to a GitHub issue if it exists. - -- Maintain a **clean commit history** and use **meaningful commit messages**. - PRs with messy commit histories are difficult to review and won't be merged. - Before sending your PR, ensure your changes are based on top of the latest - `upstream/master` commits, and avoid rebasing in the middle of a code review. - You should **never use `git push -f`** unless absolutely necessary during a - review, as it can interfere with GitHub's tracking of comments. - - **All tests need to be passing** before your change can be merged. We recommend you run tests locally before creating your PR to catch breakages early on: @@ -81,15 +75,80 @@ How to get your contributions merged smoothly and quickly: GitHub, which will trigger a GitHub Actions run that you can use to verify everything is passing. -- If you are adding a new file, make sure it has the **copyright message** +- Note that there are two GitHub actions checks that need not be green: + + 1. We test the freshness of the generated proto code we maintain via the + `vet-proto` check. If the source proto files are updated, but our repo is + not updated, an optional checker will fail. This will be fixed by our team + in a separate PR and will not prevent the merge of your PR. + + 2. We run a checker that will fail if there is any change in dependencies of + an exported package via the `dependencies` check. If new dependencies are + added that are not appropriate, we may not accept your PR (see below). + +- If you are adding a **new file**, make sure it has the **copyright message** template at the top as a comment. You can copy the message from an existing file and update the year. - The grpc package should only depend on standard Go packages and a small number of exceptions. **If your contribution introduces new dependencies**, you will - need a discussion with gRPC-Go maintainers. A GitHub action check will run on - every PR, and will flag any transitive dependency changes from any public - package. + need a discussion with gRPC-Go maintainers. + +### PR Descriptions + +- **PR titles** should start with the name of the component being addressed, or + the type of change. Examples: transport, client, server, round_robin, xds, + cleanup, deps. + +- Read and follow the **guidelines for PR titles and descriptions** here: + https://google.github.io/eng-practices/review/developer/cl-descriptions.html + + *particularly* the sections "First Line" and "Body is Informative". + + Note: your PR description will be used as the git commit message in a + squash-and-merge if your PR is approved. We may make changes to this as + necessary. + +- **Does this PR relate to an open issue?** On the first line, please use the + tag `Fixes #` to ensure the issue is closed when the PR is merged. Or + use `Updates #` if the PR is related to an open issue, but does not fix + it. Consider filing an issue if one does not already exist. + +- PR descriptions *must* conclude with **release notes** as follows: + + ``` + RELEASE NOTES: + * : + ``` + + This need not match the PR title. + + The summary must: + + * be something that gRPC users will understand. + + * clearly explain the feature being added, the issue being fixed, or the + behavior being changed, etc. If fixing a bug, be clear about how the bug + can be triggered by an end-user. + + * begin with a capital letter and use complete sentences. + + * be as short as possible to describe the change being made. + + If a PR is *not* end-user visible -- e.g. a cleanup, testing change, or + GitHub-related, use `RELEASE NOTES: n/a`. + +### PR Process + +- Please **self-review** your code changes before sending your PR. This will + prevent simple, obvious errors from causing delays. + +- Maintain a **clean commit history** and use **meaningful commit messages**. + PRs with messy commit histories are difficult to review and won't be merged. + Before sending your PR, ensure your changes are based on top of the latest + `upstream/master` commits, and avoid rebasing in the middle of a code review. + You should **never use `git push -f`** unless absolutely necessary during a + review, as it can interfere with GitHub's tracking of comments. - Unless your PR is trivial, you should **expect reviewer comments** that you will need to address before merging. We'll label the PR as `Status: Requires @@ -98,5 +157,3 @@ How to get your contributions merged smoothly and quickly: `stale`, and we will automatically close it after 7 days if we don't hear back from you. Please feel free to ping issues or bugs if you do not get a response within a week. - -- Exceptions to the rules can be made if there's a compelling reason to do so. diff --git a/balancer/grpclb/grpclb_remote_balancer.go b/balancer/grpclb/grpclb_remote_balancer.go index f2df56120fec..002052120570 100644 --- a/balancer/grpclb/grpclb_remote_balancer.go +++ b/balancer/grpclb/grpclb_remote_balancer.go @@ -82,14 +82,8 @@ func (lb *lbBalancer) processServerList(l *lbpb.ServerList) { } md := metadata.Pairs(lbTokenKey, s.LoadBalanceToken) - ip := net.IP(s.IpAddress) - ipStr := ip.String() - if ip.To4() == nil { - // Add square brackets to ipv6 addresses, otherwise net.Dial() and - // net.SplitHostPort() will return too many colons error. - ipStr = fmt.Sprintf("[%s]", ipStr) - } - addr := imetadata.Set(resolver.Address{Addr: fmt.Sprintf("%s:%d", ipStr, s.Port)}, md) + ipStr := net.IP(s.IpAddress).String() + addr := imetadata.Set(resolver.Address{Addr: net.JoinHostPort(ipStr, fmt.Sprintf("%d", s.Port))}, md) if lb.logger.V(2) { lb.logger.Infof("Server list entry:|%d|, ipStr:|%s|, port:|%d|, load balancer token:|%v|", i, ipStr, s.Port, s.LoadBalanceToken) } diff --git a/balancer/pickfirst/pickfirst.go b/balancer/pickfirst/pickfirst.go index ea8899818c22..b15c10e46b0a 100644 --- a/balancer/pickfirst/pickfirst.go +++ b/balancer/pickfirst/pickfirst.go @@ -169,7 +169,7 @@ func (b *pickfirstBalancer) UpdateClientConnState(state balancer.ClientConnState addrs = state.ResolverState.Addresses if cfg.ShuffleAddressList { addrs = append([]resolver.Address{}, addrs...) - rand.Shuffle(len(addrs), func(i, j int) { addrs[i], addrs[j] = addrs[j], addrs[i] }) + internal.RandShuffle(len(addrs), func(i, j int) { addrs[i], addrs[j] = addrs[j], addrs[i] }) } } diff --git a/balancer/pickfirst/pickfirst_ext_test.go b/balancer/pickfirst/pickfirst_ext_test.go index 81691fc806ab..207fc4316f98 100644 --- a/balancer/pickfirst/pickfirst_ext_test.go +++ b/balancer/pickfirst/pickfirst_ext_test.go @@ -20,6 +20,7 @@ package pickfirst_test import ( "context" + "encoding/json" "errors" "fmt" "strings" @@ -28,11 +29,14 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/backoff" + "google.golang.org/grpc/balancer" + pfbalancer "google.golang.org/grpc/balancer/pickfirst" pfinternal "google.golang.org/grpc/balancer/pickfirst/internal" "google.golang.org/grpc/codes" "google.golang.org/grpc/connectivity" "google.golang.org/grpc/credentials/insecure" "google.golang.org/grpc/internal" + "google.golang.org/grpc/internal/balancer/stub" "google.golang.org/grpc/internal/channelz" "google.golang.org/grpc/internal/grpctest" "google.golang.org/grpc/internal/stubserver" @@ -463,6 +467,85 @@ func (s) TestPickFirst_ShuffleAddressList(t *testing.T) { } } +// Tests the PF LB policy with shuffling enabled. It explicitly unsets the +// Endpoints field in the resolver update to test the shuffling of the +// Addresses. +func (s) TestPickFirst_ShuffleAddressListNoEndpoints(t *testing.T) { + // Install a shuffler that always reverses two entries. + origShuf := pfinternal.RandShuffle + defer func() { pfinternal.RandShuffle = origShuf }() + pfinternal.RandShuffle = func(n int, f func(int, int)) { + if n != 2 { + t.Errorf("Shuffle called with n=%v; want 2", n) + return + } + f(0, 1) // reverse the two addresses + } + + pfBuilder := balancer.Get(pfbalancer.Name) + shuffleConfig, err := pfBuilder.(balancer.ConfigParser).ParseConfig(json.RawMessage(`{ "shuffleAddressList": true }`)) + if err != nil { + t.Fatal(err) + } + noShuffleConfig, err := pfBuilder.(balancer.ConfigParser).ParseConfig(json.RawMessage(`{ "shuffleAddressList": false }`)) + if err != nil { + t.Fatal(err) + } + var activeCfg serviceconfig.LoadBalancingConfig + + bf := stub.BalancerFuncs{ + Init: func(bd *stub.BalancerData) { + bd.ChildBalancer = pfBuilder.Build(bd.ClientConn, bd.BuildOptions) + }, + Close: func(bd *stub.BalancerData) { + bd.ChildBalancer.Close() + }, + UpdateClientConnState: func(bd *stub.BalancerData, ccs balancer.ClientConnState) error { + ccs.BalancerConfig = activeCfg + ccs.ResolverState.Endpoints = nil + return bd.ChildBalancer.UpdateClientConnState(ccs) + }, + } + + stub.Register(t.Name(), bf) + svcCfg := fmt.Sprintf(`{ "loadBalancingConfig": [{%q: {}}] }`, t.Name()) + // Set up our backends. + cc, r, backends := setupPickFirst(t, 2, grpc.WithDefaultServiceConfig(svcCfg)) + addrs := stubBackendsToResolverAddrs(backends) + + ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) + defer cancel() + + // Push an update with both addresses and shuffling disabled. We should + // connect to backend 0. + activeCfg = noShuffleConfig + resolverState := resolver.State{Addresses: addrs} + r.UpdateState(resolverState) + if err := pickfirst.CheckRPCsToBackend(ctx, cc, addrs[0]); err != nil { + t.Fatal(err) + } + + // Send a config with shuffling enabled. This will reverse the addresses, + // but the channel should still be connected to backend 0. + activeCfg = shuffleConfig + r.UpdateState(resolverState) + if err := pickfirst.CheckRPCsToBackend(ctx, cc, addrs[0]); err != nil { + t.Fatal(err) + } + + // Send a resolver update with no addresses. This should push the channel + // into TransientFailure. + r.UpdateState(resolver.State{}) + testutils.AwaitState(ctx, t, cc, connectivity.TransientFailure) + + // Send the same config as last time with shuffling enabled. Since we are + // not connected to backend 0, we should connect to backend 1. + r.UpdateState(resolverState) + if err := pickfirst.CheckRPCsToBackend(ctx, cc, addrs[1]); err != nil { + t.Fatal(err) + } +} + // Test config parsing with the env var turned on and off for various scenarios. func (s) TestPickFirst_ParseConfig_Success(t *testing.T) { // Install a shuffler that always reverses two entries. diff --git a/balancer/pickfirst/pickfirstleaf/pickfirstleaf.go b/balancer/pickfirst/pickfirstleaf/pickfirstleaf.go index 67f315a0dbc4..9ffdd28a01ef 100644 --- a/balancer/pickfirst/pickfirstleaf/pickfirstleaf.go +++ b/balancer/pickfirst/pickfirstleaf/pickfirstleaf.go @@ -283,7 +283,7 @@ func (b *pickfirstBalancer) UpdateClientConnState(state balancer.ClientConnState newAddrs = state.ResolverState.Addresses if cfg.ShuffleAddressList { newAddrs = append([]resolver.Address{}, newAddrs...) - internal.RandShuffle(len(endpoints), func(i, j int) { endpoints[i], endpoints[j] = endpoints[j], endpoints[i] }) + internal.RandShuffle(len(newAddrs), func(i, j int) { newAddrs[i], newAddrs[j] = newAddrs[j], newAddrs[i] }) } } @@ -351,6 +351,13 @@ func (b *pickfirstBalancer) ExitIdle() { b.mu.Lock() defer b.mu.Unlock() if b.state == connectivity.Idle { + // Move the balancer into CONNECTING state immediately. This is done to + // avoid staying in IDLE if a resolver update arrives before the first + // SubConn reports CONNECTING. + b.updateBalancerState(balancer.State{ + ConnectivityState: connectivity.Connecting, + Picker: &picker{err: balancer.ErrNoSubConnAvailable}, + }) b.startFirstPassLocked() } } @@ -604,7 +611,7 @@ func (b *pickfirstBalancer) updateSubConnState(sd *scData, newState balancer.Sub if !b.addressList.seekTo(sd.addr) { // This should not fail as we should have only one SubConn after // entering READY. The SubConn should be present in the addressList. - b.logger.Errorf("Address %q not found address list in %v", sd.addr, b.addressList.addresses) + b.logger.Errorf("Address %q not found address list in %v", sd.addr, b.addressList.addresses) return } if !b.healthCheckingEnabled { diff --git a/balancer/pickfirst/pickfirstleaf/pickfirstleaf_ext_test.go b/balancer/pickfirst/pickfirstleaf/pickfirstleaf_ext_test.go index df8c06f4e653..6b2fabe25260 100644 --- a/balancer/pickfirst/pickfirstleaf/pickfirstleaf_ext_test.go +++ b/balancer/pickfirst/pickfirstleaf/pickfirstleaf_ext_test.go @@ -1504,6 +1504,102 @@ func (s) TestPickFirstLeaf_AddressUpdateWithMetadata(t *testing.T) { } } +// Tests the scenario where a connection is established and then breaks, leading +// to a reconnection attempt. While the reconnection is in progress, a resolver +// update with a new address is received. The test verifies that the balancer +// creates a new SubConn for the new address and that the ClientConn eventually +// becomes READY. +func (s) TestPickFirstLeaf_Reconnection(t *testing.T) { + ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) + defer cancel() + cc := testutils.NewBalancerClientConn(t) + bal := balancer.Get(pickfirstleaf.Name).Build(cc, balancer.BuildOptions{}) + defer bal.Close() + ccState := balancer.ClientConnState{ + ResolverState: resolver.State{ + Endpoints: []resolver.Endpoint{ + {Addresses: []resolver.Address{{Addr: "1.1.1.1:1"}}}, + }, + }, + } + if err := bal.UpdateClientConnState(ccState); err != nil { + t.Fatalf("UpdateClientConnState(%v) returned error: %v", ccState, err) + } + + select { + case state := <-cc.NewStateCh: + if got, want := state, connectivity.Connecting; got != want { + t.Fatalf("Received unexpected ClientConn sate: got %v, want %v", got, want) + } + case <-ctx.Done(): + t.Fatal("Context timed out waiting for ClientConn state update.") + } + + sc1 := <-cc.NewSubConnCh + select { + case <-sc1.ConnectCh: + case <-ctx.Done(): + t.Fatal("Context timed out waiting for Connect() to be called on sc1.") + } + sc1.UpdateState(balancer.SubConnState{ConnectivityState: connectivity.Connecting}) + sc1.UpdateState(balancer.SubConnState{ConnectivityState: connectivity.Ready}) + + if err := cc.WaitForConnectivityState(ctx, connectivity.Ready); err != nil { + t.Fatalf("Context timed out waiting for ClientConn to become READY.") + } + + // Simulate a connection breakage, this should result the channel + // transitioning to IDLE. + sc1.UpdateState(balancer.SubConnState{ConnectivityState: connectivity.Idle}) + if err := cc.WaitForConnectivityState(ctx, connectivity.Idle); err != nil { + t.Fatalf("Context timed out waiting for ClientConn to enter IDLE.") + } + + // Calling the idle picker should result in the SubConn being re-connected. + picker := <-cc.NewPickerCh + if _, err := picker.Pick(balancer.PickInfo{}); err != balancer.ErrNoSubConnAvailable { + t.Fatalf("picker.Pick() returned error: %v, want %v", err, balancer.ErrNoSubConnAvailable) + } + + select { + case <-sc1.ConnectCh: + case <-ctx.Done(): + t.Fatal("Context timed out waiting for Connect() to be called on sc1.") + } + + // Send a resolver update, removing the existing SubConn. Since the balancer + // is connecting, it should create a new SubConn for the new backend + // address. + ccState = balancer.ClientConnState{ + ResolverState: resolver.State{ + Endpoints: []resolver.Endpoint{ + {Addresses: []resolver.Address{{Addr: "2.2.2.2:2"}}}, + }, + }, + } + if err := bal.UpdateClientConnState(ccState); err != nil { + t.Fatalf("UpdateClientConnState(%v) returned error: %v", ccState, err) + } + + var sc2 *testutils.TestSubConn + select { + case sc2 = <-cc.NewSubConnCh: + case <-ctx.Done(): + t.Fatal("Context timed out waiting for new SubConn to be created.") + } + + select { + case <-sc2.ConnectCh: + case <-ctx.Done(): + t.Fatal("Context timed out waiting for Connect() to be called on sc2.") + } + sc2.UpdateState(balancer.SubConnState{ConnectivityState: connectivity.Connecting}) + sc2.UpdateState(balancer.SubConnState{ConnectivityState: connectivity.Ready}) + if err := cc.WaitForConnectivityState(ctx, connectivity.Ready); err != nil { + t.Fatalf("Context timed out waiting for ClientConn to become READY.") + } +} + // healthListenerCapturingCCWrapper is used to capture the health listener so // that health updates can be mocked for testing. type healthListenerCapturingCCWrapper struct { diff --git a/clientconn.go b/clientconn.go index 3f762285db71..a3c315f2d76e 100644 --- a/clientconn.go +++ b/clientconn.go @@ -456,7 +456,7 @@ func (cc *ClientConn) validateTransportCredentials() error { func (cc *ClientConn) channelzRegistration(target string) { parentChannel, _ := cc.dopts.channelzParent.(*channelz.Channel) cc.channelz = channelz.RegisterChannel(parentChannel, target) - cc.addTraceEvent("created") + cc.addTraceEvent(fmt.Sprintf("created for target %q", target)) } // chainUnaryClientInterceptors chains all unary client interceptors into one. diff --git a/cmd/protoc-gen-go-grpc/go.mod b/cmd/protoc-gen-go-grpc/go.mod index 88ce30d67b47..5182dd832504 100644 --- a/cmd/protoc-gen-go-grpc/go.mod +++ b/cmd/protoc-gen-go-grpc/go.mod @@ -1,6 +1,6 @@ module google.golang.org/grpc/cmd/protoc-gen-go-grpc -go 1.23.0 +go 1.24.0 require ( google.golang.org/grpc v1.70.0 diff --git a/credentials/jwt/doc.go b/credentials/jwt/doc.go new file mode 100644 index 000000000000..bba687f2151e --- /dev/null +++ b/credentials/jwt/doc.go @@ -0,0 +1,50 @@ +/* + * + * Copyright 2025 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +// Package jwt implements JWT token file-based call credentials. +// +// This package provides support for A97 JWT Call Credentials, allowing gRPC +// clients to authenticate using JWT tokens read from files. While originally +// designed for xDS environments, these credentials are general-purpose. +// +// The credentials can be used directly in gRPC clients or configured via xDS. +// +// # Token Requirements +// +// JWT tokens must: +// - Be valid, well-formed JWT tokens with header, payload, and signature +// - Include an "exp" (expiration) claim +// - Be readable from the specified file path +// +// # Considerations +// +// - Tokens are cached until expiration to avoid excessive file I/O +// - Transport security is required (RequireTransportSecurity returns true) +// - Errors in reading tokens or parsing JWTs will result in RPC UNAVAILALBE or +// UNAUTHENTICATED errors. The errors are cached and retried with exponential +// backoff. +// +// This implementation is originally intended for use in service mesh +// environments like Istio where JWT tokens are provisioned and rotated by the +// infrastructure. +// +// # Experimental +// +// Notice: All APIs in this package are experimental and may be removed in a +// later release. +package jwt diff --git a/credentials/jwt/file_reader.go b/credentials/jwt/file_reader.go new file mode 100644 index 000000000000..8337608d32de --- /dev/null +++ b/credentials/jwt/file_reader.go @@ -0,0 +1,118 @@ +/* + * + * Copyright 2025 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package jwt + +import ( + "encoding/base64" + "encoding/json" + "errors" + "fmt" + "os" + "strings" + "time" +) + +var ( + errTokenFileAccess = errors.New("token file access error") + errJWTValidation = errors.New("invalid JWT") +) + +// jwtClaims represents the JWT claims structure for extracting expiration time. +type jwtClaims struct { + Exp int64 `json:"exp"` +} + +// jwtFileReader handles reading and parsing JWT tokens from files. +// It is safe to call methods on this type concurrently as no state is stored. +type jwtFileReader struct { + tokenFilePath string +} + +// readToken reads and parses a JWT token from the configured file. +// Returns the token string, expiration time, and any error encountered. +func (r *jwtFileReader) readToken() (string, time.Time, error) { + tokenBytes, err := os.ReadFile(r.tokenFilePath) + if err != nil { + return "", time.Time{}, fmt.Errorf("%v: %w", err, errTokenFileAccess) + } + + token := strings.TrimSpace(string(tokenBytes)) + if token == "" { + return "", time.Time{}, fmt.Errorf("token file %q is empty: %w", r.tokenFilePath, errJWTValidation) + } + + exp, err := r.extractExpiration(token) + if err != nil { + return "", time.Time{}, fmt.Errorf("token file %q: %v: %w", r.tokenFilePath, err, errJWTValidation) + } + + return token, exp, nil +} + +const tokenDelim = "." + +// extractClaimsRaw returns the JWT's claims part as raw string. Even though the +// header and signature are not used, it still expects that the input string to +// be well-formed (ie comprised of exactly three parts, separated by a dot +// character). +func extractClaimsRaw(s string) (string, bool) { + _, s, ok := strings.Cut(s, tokenDelim) + if !ok { // no period found + return "", false + } + claims, s, ok := strings.Cut(s, tokenDelim) + if !ok { // only one period found + return "", false + } + _, _, ok = strings.Cut(s, tokenDelim) + if ok { // three periods found + return "", false + } + return claims, true +} + +// extractExpiration parses the JWT token to extract the expiration time. +func (r *jwtFileReader) extractExpiration(token string) (time.Time, error) { + claimsRaw, ok := extractClaimsRaw(token) + if !ok { + return time.Time{}, fmt.Errorf("expected 3 parts in token") + } + payloadBytes, err := base64.RawURLEncoding.DecodeString(claimsRaw) + if err != nil { + return time.Time{}, fmt.Errorf("decode error: %v", err) + } + + var claims jwtClaims + if err := json.Unmarshal(payloadBytes, &claims); err != nil { + return time.Time{}, fmt.Errorf("unmarshal error: %v", err) + } + + if claims.Exp == 0 { + return time.Time{}, fmt.Errorf("no expiration claims") + } + + expTime := time.Unix(claims.Exp, 0) + + // Check if token is already expired. + if expTime.Before(time.Now()) { + return time.Time{}, fmt.Errorf("expired token") + } + + return expTime, nil +} diff --git a/credentials/jwt/file_reader_test.go b/credentials/jwt/file_reader_test.go new file mode 100644 index 000000000000..481f01f072b9 --- /dev/null +++ b/credentials/jwt/file_reader_test.go @@ -0,0 +1,172 @@ +/* + * + * Copyright 2025 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package jwt + +import ( + "encoding/base64" + "encoding/json" + "errors" + "fmt" + "strings" + "testing" + "time" +) + +func (s) TestJWTFileReader_ReadToken_FileErrors(t *testing.T) { + tests := []struct { + name string + create bool + contents string + wantErr error + }{ + { + name: "nonexistent_file", + create: false, + contents: "", + wantErr: errTokenFileAccess, + }, + { + name: "empty_file", + create: true, + contents: "", + wantErr: errJWTValidation, + }, + { + name: "file_with_whitespace_only", + create: true, + contents: " \n\t ", + wantErr: errJWTValidation, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + var tokenFile string + if !tt.create { + tokenFile = "/does-not-exist" + } else { + tokenFile = writeTempFile(t, "token", tt.contents) + } + + reader := jwtFileReader{tokenFilePath: tokenFile} + if _, _, err := reader.readToken(); err == nil { + t.Fatal("ReadToken() expected error, got nil") + } else if !errors.Is(err, tt.wantErr) { + t.Fatalf("ReadToken() error = %v, want error %v", err, tt.wantErr) + } + }) + } +} + +func (s) TestJWTFileReader_ReadToken_InvalidJWT(t *testing.T) { + now := time.Now().Truncate(time.Second) + tests := []struct { + name string + tokenContent string + wantErr error + }{ + { + name: "valid_token_without_expiration", + tokenContent: createTestJWT(t, time.Time{}), + wantErr: errJWTValidation, + }, + { + name: "expired_token", + tokenContent: createTestJWT(t, now.Add(-time.Hour)), + wantErr: errJWTValidation, + }, + { + name: "malformed_JWT_not_enough_parts", + tokenContent: "invalid.jwt", + wantErr: errJWTValidation, + }, + { + name: "malformed_JWT_invalid_base64", + tokenContent: "header.invalid_base64!@#.signature", + wantErr: errJWTValidation, + }, + { + name: "malformed_JWT_invalid_JSON", + tokenContent: createInvalidJWT(t), + wantErr: errJWTValidation, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + tokenFile := writeTempFile(t, "token", tt.tokenContent) + + reader := jwtFileReader{tokenFilePath: tokenFile} + if _, _, err := reader.readToken(); err == nil { + t.Fatal("ReadToken() expected error, got nil") + } else if !errors.Is(err, tt.wantErr) { + t.Fatalf("ReadToken() error = %v, want error %v", err, tt.wantErr) + } + }) + } +} + +func (s) TestJWTFileReader_ReadToken_ValidToken(t *testing.T) { + now := time.Now().Truncate(time.Second) + tokenExp := now.Add(time.Hour) + token := createTestJWT(t, tokenExp) + tokenFile := writeTempFile(t, "token", token) + + reader := jwtFileReader{tokenFilePath: tokenFile} + readToken, expiry, err := reader.readToken() + if err != nil { + t.Fatalf("ReadToken() unexpected error: %v", err) + } + + if readToken != token { + t.Errorf("ReadToken() token = %q, want %q", readToken, token) + } + + if !expiry.Equal(tokenExp) { + t.Errorf("ReadToken() expiry = %v, want %v", expiry, tokenExp) + } +} + +// createInvalidJWT creates a JWT with invalid JSON in the payload. +func createInvalidJWT(t *testing.T) string { + t.Helper() + + header := map[string]any{ + "typ": "JWT", + "alg": "HS256", + } + + headerBytes, err := json.Marshal(header) + if err != nil { + t.Fatalf("Failed to marshal header: %v", err) + } + + headerB64 := base64.URLEncoding.EncodeToString(headerBytes) + headerB64 = strings.TrimRight(headerB64, "=") + + // Create invalid JSON payload + invalidJSON := "invalid json content" + payloadB64 := base64.URLEncoding.EncodeToString([]byte(invalidJSON)) + payloadB64 = strings.TrimRight(payloadB64, "=") + + signature := base64.URLEncoding.EncodeToString([]byte("fake_signature")) + signature = strings.TrimRight(signature, "=") + + return fmt.Sprintf("%s.%s.%s", headerB64, payloadB64, signature) +} diff --git a/credentials/jwt/token_file_call_creds.go b/credentials/jwt/token_file_call_creds.go new file mode 100644 index 000000000000..2005cf450307 --- /dev/null +++ b/credentials/jwt/token_file_call_creds.go @@ -0,0 +1,180 @@ +/* + * + * Copyright 2025 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package jwt + +import ( + "context" + "errors" + "fmt" + "sync" + "time" + + "google.golang.org/grpc/codes" + "google.golang.org/grpc/credentials" + "google.golang.org/grpc/internal/backoff" + "google.golang.org/grpc/status" +) + +const preemptiveRefreshThreshold = time.Minute + +// jwtTokenFileCallCreds provides JWT token-based PerRPCCredentials that reads +// tokens from a file. +// This implementation follows the A97 JWT Call Credentials specification. +type jwtTokenFileCallCreds struct { + fileReader *jwtFileReader + backoffStrategy backoff.Strategy + + // cached data protected by mu + mu sync.Mutex + cachedAuthHeader string // "Bearer " + token + cachedExpiry time.Time // Slightly less than actual expiration time + cachedError error // Error from last failed attempt + retryAttempt int // Current retry attempt number + nextRetryTime time.Time // When next retry is allowed + pendingRefresh bool // Whether a refresh is currently in progress +} + +// NewTokenFileCallCredentials creates PerRPCCredentials that reads JWT tokens +// from the specified file path. +func NewTokenFileCallCredentials(tokenFilePath string) (credentials.PerRPCCredentials, error) { + if tokenFilePath == "" { + return nil, fmt.Errorf("tokenFilePath cannot be empty") + } + + creds := &jwtTokenFileCallCreds{ + fileReader: &jwtFileReader{tokenFilePath: tokenFilePath}, + backoffStrategy: backoff.DefaultExponential, + } + + return creds, nil +} + +// GetRequestMetadata gets the current request metadata, refreshing tokens if +// required. This implementation follows the PerRPCCredentials interface. The +// tokens will get automatically refreshed if they are about to expire or if +// they haven't been loaded successfully yet. +// If it's not possible to extract a token from the file, UNAVAILABLE is +// returned. +// If the token is extracted but invalid, then UNAUTHENTICATED is returned. +// If errors are encoutered, a backoff is applied before retrying. +func (c *jwtTokenFileCallCreds) GetRequestMetadata(ctx context.Context, _ ...string) (map[string]string, error) { + ri, _ := credentials.RequestInfoFromContext(ctx) + if err := credentials.CheckSecurityLevel(ri.AuthInfo, credentials.PrivacyAndIntegrity); err != nil { + return nil, fmt.Errorf("cannot send secure credentials on an insecure connection: %v", err) + } + + c.mu.Lock() + defer c.mu.Unlock() + + if c.isTokenValidLocked() { + needsPreemptiveRefresh := time.Until(c.cachedExpiry) < preemptiveRefreshThreshold + if needsPreemptiveRefresh && !c.pendingRefresh { + // Start refresh if not pending (handling the prior RPC may have + // just spawned a goroutine). + c.pendingRefresh = true + go c.refreshToken() + } + return map[string]string{ + "authorization": c.cachedAuthHeader, + }, nil + } + + // If in backoff state, just return the cached error. + if c.cachedError != nil && time.Now().Before(c.nextRetryTime) { + return nil, c.cachedError + } + + // At this point, the token is either invalid or expired and we are no + // longer backing off from any encountered errors. So refresh it. + // NB: We are holding the lock while reading the token from file. This will + // cause other RPCs to block until the read completes (sucecssfully or not) + // and the cache is updated. Subsequent RPCs will end up using the cache. + // This is per A97. + token, expiry, err := c.fileReader.readToken() + c.updateCacheLocked(token, expiry, err) + + if c.cachedError != nil { + return nil, c.cachedError + } + return map[string]string{ + "authorization": c.cachedAuthHeader, + }, nil +} + +// RequireTransportSecurity indicates whether the credentials requires +// transport security. +func (c *jwtTokenFileCallCreds) RequireTransportSecurity() bool { + return true +} + +// isTokenValidLocked checks if the cached token is still valid. +// Caller must hold c.mu lock. +func (c *jwtTokenFileCallCreds) isTokenValidLocked() bool { + if c.cachedAuthHeader == "" { + return false + } + return c.cachedExpiry.After(time.Now()) +} + +// refreshToken reads the token from file and updates the cached data. +func (c *jwtTokenFileCallCreds) refreshToken() { + // Deliberately not locking c.mu here. This way other RPCs can proceed + // while we read the token. This is per gRFC A97. + token, expiry, err := c.fileReader.readToken() + + c.mu.Lock() + defer c.mu.Unlock() + c.updateCacheLocked(token, expiry, err) + c.pendingRefresh = false +} + +// updateCacheLocked updates the cached token, expiry, and error state. +// If an error is provided, it determines whether to set it as an UNAVAILABLE +// or UNAUTHENTICATED error based on the error type. +// NOTE: This method (and its callers) do not queue up a token refresh/retry if +// the expiration is soon / an error was encountered. Instead, this is done when +// handling RPCs. This is as per gRFC A97, which states that it is +// undesirable to retry loading the token if the channel is idle. +// Caller must hold c.mu lock. +func (c *jwtTokenFileCallCreds) updateCacheLocked(token string, expiry time.Time, err error) { + if err != nil { + // Convert to gRPC status codes + if errors.Is(err, errTokenFileAccess) { + c.cachedError = status.Error(codes.Unavailable, err.Error()) + } else if errors.Is(err, errJWTValidation) { + c.cachedError = status.Error(codes.Unauthenticated, err.Error()) + } else { + // Should not happen. Treat unknown errors as UNAUTHENTICATED. + c.cachedError = status.Error(codes.Unauthenticated, err.Error()) + } + c.retryAttempt++ + backoffDelay := c.backoffStrategy.Backoff(c.retryAttempt - 1) + c.nextRetryTime = time.Now().Add(backoffDelay) + return + } + // Success - clear any cached error and update token cache + c.cachedError = nil + c.retryAttempt = 0 + c.nextRetryTime = time.Time{} + + c.cachedAuthHeader = "Bearer " + token + // Per gRFC A97: consider token invalid if it expires within the next 30 + // seconds to accommodate for clock skew and server processing time. + c.cachedExpiry = expiry.Add(-30 * time.Second) +} diff --git a/credentials/jwt/token_file_call_creds_test.go b/credentials/jwt/token_file_call_creds_test.go new file mode 100644 index 000000000000..48c1b4f4156e --- /dev/null +++ b/credentials/jwt/token_file_call_creds_test.go @@ -0,0 +1,555 @@ +/* + * + * Copyright 2025 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package jwt + +import ( + "context" + "encoding/base64" + "encoding/json" + "fmt" + "os" + "path/filepath" + "strings" + "testing" + "time" + + "github.com/google/go-cmp/cmp" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/credentials" + "google.golang.org/grpc/internal/grpctest" + "google.golang.org/grpc/status" +) + +const defaultTestTimeout = 5 * time.Second + +type s struct { + grpctest.Tester +} + +func Test(t *testing.T) { + grpctest.RunSubTests(t, s{}) +} + +func (s) TestNewTokenFileCallCredentialsValidFilepath(t *testing.T) { + creds, err := NewTokenFileCallCredentials("/path/to/token") + if err != nil { + t.Fatalf("NewTokenFileCallCredentials() unexpected error: %v", err) + } + if creds == nil { + t.Fatal("NewTokenFileCallCredentials() returned nil credentials") + } +} + +func (s) TestNewTokenFileCallCredentialsMissingFilepath(t *testing.T) { + if _, err := NewTokenFileCallCredentials(""); err == nil { + t.Fatalf("NewTokenFileCallCredentials() expected error, got nil") + } +} + +func (s) TestTokenFileCallCreds_RequireTransportSecurity(t *testing.T) { + creds, err := NewTokenFileCallCredentials("/path/to/token") + if err != nil { + t.Fatalf("NewTokenFileCallCredentials() failed: %v", err) + } + + if !creds.RequireTransportSecurity() { + t.Error("RequireTransportSecurity() = false, want true") + } +} + +func (s) TestTokenFileCallCreds_GetRequestMetadata(t *testing.T) { + now := time.Now().Truncate(time.Second) + tests := []struct { + name string + invalidTokenPath bool + tokenContent string + authInfo credentials.AuthInfo + wantCode codes.Code + wantMetadata map[string]string + }{ + { + name: "valid_token_with_future_expiration", + tokenContent: createTestJWT(t, now.Add(time.Hour)), + authInfo: &testAuthInfo{secLevel: credentials.PrivacyAndIntegrity}, + wantCode: codes.OK, + wantMetadata: map[string]string{"authorization": "Bearer " + createTestJWT(t, now.Add(time.Hour))}, + }, + { + name: "insufficient_security_level", + tokenContent: createTestJWT(t, now.Add(time.Hour)), + authInfo: &testAuthInfo{secLevel: credentials.NoSecurity}, + wantCode: codes.Unknown, // http2Client.getCallAuthData actually transforms such errors into into Unauthenticated + }, + { + name: "unreachable_token_file", + invalidTokenPath: true, + authInfo: &testAuthInfo{secLevel: credentials.PrivacyAndIntegrity}, + wantCode: codes.Unavailable, + }, + { + name: "empty_file", + tokenContent: "", + authInfo: &testAuthInfo{secLevel: credentials.PrivacyAndIntegrity}, + wantCode: codes.Unauthenticated, + }, + { + name: "malformed_JWT_token", + tokenContent: "bad contents", + authInfo: &testAuthInfo{secLevel: credentials.PrivacyAndIntegrity}, + wantCode: codes.Unauthenticated, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + var tokenFile string + if tt.invalidTokenPath { + tokenFile = "/does-not-exist" + } else { + tokenFile = writeTempFile(t, "token", tt.tokenContent) + } + creds, err := NewTokenFileCallCredentials(tokenFile) + if err != nil { + t.Fatalf("NewTokenFileCallCredentials() failed: %v", err) + } + + ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) + defer cancel() + ctx = credentials.NewContextWithRequestInfo(ctx, credentials.RequestInfo{ + AuthInfo: tt.authInfo, + }) + + metadata, err := creds.GetRequestMetadata(ctx) + if gotCode := status.Code(err); gotCode != tt.wantCode { + t.Fatalf("GetRequestMetadata() = %v, want %v", gotCode, tt.wantCode) + } + + if diff := cmp.Diff(tt.wantMetadata, metadata); diff != "" { + t.Errorf("GetRequestMetadata() returned unexpected metadata (-want +got):\n%s", diff) + } + }) + } +} + +func (s) TestTokenFileCallCreds_TokenCaching(t *testing.T) { + token := createTestJWT(t, time.Now().Add(time.Hour)) + tokenFile := writeTempFile(t, "token", token) + + creds, err := NewTokenFileCallCredentials(tokenFile) + if err != nil { + t.Fatalf("NewTokenFileCallCredentials() failed: %v", err) + } + + ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) + defer cancel() + ctx = credentials.NewContextWithRequestInfo(ctx, credentials.RequestInfo{ + AuthInfo: &testAuthInfo{secLevel: credentials.PrivacyAndIntegrity}, + }) + + // First call should read from file. + metadata1, err := creds.GetRequestMetadata(ctx) + if err != nil { + t.Fatalf("First GetRequestMetadata() failed: %v", err) + } + wantMetadata := map[string]string{"authorization": "Bearer " + token} + if diff := cmp.Diff(wantMetadata, metadata1); diff != "" { + t.Errorf("First GetRequestMetadata() returned unexpected metadata (-want +got):\n%s", diff) + } + + // Update the file with a different token. + newToken := createTestJWT(t, time.Now().Add(2*time.Hour)) + if err := os.WriteFile(tokenFile, []byte(newToken), 0600); err != nil { + t.Fatalf("Failed to update token file: %v", err) + } + + // Second call should return cached token (not the updated one). + metadata2, err := creds.GetRequestMetadata(ctx) + if err != nil { + t.Fatalf("Second GetRequestMetadata() failed: %v", err) + } + + if diff := cmp.Diff(metadata1, metadata2); diff != "" { + t.Errorf("Second GetRequestMetadata() returned unexpected metadata (-want +got):\n%s", diff) + } +} + +// testAuthInfo implements credentials.AuthInfo for testing. +type testAuthInfo struct { + secLevel credentials.SecurityLevel +} + +func (t *testAuthInfo) AuthType() string { + return "test" +} + +func (t *testAuthInfo) GetCommonAuthInfo() credentials.CommonAuthInfo { + return credentials.CommonAuthInfo{SecurityLevel: t.secLevel} +} + +// Tests that cached token expiration is set to 30 seconds before actual token +// expiration. +// TODO: Refactor the test to avoid inspecting and mutating internal state. +func (s) TestTokenFileCallCreds_CacheExpirationIsBeforeTokenExpiration(t *testing.T) { + // Create token that expires in 2 hours. + tokenExp := time.Now().Truncate(time.Second).Add(2 * time.Hour) + token := createTestJWT(t, tokenExp) + tokenFile := writeTempFile(t, "token", token) + + creds, err := NewTokenFileCallCredentials(tokenFile) + if err != nil { + t.Fatalf("NewTokenFileCallCredentials() failed: %v", err) + } + + ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) + defer cancel() + ctx = credentials.NewContextWithRequestInfo(ctx, credentials.RequestInfo{ + AuthInfo: &testAuthInfo{secLevel: credentials.PrivacyAndIntegrity}, + }) + + // Get token to trigger caching. + if _, err = creds.GetRequestMetadata(ctx); err != nil { + t.Fatalf("GetRequestMetadata() failed: %v", err) + } + + // Verify cached expiration is 30 seconds before actual token expiration. + impl := creds.(*jwtTokenFileCallCreds) + impl.mu.Lock() + cachedExp := impl.cachedExpiry + impl.mu.Unlock() + + wantExp := tokenExp.Add(-30 * time.Second) + if !cachedExp.Equal(wantExp) { + t.Errorf("Cache expiration = %v, want %v", cachedExp, wantExp) + } +} + +// Tests that pre-emptive refresh is triggered within 1 minute of expiration. +// This is tested as follows: +// * A token which expires "soon" is created. +// * On the first call to GetRequestMetadata, the token will get loaded and returned. +// * Another token is created and overwrites the file. +// * On the second call we will still return the (valid) first token but also +// detect that a refresh needs to happen and trigger it. +// * On the third call we confirm the new token has been loaded and returned. +func (s) TestTokenFileCallCreds_PreemptiveRefreshIsTriggered(t *testing.T) { + // Create token that expires in 80 seconds (=> cache expires in ~50s). + // This ensures pre-emptive refresh triggers since 50s < the 1 minute check. + tokenExp := time.Now().Add(80 * time.Second) + expiringToken := createTestJWT(t, tokenExp) + tokenFile := writeTempFile(t, "token", expiringToken) + + creds, err := NewTokenFileCallCredentials(tokenFile) + if err != nil { + t.Fatalf("NewTokenFileCallCredentials() failed: %v", err) + } + + ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) + defer cancel() + ctx = credentials.NewContextWithRequestInfo(ctx, credentials.RequestInfo{ + AuthInfo: &testAuthInfo{secLevel: credentials.PrivacyAndIntegrity}, + }) + + // First call should read from file synchronously. + metadata1, err := creds.GetRequestMetadata(ctx) + if err != nil { + t.Fatalf("GetRequestMetadata() failed: %v", err) + } + wantAuth1 := "Bearer " + expiringToken + gotAuth1 := metadata1["authorization"] + if gotAuth1 != wantAuth1 { + t.Fatalf("First call should return original token: got %q, want %q", gotAuth1, wantAuth1) + } + + // Verify token was cached and confirm expectation that refresh should be + // triggered. + impl := creds.(*jwtTokenFileCallCreds) + impl.mu.Lock() + cacheExp := impl.cachedExpiry + tokenCached := impl.cachedAuthHeader != "" + shouldTriggerRefresh := time.Until(cacheExp) < preemptiveRefreshThreshold + impl.mu.Unlock() + + if !tokenCached { + t.Fatal("Token should be cached after successful GetRequestMetadata") + } + + if !shouldTriggerRefresh { + timeUntilExp := time.Until(cacheExp) + t.Fatalf("Cache expires in %v; test precondition requires that this triggers preemptive refresh", timeUntilExp) + } + + // Create new token file with different expiration while refresh is + // happening. + newToken := createTestJWT(t, time.Now().Add(2*time.Hour)) + if err := os.WriteFile(tokenFile, []byte(newToken), 0600); err != nil { + t.Fatalf("Failed to write updated token file: %v", err) + } + + // Get token again - this call should trigger a refresh given that the first + // one was cached but expiring soon. + // However, the function should have returned right away with the current + // cached token because it is still valid and the preemptive refresh is + // meant to happen without blocking the RPC. + metadata2, err := creds.GetRequestMetadata(ctx) + if err != nil { + t.Fatalf("Second GetRequestMetadata() failed: %v", err) + } + wantAuth2 := wantAuth1 + gotAuth2 := metadata2["authorization"] + if gotAuth2 != wantAuth2 { + t.Fatalf("Second call should return the original token: got %q, want %q", gotAuth2, wantAuth2) + } + + // Now should get the new token which was refreshed in the background. + wantAuth3 := "Bearer " + newToken + ctx, cancel = context.WithTimeout(context.Background(), defaultTestTimeout) + defer cancel() + ctx = credentials.NewContextWithRequestInfo(ctx, credentials.RequestInfo{ + AuthInfo: &testAuthInfo{secLevel: credentials.PrivacyAndIntegrity}, + }) + for ; ; <-time.After(time.Millisecond) { + if ctx.Err() != nil { + t.Fatal("Context deadline expired before pre-emptive refresh completed") + } + // If the newly returned metadata is different to the old one, verify + // that it matches the token from the updated file. If not, fail the + // test. + metadata3, err := creds.GetRequestMetadata(ctx) + if err != nil { + t.Fatalf("Second GetRequestMetadata() failed: %v", err) + } + // Pre-emptive refresh not completed yet, try again. + gotAuth3 := metadata3["authorization"] + if gotAuth3 == gotAuth2 { + continue + } + if gotAuth3 != wantAuth3 { + t.Fatalf("Third call should return the new token: got %q, want %q", gotAuth3, wantAuth3) + } + break + } +} + +// Tests that backoff behavior handles file read errors correctly. +// It has the following expectations: +// First call to GetRequestMetadata() fails with UNAVAILABLE due to a +// missing file. +// Second call to GetRequestMetadata() fails with UNAVAILABLE due backoff. +// Third call to GetRequestMetadata() fails with UNAVAILABLE due to retry. +// Fourth call to GetRequestMetadata() fails with UNAVAILABLE due to backoff +// even though file exists. +// Fifth call to GetRequestMetadata() succeeds after reading the file and +// backoff has expired. +// TODO: Refactor the test to avoid inspecting and mutating internal state. +func (s) TestTokenFileCallCreds_BackoffBehavior(t *testing.T) { + tempDir := t.TempDir() + nonExistentFile := filepath.Join(tempDir, "nonexistent") + + creds, err := NewTokenFileCallCredentials(nonExistentFile) + if err != nil { + t.Fatalf("NewTokenFileCallCredentials() failed: %v", err) + } + + ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) + defer cancel() + ctx = credentials.NewContextWithRequestInfo(ctx, credentials.RequestInfo{ + AuthInfo: &testAuthInfo{secLevel: credentials.PrivacyAndIntegrity}, + }) + + // First call should fail with UNAVAILABLE. + beforeCallRetryTime := time.Now() + _, err = creds.GetRequestMetadata(ctx) + if err == nil { + t.Fatal("Expected error from nonexistent file") + } + if status.Code(err) != codes.Unavailable { + t.Fatalf("GetRequestMetadata() = %v, want UNAVAILABLE", status.Code(err)) + } + + // Verify error is cached internally. + impl := creds.(*jwtTokenFileCallCreds) + impl.mu.Lock() + retryAttempt := impl.retryAttempt + nextRetryTime := impl.nextRetryTime + impl.mu.Unlock() + + if retryAttempt != 1 { + t.Errorf("Expected retry attempt to be 1, got %d", retryAttempt) + } + if !nextRetryTime.After(beforeCallRetryTime) { + t.Error("Next retry time should be set to a time after the first call") + } + + // Second call should still return cached error and not retry. + // Set nextRetryTime far enough in the future to ensure that's the case. + impl.mu.Lock() + impl.nextRetryTime = time.Now().Add(1 * time.Minute) + wantNextRetryTime := impl.nextRetryTime + impl.mu.Unlock() + _, err = creds.GetRequestMetadata(ctx) + if err == nil { + t.Fatalf("creds.GetRequestMetadata() = %v, want non-nil", err) + } + if status.Code(err) != codes.Unavailable { + t.Fatalf("GetRequestMetadata() = %v, want cached UNAVAILABLE", status.Code(err)) + } + + impl.mu.Lock() + retryAttempt2 := impl.retryAttempt + nextRetryTime2 := impl.nextRetryTime + impl.mu.Unlock() + if !nextRetryTime2.Equal(wantNextRetryTime) { + t.Errorf("nextRetryTime should not change due to backoff. Got: %v, Want: %v", nextRetryTime2, wantNextRetryTime) + } + if retryAttempt2 != 1 { + t.Error("Retry attempt should not change due to backoff") + } + + // Third call should retry but still fail with UNAVAILABLE. + // Set the backoff retry time in the past to allow next retry attempt. + impl.mu.Lock() + impl.nextRetryTime = time.Now().Add(-1 * time.Minute) + beforeCallRetryTime = impl.nextRetryTime + impl.mu.Unlock() + _, err = creds.GetRequestMetadata(ctx) + if err == nil { + t.Fatalf("creds.GetRequestMetadata() = %v, want non-nil", err) + } + if status.Code(err) != codes.Unavailable { + t.Fatalf("GetRequestMetadata() = %v, want cached UNAVAILABLE", status.Code(err)) + } + + impl.mu.Lock() + retryAttempt3 := impl.retryAttempt + nextRetryTime3 := impl.nextRetryTime + impl.mu.Unlock() + + if !nextRetryTime3.After(beforeCallRetryTime) { + t.Error("nextRetryTime3 should have been updated after third call") + } + if retryAttempt3 != 2 { + t.Error("Expected retry attempt to increase after retry") + } + + // Create valid token file. + validToken := createTestJWT(t, time.Now().Add(time.Hour)) + if err := os.WriteFile(nonExistentFile, []byte(validToken), 0600); err != nil { + t.Fatalf("Failed to create valid token file: %v", err) + } + + // Fourth call should still fail even though the file now exists due to backoff. + // Set nextRetryTime far enough in the future to ensure that's the case. + _, err = creds.GetRequestMetadata(ctx) + impl.mu.Lock() + impl.nextRetryTime = time.Now().Add(1 * time.Minute) + wantNextRetryTime = impl.nextRetryTime + impl.mu.Unlock() + if err == nil { + t.Fatalf("creds.GetRequestMetadata() = %v, want non-nil", err) + } + if status.Code(err) != codes.Unavailable { + t.Fatalf("GetRequestMetadata() = %v, want cached UNAVAILABLE", status.Code(err)) + } + + impl.mu.Lock() + retryAttempt4 := impl.retryAttempt + nextRetryTime4 := impl.nextRetryTime + impl.mu.Unlock() + + if !nextRetryTime4.Equal(wantNextRetryTime) { + t.Errorf("nextRetryTime should not change due to backoff. Got: %v, Want: %v", nextRetryTime4, wantNextRetryTime) + } + if retryAttempt4 != retryAttempt3 { + t.Error("Retry attempt should not change due to backoff") + } + + // Fifth call should succeed since the file now exists and the backoff has + // expired. + // Set the backoff retry time in the past to allow next retry attempt. + impl.mu.Lock() + impl.nextRetryTime = time.Now().Add(-1 * time.Minute) + impl.mu.Unlock() + _, err = creds.GetRequestMetadata(ctx) + if err != nil { + t.Fatalf("After creating valid token file, backoff should expire and trigger a token reload on the next RPC. GetRequestMetadata() should eventually succeed, but got: %v", err) + } + // If successful, verify error cache and backoff state were cleared. + impl.mu.Lock() + clearedErr := impl.cachedError + retryAttempt = impl.retryAttempt + nextRetryTime = impl.nextRetryTime + impl.mu.Unlock() + + if clearedErr != nil { + t.Errorf("After successful retry, cached error should be cleared, got: %v", clearedErr) + } + if retryAttempt != 0 { + t.Errorf("After successful retry, retry attempt should be reset, got: %d", retryAttempt) + } + if !nextRetryTime.IsZero() { + t.Error("After successful retry, next retry time should be cleared") + } +} + +// createTestJWT creates a test JWT token with the specified expiration. +func createTestJWT(t *testing.T, expiration time.Time) string { + t.Helper() + + claims := map[string]any{} + if !expiration.IsZero() { + claims["exp"] = expiration.Unix() + } + + header := map[string]any{ + "typ": "JWT", + "alg": "HS256", + } + headerBytes, err := json.Marshal(header) + if err != nil { + t.Fatalf("Failed to marshal header: %v", err) + } + + claimsBytes, err := json.Marshal(claims) + if err != nil { + t.Fatalf("Failed to marshal claims: %v", err) + } + + headerB64 := base64.URLEncoding.EncodeToString(headerBytes) + claimsB64 := base64.URLEncoding.EncodeToString(claimsBytes) + + // Remove padding for URL-safe base64 + headerB64 = strings.TrimRight(headerB64, "=") + claimsB64 = strings.TrimRight(claimsB64, "=") + + // For testing, we'll use a fake signature + signature := base64.URLEncoding.EncodeToString([]byte("fake_signature")) + signature = strings.TrimRight(signature, "=") + + return fmt.Sprintf("%s.%s.%s", headerB64, claimsB64, signature) +} + +func writeTempFile(t *testing.T, name, content string) string { + t.Helper() + tempDir := t.TempDir() + filePath := filepath.Join(tempDir, name) + if err := os.WriteFile(filePath, []byte(content), 0600); err != nil { + t.Fatalf("Failed to write temp file: %v", err) + } + return filePath +} diff --git a/encoding/proto/proto.go b/encoding/proto/proto.go index ceec319dd2fb..1ab874c7ad26 100644 --- a/encoding/proto/proto.go +++ b/encoding/proto/proto.go @@ -46,9 +46,25 @@ func (c *codecV2) Marshal(v any) (data mem.BufferSlice, err error) { return nil, fmt.Errorf("proto: failed to marshal, message is %T, want proto.Message", v) } + // Important: if we remove this Size call then we cannot use + // UseCachedSize in MarshalOptions below. size := proto.Size(vv) + + // MarshalOptions with UseCachedSize allows reusing the result from the + // previous Size call. This is safe here because: + // + // 1. We just computed the size. + // 2. We assume the message is not being mutated concurrently. + // + // Important: If the proto.Size call above is removed, using UseCachedSize + // becomes unsafe and may lead to incorrect marshaling. + // + // For more details, see the doc of UseCachedSize: + // https://pkg.go.dev/google.golang.org/protobuf/proto#MarshalOptions + marshalOptions := proto.MarshalOptions{UseCachedSize: true} + if mem.IsBelowBufferPoolingThreshold(size) { - buf, err := proto.Marshal(vv) + buf, err := marshalOptions.Marshal(vv) if err != nil { return nil, err } @@ -56,7 +72,7 @@ func (c *codecV2) Marshal(v any) (data mem.BufferSlice, err error) { } else { pool := mem.DefaultBufferPool() buf := pool.Get(size) - if _, err := (proto.MarshalOptions{}).MarshalAppend((*buf)[:0], vv); err != nil { + if _, err := marshalOptions.MarshalAppend((*buf)[:0], vv); err != nil { pool.Put(buf) return nil, err } diff --git a/examples/features/csm_observability/client/Dockerfile b/examples/features/csm_observability/client/Dockerfile index 0e974c135372..6d46d079db87 100644 --- a/examples/features/csm_observability/client/Dockerfile +++ b/examples/features/csm_observability/client/Dockerfile @@ -15,7 +15,7 @@ # Dockerfile for building the example client. To build the image, run the # following command from grpc-go directory: # docker build -t -f examples/features/csm_observability/client/Dockerfile . -FROM golang:1.23-alpine as build +FROM golang:1.25-alpine as build RUN apk --no-cache add curl diff --git a/examples/features/csm_observability/server/Dockerfile b/examples/features/csm_observability/server/Dockerfile index 3ba99a7f34a6..7ab8e2e8b98c 100644 --- a/examples/features/csm_observability/server/Dockerfile +++ b/examples/features/csm_observability/server/Dockerfile @@ -16,7 +16,7 @@ # following command from grpc-go directory: # docker build -t -f examples/features/csm_observability/server/Dockerfile . -FROM golang:1.23-alpine as build +FROM golang:1.25-alpine as build RUN apk --no-cache add curl # Make a grpc-go directory and copy the repo into it. WORKDIR /go/src/grpc-go diff --git a/examples/go.mod b/examples/go.mod index 2c07d1c391ec..bacaa2b0d6ad 100644 --- a/examples/go.mod +++ b/examples/go.mod @@ -1,18 +1,18 @@ module google.golang.org/grpc/examples -go 1.23.0 +go 1.24.0 require ( github.com/cncf/xds/go v0.0.0-20250501225837-2ac532fd4443 - github.com/prometheus/client_golang v1.22.0 + github.com/prometheus/client_golang v1.23.0 go.opentelemetry.io/otel v1.37.0 go.opentelemetry.io/otel/exporters/prometheus v0.59.1 go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.37.0 go.opentelemetry.io/otel/sdk v1.37.0 go.opentelemetry.io/otel/sdk/metric v1.37.0 golang.org/x/oauth2 v0.30.0 - google.golang.org/genproto/googleapis/rpc v0.0.0-20250707201910-8d1bb00bc6a7 - google.golang.org/grpc v1.73.0 + google.golang.org/genproto/googleapis/rpc v0.0.0-20250804133106-a7a43d27e69b + google.golang.org/grpc v1.74.2 google.golang.org/grpc/gcp/observability v1.0.1 google.golang.org/grpc/security/advancedtls v1.0.0 google.golang.org/protobuf v1.36.6 @@ -20,8 +20,8 @@ require ( require ( cel.dev/expr v0.24.0 // indirect - cloud.google.com/go v0.121.3 // indirect - cloud.google.com/go/auth v0.16.2 // indirect + cloud.google.com/go v0.121.4 // indirect + cloud.google.com/go/auth v0.16.3 // indirect cloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect cloud.google.com/go/compute/metadata v0.7.0 // indirect cloud.google.com/go/logging v1.13.0 // indirect @@ -30,26 +30,26 @@ require ( cloud.google.com/go/trace v1.11.6 // indirect contrib.go.opencensus.io/exporter/stackdriver v0.13.15-0.20230702191903-2de6d2748484 // indirect github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.29.0 // indirect - github.com/aws/aws-sdk-go-v2 v1.36.5 // indirect - github.com/aws/aws-sdk-go-v2/config v1.29.17 // indirect - github.com/aws/aws-sdk-go-v2/credentials v1.17.70 // indirect - github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.32 // indirect - github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.36 // indirect - github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.36 // indirect + github.com/aws/aws-sdk-go-v2 v1.37.2 // indirect + github.com/aws/aws-sdk-go-v2/config v1.30.3 // indirect + github.com/aws/aws-sdk-go-v2/credentials v1.18.3 // indirect + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.2 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.2 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.2 // indirect github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.4 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.17 // indirect - github.com/aws/aws-sdk-go-v2/service/sso v1.25.5 // indirect - github.com/aws/aws-sdk-go-v2/service/ssooidc v1.30.3 // indirect - github.com/aws/aws-sdk-go-v2/service/sts v1.34.0 // indirect - github.com/aws/smithy-go v1.22.4 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.0 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.2 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.27.0 // indirect + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.32.0 // indirect + github.com/aws/aws-sdk-go-v2/service/sts v1.36.0 // indirect + github.com/aws/smithy-go v1.22.5 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/census-instrumentation/opencensus-proto v0.4.1 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/envoyproxy/go-control-plane/envoy v1.32.4 // indirect github.com/envoyproxy/protoc-gen-validate v1.2.1 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect - github.com/go-jose/go-jose/v4 v4.1.1 // indirect + github.com/go-jose/go-jose/v4 v4.1.2 // indirect github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect @@ -57,13 +57,13 @@ require ( github.com/google/s2a-go v0.1.9 // indirect github.com/google/uuid v1.6.0 // indirect github.com/googleapis/enterprise-certificate-proxy v0.3.6 // indirect - github.com/googleapis/gax-go/v2 v2.14.2 // indirect + github.com/googleapis/gax-go/v2 v2.15.0 // indirect github.com/grafana/regexp v0.0.0-20240518133315-a468a5bfb3bc // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 // indirect github.com/prometheus/client_model v0.6.2 // indirect github.com/prometheus/common v0.65.0 // indirect - github.com/prometheus/otlptranslator v0.0.0-20250717125610-8549f4ab4f8f // indirect + github.com/prometheus/otlptranslator v0.0.0-20250725141939-ab8d56d297e3 // indirect github.com/prometheus/procfs v0.17.0 // indirect github.com/spiffe/go-spiffe/v2 v2.5.0 // indirect github.com/zeebo/errs v1.4.0 // indirect @@ -74,15 +74,15 @@ require ( go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.62.0 // indirect go.opentelemetry.io/otel/metric v1.37.0 // indirect go.opentelemetry.io/otel/trace v1.37.0 // indirect - golang.org/x/crypto v0.39.0 // indirect - golang.org/x/net v0.41.0 // indirect - golang.org/x/sync v0.15.0 // indirect + golang.org/x/crypto v0.40.0 // indirect + golang.org/x/net v0.42.0 // indirect + golang.org/x/sync v0.16.0 // indirect golang.org/x/sys v0.34.0 // indirect - golang.org/x/text v0.26.0 // indirect + golang.org/x/text v0.27.0 // indirect golang.org/x/time v0.12.0 // indirect - google.golang.org/api v0.240.0 // indirect - google.golang.org/genproto v0.0.0-20250707201910-8d1bb00bc6a7 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20250707201910-8d1bb00bc6a7 // indirect + google.golang.org/api v0.245.0 // indirect + google.golang.org/genproto v0.0.0-20250804133106-a7a43d27e69b // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20250804133106-a7a43d27e69b // indirect google.golang.org/grpc/stats/opencensus v1.0.0 // indirect ) diff --git a/examples/go.sum b/examples/go.sum index 9dd74ed3c227..c3951d80c8d5 100644 --- a/examples/go.sum +++ b/examples/go.sum @@ -43,8 +43,8 @@ cloud.google.com/go v0.110.0/go.mod h1:SJnCLqQ0FCFGSZMUNUf84MV3Aia54kn7pi8st7tMz cloud.google.com/go v0.110.2/go.mod h1:k04UEeEtb6ZBRTv3dZz4CeJC3jKGxyhl0sAiVVquxiw= cloud.google.com/go v0.110.4/go.mod h1:+EYjdK8e5RME/VY/qLCAtuyALQ9q67dvuum8i+H5xsI= cloud.google.com/go v0.110.6/go.mod h1:+EYjdK8e5RME/VY/qLCAtuyALQ9q67dvuum8i+H5xsI= -cloud.google.com/go v0.121.3 h1:84RD+hQXNdY5Sw/MWVAx5O9Aui/rd5VQ9HEcdN19afo= -cloud.google.com/go v0.121.3/go.mod h1:6vWF3nJWRrEUv26mMB3FEIU/o1MQNVPG1iHdisa2SJc= +cloud.google.com/go v0.121.4 h1:cVvUiY0sX0xwyxPwdSU2KsF9knOVmtRyAMt8xou0iTs= +cloud.google.com/go v0.121.4/go.mod h1:XEBchUiHFJbz4lKBZwYBDHV/rSyfFktk737TLDU089s= cloud.google.com/go/accessapproval v1.4.0/go.mod h1:zybIuC3KpDOvotz59lFe5qxRZx6C75OtwbisN56xYB4= cloud.google.com/go/accessapproval v1.5.0/go.mod h1:HFy3tuiGvMdcd/u+Cu5b9NkO1pEICJ46IR82PoUdplw= cloud.google.com/go/accessapproval v1.6.0/go.mod h1:R0EiYnwV5fsRFiKZkPHr6mwyk2wxUJ30nL4j2pcFY2E= @@ -121,8 +121,8 @@ cloud.google.com/go/assuredworkloads v1.8.0/go.mod h1:AsX2cqyNCOvEQC8RMPnoc0yEar cloud.google.com/go/assuredworkloads v1.9.0/go.mod h1:kFuI1P78bplYtT77Tb1hi0FMxM0vVpRC7VVoJC3ZoT0= cloud.google.com/go/assuredworkloads v1.10.0/go.mod h1:kwdUQuXcedVdsIaKgKTp9t0UJkE5+PAVNhdQm4ZVq2E= cloud.google.com/go/assuredworkloads v1.11.1/go.mod h1:+F04I52Pgn5nmPG36CWFtxmav6+7Q+c5QyJoL18Lry0= -cloud.google.com/go/auth v0.16.2 h1:QvBAGFPLrDeoiNjyfVunhQ10HKNYuOwZ5noee0M5df4= -cloud.google.com/go/auth v0.16.2/go.mod h1:sRBas2Y1fB1vZTdurouM0AzuYQBMZinrUYL8EufhtEA= +cloud.google.com/go/auth v0.16.3 h1:kabzoQ9/bobUmnseYnBO6qQG7q4a/CffFRlJSxv2wCc= +cloud.google.com/go/auth v0.16.3/go.mod h1:NucRGjaXfzP1ltpcQ7On/VTZ0H4kWB5Jy+Y9Dnm76fA= cloud.google.com/go/auth/oauth2adapt v0.2.8 h1:keo8NaayQZ6wimpNSmW5OPc283g65QNIiLpZnkHRbnc= cloud.google.com/go/auth/oauth2adapt v0.2.8/go.mod h1:XQ9y31RkqZCcwJWNSx2Xvric3RrU88hAYYbjDWYDL+c= cloud.google.com/go/automl v1.5.0/go.mod h1:34EjfoFGMZ5sgJ9EoLsRtdPSNZLcfflJR39VbVNS2M0= @@ -838,32 +838,32 @@ github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6l github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU= github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g= -github.com/aws/aws-sdk-go-v2 v1.36.5 h1:0OF9RiEMEdDdZEMqF9MRjevyxAQcf6gY+E7vwBILFj0= -github.com/aws/aws-sdk-go-v2 v1.36.5/go.mod h1:EYrzvCCN9CMUTa5+6lf6MM4tq3Zjp8UhSGR/cBsjai0= -github.com/aws/aws-sdk-go-v2/config v1.29.17 h1:jSuiQ5jEe4SAMH6lLRMY9OVC+TqJLP5655pBGjmnjr0= -github.com/aws/aws-sdk-go-v2/config v1.29.17/go.mod h1:9P4wwACpbeXs9Pm9w1QTh6BwWwJjwYvJ1iCt5QbCXh8= -github.com/aws/aws-sdk-go-v2/credentials v1.17.70 h1:ONnH5CM16RTXRkS8Z1qg7/s2eDOhHhaXVd72mmyv4/0= -github.com/aws/aws-sdk-go-v2/credentials v1.17.70/go.mod h1:M+lWhhmomVGgtuPOhO85u4pEa3SmssPTdcYpP/5J/xc= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.32 h1:KAXP9JSHO1vKGCr5f4O6WmlVKLFFXgWYAGoJosorxzU= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.32/go.mod h1:h4Sg6FQdexC1yYG9RDnOvLbW1a/P986++/Y/a+GyEM8= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.36 h1:SsytQyTMHMDPspp+spo7XwXTP44aJZZAC7fBV2C5+5s= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.36/go.mod h1:Q1lnJArKRXkenyog6+Y+zr7WDpk4e6XlR6gs20bbeNo= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.36 h1:i2vNHQiXUvKhs3quBR6aqlgJaiaexz/aNvdCktW/kAM= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.36/go.mod h1:UdyGa7Q91id/sdyHPwth+043HhmP6yP9MBHgbZM0xo8= +github.com/aws/aws-sdk-go-v2 v1.37.2 h1:xkW1iMYawzcmYFYEV0UCMxc8gSsjCGEhBXQkdQywVbo= +github.com/aws/aws-sdk-go-v2 v1.37.2/go.mod h1:9Q0OoGQoboYIAJyslFyF1f5K1Ryddop8gqMhWx/n4Wg= +github.com/aws/aws-sdk-go-v2/config v1.30.3 h1:utupeVnE3bmB221W08P0Moz1lDI3OwYa2fBtUhl7TCc= +github.com/aws/aws-sdk-go-v2/config v1.30.3/go.mod h1:NDGwOEBdpyZwLPlQkpKIO7frf18BW8PaCmAM9iUxQmI= +github.com/aws/aws-sdk-go-v2/credentials v1.18.3 h1:ptfyXmv+ooxzFwyuBth0yqABcjVIkjDL0iTYZBSbum8= +github.com/aws/aws-sdk-go-v2/credentials v1.18.3/go.mod h1:Q43Nci++Wohb0qUh4m54sNln0dbxJw8PvQWkrwOkGOI= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.2 h1:nRniHAvjFJGUCl04F3WaAj7qp/rcz5Gi1OVoj5ErBkc= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.2/go.mod h1:eJDFKAMHHUvv4a0Zfa7bQb//wFNUXGrbFpYRCHe2kD0= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.2 h1:sPiRHLVUIIQcoVZTNwqQcdtjkqkPopyYmIX0M5ElRf4= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.2/go.mod h1:ik86P3sgV+Bk7c1tBFCwI3VxMoSEwl4YkRB9xn1s340= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.2 h1:ZdzDAg075H6stMZtbD2o+PyB933M/f20e9WmCBC17wA= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.2/go.mod h1:eE1IIzXG9sdZCB0pNNpMpsYTLl4YdOQD3njiVN1e/E4= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3 h1:bIqFDwgGXXN1Kpp99pDOdKMTTb5d2KyU5X/BZxjOkRo= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3/go.mod h1:H5O/EsxDWyU+LP/V8i5sm8cxoZgc2fdNR9bxlOFrQTo= -github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.4 h1:CXV68E2dNqhuynZJPB80bhPQwAKqBWVer887figW6Jc= -github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.4/go.mod h1:/xFi9KtvBXP97ppCz1TAEvU1Uf66qvid89rbem3wCzQ= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.17 h1:t0E6FzREdtCsiLIoLCWsYliNsRBgyGD/MCK571qk4MI= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.17/go.mod h1:ygpklyoaypuyDvOM5ujWGrYWpAK3h7ugnmKCU/76Ys4= -github.com/aws/aws-sdk-go-v2/service/sso v1.25.5 h1:AIRJ3lfb2w/1/8wOOSqYb9fUKGwQbtysJ2H1MofRUPg= -github.com/aws/aws-sdk-go-v2/service/sso v1.25.5/go.mod h1:b7SiVprpU+iGazDUqvRSLf5XmCdn+JtT1on7uNL6Ipc= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.30.3 h1:BpOxT3yhLwSJ77qIY3DoHAQjZsc4HEGfMCE4NGy3uFg= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.30.3/go.mod h1:vq/GQR1gOFLquZMSrxUK/cpvKCNVYibNyJ1m7JrU88E= -github.com/aws/aws-sdk-go-v2/service/sts v1.34.0 h1:NFOJ/NXEGV4Rq//71Hs1jC/NvPs1ezajK+yQmkwnPV0= -github.com/aws/aws-sdk-go-v2/service/sts v1.34.0/go.mod h1:7ph2tGpfQvwzgistp2+zga9f+bCjlQJPkPUmMgDSD7w= -github.com/aws/smithy-go v1.22.4 h1:uqXzVZNuNexwc/xrh6Tb56u89WDlJY6HS+KC0S4QSjw= -github.com/aws/smithy-go v1.22.4/go.mod h1:t1ufH5HMublsJYulve2RKmHDC15xu1f26kHCp/HgceI= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.0 h1:6+lZi2JeGKtCraAj1rpoZfKqnQ9SptseRZioejfUOLM= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.0/go.mod h1:eb3gfbVIxIoGgJsi9pGne19dhCBpK6opTYpQqAmdy44= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.2 h1:oxmDEO14NBZJbK/M8y3brhMFEIGN4j8a6Aq8eY0sqlo= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.2/go.mod h1:4hH+8QCrk1uRWDPsVfsNDUup3taAjO8Dnx63au7smAU= +github.com/aws/aws-sdk-go-v2/service/sso v1.27.0 h1:j7/jTOjWeJDolPwZ/J4yZ7dUsxsWZEsxNwH5O7F8eEA= +github.com/aws/aws-sdk-go-v2/service/sso v1.27.0/go.mod h1:M0xdEPQtgpNT7kdAX4/vOAPkFj60hSQRb7TvW9B0iug= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.32.0 h1:ywQF2N4VjqX+Psw+jLjMmUL2g1RDHlvri3NxHA08MGI= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.32.0/go.mod h1:Z+qv5Q6b7sWiclvbJyPSOT1BRVU9wfSUPaqQzZ1Xg3E= +github.com/aws/aws-sdk-go-v2/service/sts v1.36.0 h1:bRP/a9llXSSgDPk7Rqn5GD/DQCGo6uk95plBFKoXt2M= +github.com/aws/aws-sdk-go-v2/service/sts v1.36.0/go.mod h1:tgBsFzxwl65BWkuJ/x2EUs59bD4SfYKgikvFDJi1S58= +github.com/aws/smithy-go v1.22.5 h1:P9ATCXPMb2mPjYBgueqJNCA5S9UfktsW0tTxi+a7eqw= +github.com/aws/smithy-go v1.22.5/go.mod h1:t1ufH5HMublsJYulve2RKmHDC15xu1f26kHCp/HgceI= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= @@ -967,8 +967,8 @@ github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2 github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20231223183121-56fa3ac82ce7/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-jose/go-jose/v4 v4.0.4/go.mod h1:NKb5HO1EZccyMpiZNbdUw/14tiXNyUJh188dfnMCAfc= -github.com/go-jose/go-jose/v4 v4.1.1 h1:JYhSgy4mXXzAdF3nUx3ygx347LRXJRrpgyU3adRmkAI= -github.com/go-jose/go-jose/v4 v4.1.1/go.mod h1:BdsZGqgdO3b6tTc6LSE56wcDbMMLuPsw5d4ZD5f94kA= +github.com/go-jose/go-jose/v4 v4.1.2 h1:TK/7NqRQZfgAh+Td8AlsrvtPoUyiHh0LqVvokh+1vHI= +github.com/go-jose/go-jose/v4 v4.1.2/go.mod h1:22cg9HWM1pOlnRiY+9cQYJ9XHmya1bYW8OeDM6Ku6Oo= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o= @@ -1119,8 +1119,8 @@ github.com/googleapis/gax-go/v2 v2.7.1/go.mod h1:4orTrqY6hXxxaUL4LHIPl6lGo8vAE38 github.com/googleapis/gax-go/v2 v2.8.0/go.mod h1:4orTrqY6hXxxaUL4LHIPl6lGo8vAE38/qKbhSAKP6QI= github.com/googleapis/gax-go/v2 v2.10.0/go.mod h1:4UOEnMCrxsSqQ940WnTiD6qJ63le2ev3xfyagutxiPw= github.com/googleapis/gax-go/v2 v2.11.0/go.mod h1:DxmR61SGKkGLa2xigwuZIQpkCI2S5iydzRfb3peWZJI= -github.com/googleapis/gax-go/v2 v2.14.2 h1:eBLnkZ9635krYIPD+ag1USrOAI0Nr0QYF3+/3GqO0k0= -github.com/googleapis/gax-go/v2 v2.14.2/go.mod h1:ON64QhlJkhVtSqp4v1uaK92VyZ2gmvDQsweuyLV+8+w= +github.com/googleapis/gax-go/v2 v2.15.0 h1:SyjDc1mGgZU5LncH8gimWo9lW1DtIfPibOG81vgd/bo= +github.com/googleapis/gax-go/v2 v2.15.0/go.mod h1:zVVkkxAQHa1RQpg9z2AUCMnKhi0Qld9rcmyfL1OZhoc= github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4= github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= @@ -1281,8 +1281,8 @@ github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXP github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og= -github.com/prometheus/client_golang v1.22.0 h1:rb93p9lokFEsctTys46VnV1kLCDpVZ0a/Y92Vm0Zc6Q= -github.com/prometheus/client_golang v1.22.0/go.mod h1:R7ljNsLXhuQXYZYtw6GAE9AZg8Y7vEW5scdCXrWRXC0= +github.com/prometheus/client_golang v1.23.0 h1:ust4zpdl9r4trLY/gSjlm07PuiBq2ynaXXlptpfy8Uc= +github.com/prometheus/client_golang v1.23.0/go.mod h1:i/o0R9ByOnHX0McrTMTyhYvKE4haaf2mW08I+jGAjEE= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= @@ -1299,8 +1299,8 @@ github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y8 github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA= github.com/prometheus/common v0.65.0 h1:QDwzd+G1twt//Kwj/Ww6E9FQq1iVMmODnILtW1t2VzE= github.com/prometheus/common v0.65.0/go.mod h1:0gZns+BLRQ3V6NdaerOhMbwwRbNh9hkGINtQAsP5GS8= -github.com/prometheus/otlptranslator v0.0.0-20250717125610-8549f4ab4f8f h1:QQB6SuvGZjK8kdc2YaLJpYhV8fxauOsjE6jgcL6YJ8Q= -github.com/prometheus/otlptranslator v0.0.0-20250717125610-8549f4ab4f8f/go.mod h1:P8AwMgdD7XEr6QRUJ2QWLpiAZTgTE2UYgjlu3svompI= +github.com/prometheus/otlptranslator v0.0.0-20250725141939-ab8d56d297e3 h1:b/yrfZp3Ee3SrHXqbRT2L2zLODkY27IjZVvtEcEPES0= +github.com/prometheus/otlptranslator v0.0.0-20250725141939-ab8d56d297e3/go.mod h1:P8AwMgdD7XEr6QRUJ2QWLpiAZTgTE2UYgjlu3svompI= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= @@ -1476,8 +1476,9 @@ golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ss golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc= golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc= golang.org/x/crypto v0.38.0/go.mod h1:MvrbAqul58NNYPKnOra203SB9vpuZW0e+RRZV+Ggqjw= -golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM= golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U= +golang.org/x/crypto v0.40.0 h1:r4x+VvoG5Fm+eJcxMaY8CQM7Lb0l1lsmjGBQ6s8BfKM= +golang.org/x/crypto v0.40.0/go.mod h1:Qr1vMER5WyS2dfPHAlsOj01wgLbsyWtFn/aY+5+ZdxY= golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -1654,8 +1655,9 @@ golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k= golang.org/x/net v0.37.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8= golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds= -golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw= golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA= +golang.org/x/net v0.42.0 h1:jzkYrhi3YQWD6MLBJcsklgQsoAcw89EcZbJw8Z614hs= +golang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -1713,8 +1715,9 @@ golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sync v0.14.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= -golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8= golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw= +golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -1855,6 +1858,7 @@ golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM= golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek= golang.org/x/term v0.30.0/go.mod h1:NYYFdzHoI5wRh/h5tDMdMqCqPJZEuNqVR5xJLd/n67g= golang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ= +golang.org/x/term v0.33.0/go.mod h1:s18+ql9tYWp1IfpV9DmCtQDDSRBUjKaw9M1eAv5UeF0= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1883,8 +1887,9 @@ golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY= golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4= golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA= -golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M= golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA= +golang.org/x/text v0.27.0 h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4= +golang.org/x/text v0.27.0/go.mod h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -1970,6 +1975,7 @@ golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxb golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c= golang.org/x/tools v0.26.0/go.mod h1:TPVVj70c7JJ3WCazhD8OdXcZg/og+b9+tH/KxylGwH0= golang.org/x/tools v0.33.0/go.mod h1:CIJMaWEY88juyUfo7UbgPqbC8rU2OqfAV1h2Qp0oMYI= +golang.org/x/tools v0.34.0/go.mod h1:pAP9OwEaY1CAW3HOmg3hLZC5Z0CCmzjAF2UQMSqNARg= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -2055,8 +2061,8 @@ google.golang.org/api v0.122.0/go.mod h1:gcitW0lvnyWjSp9nKxAbdHKIZ6vF4aajGueeslZ google.golang.org/api v0.124.0/go.mod h1:xu2HQurE5gi/3t1aFCvhPD781p0a3p11sdunTJ2BlP4= google.golang.org/api v0.125.0/go.mod h1:mBwVAtz+87bEN6CbA1GtZPDOqY2R5ONPqJeIlvyo4Aw= google.golang.org/api v0.126.0/go.mod h1:mBwVAtz+87bEN6CbA1GtZPDOqY2R5ONPqJeIlvyo4Aw= -google.golang.org/api v0.240.0 h1:PxG3AA2UIqT1ofIzWV2COM3j3JagKTKSwy7L6RHNXNU= -google.golang.org/api v0.240.0/go.mod h1:cOVEm2TpdAGHL2z+UwyS+kmlGr3bVWQQ6sYEqkKje50= +google.golang.org/api v0.245.0 h1:YliGvz1rjXB+sTLNIST6Ffeji9WlRdLQ+LPl9ruSa5Y= +google.golang.org/api v0.245.0/go.mod h1:dMVhVcylamkirHdzEBAIQWUCgqY885ivNeZYd7VAVr8= google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -2205,8 +2211,8 @@ google.golang.org/genproto v0.0.0-20230629202037-9506855d4529/go.mod h1:xZnkP7mR google.golang.org/genproto v0.0.0-20230706204954-ccb25ca9f130/go.mod h1:O9kGHb51iE/nOGvQaDUuadVYqovW56s5emA88lQnj6Y= google.golang.org/genproto v0.0.0-20230726155614-23370e0ffb3e/go.mod h1:0ggbjUrZYpy1q+ANUS30SEoGZ53cdfwtbuG7Ptgy108= google.golang.org/genproto v0.0.0-20230803162519-f966b187b2e5/go.mod h1:oH/ZOT02u4kWEp7oYBGYFFkCdKS/uYR9Z7+0/xuuFp8= -google.golang.org/genproto v0.0.0-20250707201910-8d1bb00bc6a7 h1:FGOcxvKlJgRBVbXeugjljCfCgfKWhC42FBoYmTCWVBs= -google.golang.org/genproto v0.0.0-20250707201910-8d1bb00bc6a7/go.mod h1:249YoW4b1INqFTEop2T4aJgiO7UBYJrpejsaLvjWfI8= +google.golang.org/genproto v0.0.0-20250804133106-a7a43d27e69b h1:eZTgydvqZO44zyTZAvMaSyAxccZZdraiSAGvqOczVvk= +google.golang.org/genproto v0.0.0-20250804133106-a7a43d27e69b/go.mod h1:suyz2QBHQKlGIF92HEEsCfO1SwxXdk7PFLz+Zd9Uah4= google.golang.org/genproto/googleapis/api v0.0.0-20230525234020-1aefcd67740a/go.mod h1:ts19tUU+Z0ZShN1y3aPyq2+O3d5FUNNgT6FtOzmrNn8= google.golang.org/genproto/googleapis/api v0.0.0-20230525234035-dd9d682886f9/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig= google.golang.org/genproto/googleapis/api v0.0.0-20230526203410-71b5a4ffd15e/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig= @@ -2217,8 +2223,8 @@ google.golang.org/genproto/googleapis/api v0.0.0-20230726155614-23370e0ffb3e/go. google.golang.org/genproto/googleapis/api v0.0.0-20230822172742-b8732ec3820d/go.mod h1:KjSP20unUpOx5kyQUFa7k4OJg0qeJ7DEZflGDu2p6Bk= google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142/go.mod h1:d6be+8HhtEtucleCbxpPW9PA9XwISACu8nvpPqF0BVo= google.golang.org/genproto/googleapis/api v0.0.0-20241202173237-19429a94021a/go.mod h1:jehYqy3+AhJU9ve55aNOaSml7wUXjF9x6z2LcCfpAhY= -google.golang.org/genproto/googleapis/api v0.0.0-20250707201910-8d1bb00bc6a7 h1:FiusG7LWj+4byqhbvmB+Q93B/mOxJLN2DTozDuZm4EU= -google.golang.org/genproto/googleapis/api v0.0.0-20250707201910-8d1bb00bc6a7/go.mod h1:kXqgZtrWaf6qS3jZOCnCH7WYfrvFjkC51bM8fz3RsCA= +google.golang.org/genproto/googleapis/api v0.0.0-20250804133106-a7a43d27e69b h1:ULiyYQ0FdsJhwwZUwbaXpZF5yUE3h+RA+gxvBu37ucc= +google.golang.org/genproto/googleapis/api v0.0.0-20250804133106-a7a43d27e69b/go.mod h1:oDOGiMSXHL4sDTJvFvIB9nRQCGdLP1o/iVaqQK8zB+M= google.golang.org/genproto/googleapis/bytestream v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:ylj+BE99M198VPbBh6A8d9n3w8fChvyLK3wwBOjXBFA= google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234015-3fc162c6f38a/go.mod h1:xURIpW9ES5+/GZhnV6beoEtxQrnkRGIfP5VQG2tCBLc= google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA= @@ -2235,9 +2241,9 @@ google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142/go. google.golang.org/genproto/googleapis/rpc v0.0.0-20240826202546-f6391c0de4c7/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= google.golang.org/genproto/googleapis/rpc v0.0.0-20241118233622-e639e219e697/go.mod h1:5uTbfoYQed2U9p3KIj2/Zzm02PYhndfdmML0qC3q3FU= google.golang.org/genproto/googleapis/rpc v0.0.0-20241202173237-19429a94021a/go.mod h1:5uTbfoYQed2U9p3KIj2/Zzm02PYhndfdmML0qC3q3FU= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250707201910-8d1bb00bc6a7 h1:pFyd6EwwL2TqFf8emdthzeX+gZE1ElRq3iM8pui4KBY= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250707201910-8d1bb00bc6a7/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250728155136-f173205681a0/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250804133106-a7a43d27e69b h1:zPKJod4w6F1+nRGDI9ubnXYhU9NSWoFAijkHkUXeTK8= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250804133106-a7a43d27e69b/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/grpc/examples v0.0.0-20230224211313-3775f633ce20/go.mod h1:Nr5H8+MlGWr5+xX/STzdoEqJrO+YteqFbMyCsrb6mH0= google.golang.org/grpc/security/advancedtls v1.0.0 h1:/KQ7VP/1bs53/aopk9QhuPyFAp9Dm9Ejix3lzYkCrDA= diff --git a/gcp/observability/go.mod b/gcp/observability/go.mod index d766a4ecd93f..a4404558d5da 100644 --- a/gcp/observability/go.mod +++ b/gcp/observability/go.mod @@ -1,6 +1,6 @@ module google.golang.org/grpc/gcp/observability -go 1.23.0 +go 1.24.0 require ( cloud.google.com/go/logging v1.13.0 @@ -9,32 +9,32 @@ require ( github.com/google/uuid v1.6.0 go.opencensus.io v0.24.0 golang.org/x/oauth2 v0.30.0 - google.golang.org/api v0.240.0 - google.golang.org/grpc v1.73.0 + google.golang.org/api v0.245.0 + google.golang.org/grpc v1.74.2 google.golang.org/grpc/stats/opencensus v1.0.0 ) require ( - cloud.google.com/go v0.121.3 // indirect - cloud.google.com/go/auth v0.16.2 // indirect + cloud.google.com/go v0.121.4 // indirect + cloud.google.com/go/auth v0.16.3 // indirect cloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect cloud.google.com/go/compute/metadata v0.7.0 // indirect cloud.google.com/go/longrunning v0.6.7 // indirect cloud.google.com/go/monitoring v1.24.2 // indirect cloud.google.com/go/trace v1.11.6 // indirect - github.com/aws/aws-sdk-go-v2 v1.36.5 // indirect - github.com/aws/aws-sdk-go-v2/config v1.29.17 // indirect - github.com/aws/aws-sdk-go-v2/credentials v1.17.70 // indirect - github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.32 // indirect - github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.36 // indirect - github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.36 // indirect + github.com/aws/aws-sdk-go-v2 v1.37.2 // indirect + github.com/aws/aws-sdk-go-v2/config v1.30.3 // indirect + github.com/aws/aws-sdk-go-v2/credentials v1.18.3 // indirect + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.2 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.2 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.2 // indirect github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.4 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.17 // indirect - github.com/aws/aws-sdk-go-v2/service/sso v1.25.5 // indirect - github.com/aws/aws-sdk-go-v2/service/ssooidc v1.30.3 // indirect - github.com/aws/aws-sdk-go-v2/service/sts v1.34.0 // indirect - github.com/aws/smithy-go v1.22.4 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.0 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.2 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.27.0 // indirect + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.32.0 // indirect + github.com/aws/aws-sdk-go-v2/service/sts v1.36.0 // indirect + github.com/aws/smithy-go v1.22.5 // indirect github.com/census-instrumentation/opencensus-proto v0.4.1 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect github.com/go-logr/logr v1.4.3 // indirect @@ -43,22 +43,22 @@ require ( github.com/golang/protobuf v1.5.4 // indirect github.com/google/s2a-go v0.1.9 // indirect github.com/googleapis/enterprise-certificate-proxy v0.3.6 // indirect - github.com/googleapis/gax-go/v2 v2.14.2 // indirect + github.com/googleapis/gax-go/v2 v2.15.0 // indirect go.opentelemetry.io/auto/sdk v1.1.0 // indirect go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.62.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.62.0 // indirect go.opentelemetry.io/otel v1.37.0 // indirect go.opentelemetry.io/otel/metric v1.37.0 // indirect go.opentelemetry.io/otel/trace v1.37.0 // indirect - golang.org/x/crypto v0.39.0 // indirect - golang.org/x/net v0.41.0 // indirect - golang.org/x/sync v0.15.0 // indirect - golang.org/x/sys v0.33.0 // indirect - golang.org/x/text v0.26.0 // indirect + golang.org/x/crypto v0.40.0 // indirect + golang.org/x/net v0.42.0 // indirect + golang.org/x/sync v0.16.0 // indirect + golang.org/x/sys v0.34.0 // indirect + golang.org/x/text v0.27.0 // indirect golang.org/x/time v0.12.0 // indirect - google.golang.org/genproto v0.0.0-20250707201910-8d1bb00bc6a7 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20250707201910-8d1bb00bc6a7 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20250707201910-8d1bb00bc6a7 // indirect + google.golang.org/genproto v0.0.0-20250804133106-a7a43d27e69b // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20250804133106-a7a43d27e69b // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20250804133106-a7a43d27e69b // indirect google.golang.org/protobuf v1.36.6 // indirect ) diff --git a/gcp/observability/go.sum b/gcp/observability/go.sum index cd51f9d812af..6615a0b8de60 100644 --- a/gcp/observability/go.sum +++ b/gcp/observability/go.sum @@ -42,8 +42,8 @@ cloud.google.com/go v0.110.0/go.mod h1:SJnCLqQ0FCFGSZMUNUf84MV3Aia54kn7pi8st7tMz cloud.google.com/go v0.110.2/go.mod h1:k04UEeEtb6ZBRTv3dZz4CeJC3jKGxyhl0sAiVVquxiw= cloud.google.com/go v0.110.4/go.mod h1:+EYjdK8e5RME/VY/qLCAtuyALQ9q67dvuum8i+H5xsI= cloud.google.com/go v0.110.6/go.mod h1:+EYjdK8e5RME/VY/qLCAtuyALQ9q67dvuum8i+H5xsI= -cloud.google.com/go v0.121.3 h1:84RD+hQXNdY5Sw/MWVAx5O9Aui/rd5VQ9HEcdN19afo= -cloud.google.com/go v0.121.3/go.mod h1:6vWF3nJWRrEUv26mMB3FEIU/o1MQNVPG1iHdisa2SJc= +cloud.google.com/go v0.121.4 h1:cVvUiY0sX0xwyxPwdSU2KsF9knOVmtRyAMt8xou0iTs= +cloud.google.com/go v0.121.4/go.mod h1:XEBchUiHFJbz4lKBZwYBDHV/rSyfFktk737TLDU089s= cloud.google.com/go/accessapproval v1.4.0/go.mod h1:zybIuC3KpDOvotz59lFe5qxRZx6C75OtwbisN56xYB4= cloud.google.com/go/accessapproval v1.5.0/go.mod h1:HFy3tuiGvMdcd/u+Cu5b9NkO1pEICJ46IR82PoUdplw= cloud.google.com/go/accessapproval v1.6.0/go.mod h1:R0EiYnwV5fsRFiKZkPHr6mwyk2wxUJ30nL4j2pcFY2E= @@ -120,8 +120,8 @@ cloud.google.com/go/assuredworkloads v1.8.0/go.mod h1:AsX2cqyNCOvEQC8RMPnoc0yEar cloud.google.com/go/assuredworkloads v1.9.0/go.mod h1:kFuI1P78bplYtT77Tb1hi0FMxM0vVpRC7VVoJC3ZoT0= cloud.google.com/go/assuredworkloads v1.10.0/go.mod h1:kwdUQuXcedVdsIaKgKTp9t0UJkE5+PAVNhdQm4ZVq2E= cloud.google.com/go/assuredworkloads v1.11.1/go.mod h1:+F04I52Pgn5nmPG36CWFtxmav6+7Q+c5QyJoL18Lry0= -cloud.google.com/go/auth v0.16.2 h1:QvBAGFPLrDeoiNjyfVunhQ10HKNYuOwZ5noee0M5df4= -cloud.google.com/go/auth v0.16.2/go.mod h1:sRBas2Y1fB1vZTdurouM0AzuYQBMZinrUYL8EufhtEA= +cloud.google.com/go/auth v0.16.3 h1:kabzoQ9/bobUmnseYnBO6qQG7q4a/CffFRlJSxv2wCc= +cloud.google.com/go/auth v0.16.3/go.mod h1:NucRGjaXfzP1ltpcQ7On/VTZ0H4kWB5Jy+Y9Dnm76fA= cloud.google.com/go/auth/oauth2adapt v0.2.8 h1:keo8NaayQZ6wimpNSmW5OPc283g65QNIiLpZnkHRbnc= cloud.google.com/go/auth/oauth2adapt v0.2.8/go.mod h1:XQ9y31RkqZCcwJWNSx2Xvric3RrU88hAYYbjDWYDL+c= cloud.google.com/go/automl v1.5.0/go.mod h1:34EjfoFGMZ5sgJ9EoLsRtdPSNZLcfflJR39VbVNS2M0= @@ -836,32 +836,32 @@ github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6l github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU= github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g= -github.com/aws/aws-sdk-go-v2 v1.36.5 h1:0OF9RiEMEdDdZEMqF9MRjevyxAQcf6gY+E7vwBILFj0= -github.com/aws/aws-sdk-go-v2 v1.36.5/go.mod h1:EYrzvCCN9CMUTa5+6lf6MM4tq3Zjp8UhSGR/cBsjai0= -github.com/aws/aws-sdk-go-v2/config v1.29.17 h1:jSuiQ5jEe4SAMH6lLRMY9OVC+TqJLP5655pBGjmnjr0= -github.com/aws/aws-sdk-go-v2/config v1.29.17/go.mod h1:9P4wwACpbeXs9Pm9w1QTh6BwWwJjwYvJ1iCt5QbCXh8= -github.com/aws/aws-sdk-go-v2/credentials v1.17.70 h1:ONnH5CM16RTXRkS8Z1qg7/s2eDOhHhaXVd72mmyv4/0= -github.com/aws/aws-sdk-go-v2/credentials v1.17.70/go.mod h1:M+lWhhmomVGgtuPOhO85u4pEa3SmssPTdcYpP/5J/xc= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.32 h1:KAXP9JSHO1vKGCr5f4O6WmlVKLFFXgWYAGoJosorxzU= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.32/go.mod h1:h4Sg6FQdexC1yYG9RDnOvLbW1a/P986++/Y/a+GyEM8= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.36 h1:SsytQyTMHMDPspp+spo7XwXTP44aJZZAC7fBV2C5+5s= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.36/go.mod h1:Q1lnJArKRXkenyog6+Y+zr7WDpk4e6XlR6gs20bbeNo= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.36 h1:i2vNHQiXUvKhs3quBR6aqlgJaiaexz/aNvdCktW/kAM= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.36/go.mod h1:UdyGa7Q91id/sdyHPwth+043HhmP6yP9MBHgbZM0xo8= +github.com/aws/aws-sdk-go-v2 v1.37.2 h1:xkW1iMYawzcmYFYEV0UCMxc8gSsjCGEhBXQkdQywVbo= +github.com/aws/aws-sdk-go-v2 v1.37.2/go.mod h1:9Q0OoGQoboYIAJyslFyF1f5K1Ryddop8gqMhWx/n4Wg= +github.com/aws/aws-sdk-go-v2/config v1.30.3 h1:utupeVnE3bmB221W08P0Moz1lDI3OwYa2fBtUhl7TCc= +github.com/aws/aws-sdk-go-v2/config v1.30.3/go.mod h1:NDGwOEBdpyZwLPlQkpKIO7frf18BW8PaCmAM9iUxQmI= +github.com/aws/aws-sdk-go-v2/credentials v1.18.3 h1:ptfyXmv+ooxzFwyuBth0yqABcjVIkjDL0iTYZBSbum8= +github.com/aws/aws-sdk-go-v2/credentials v1.18.3/go.mod h1:Q43Nci++Wohb0qUh4m54sNln0dbxJw8PvQWkrwOkGOI= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.2 h1:nRniHAvjFJGUCl04F3WaAj7qp/rcz5Gi1OVoj5ErBkc= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.2/go.mod h1:eJDFKAMHHUvv4a0Zfa7bQb//wFNUXGrbFpYRCHe2kD0= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.2 h1:sPiRHLVUIIQcoVZTNwqQcdtjkqkPopyYmIX0M5ElRf4= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.2/go.mod h1:ik86P3sgV+Bk7c1tBFCwI3VxMoSEwl4YkRB9xn1s340= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.2 h1:ZdzDAg075H6stMZtbD2o+PyB933M/f20e9WmCBC17wA= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.2/go.mod h1:eE1IIzXG9sdZCB0pNNpMpsYTLl4YdOQD3njiVN1e/E4= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3 h1:bIqFDwgGXXN1Kpp99pDOdKMTTb5d2KyU5X/BZxjOkRo= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3/go.mod h1:H5O/EsxDWyU+LP/V8i5sm8cxoZgc2fdNR9bxlOFrQTo= -github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.4 h1:CXV68E2dNqhuynZJPB80bhPQwAKqBWVer887figW6Jc= -github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.4/go.mod h1:/xFi9KtvBXP97ppCz1TAEvU1Uf66qvid89rbem3wCzQ= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.17 h1:t0E6FzREdtCsiLIoLCWsYliNsRBgyGD/MCK571qk4MI= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.17/go.mod h1:ygpklyoaypuyDvOM5ujWGrYWpAK3h7ugnmKCU/76Ys4= -github.com/aws/aws-sdk-go-v2/service/sso v1.25.5 h1:AIRJ3lfb2w/1/8wOOSqYb9fUKGwQbtysJ2H1MofRUPg= -github.com/aws/aws-sdk-go-v2/service/sso v1.25.5/go.mod h1:b7SiVprpU+iGazDUqvRSLf5XmCdn+JtT1on7uNL6Ipc= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.30.3 h1:BpOxT3yhLwSJ77qIY3DoHAQjZsc4HEGfMCE4NGy3uFg= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.30.3/go.mod h1:vq/GQR1gOFLquZMSrxUK/cpvKCNVYibNyJ1m7JrU88E= -github.com/aws/aws-sdk-go-v2/service/sts v1.34.0 h1:NFOJ/NXEGV4Rq//71Hs1jC/NvPs1ezajK+yQmkwnPV0= -github.com/aws/aws-sdk-go-v2/service/sts v1.34.0/go.mod h1:7ph2tGpfQvwzgistp2+zga9f+bCjlQJPkPUmMgDSD7w= -github.com/aws/smithy-go v1.22.4 h1:uqXzVZNuNexwc/xrh6Tb56u89WDlJY6HS+KC0S4QSjw= -github.com/aws/smithy-go v1.22.4/go.mod h1:t1ufH5HMublsJYulve2RKmHDC15xu1f26kHCp/HgceI= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.0 h1:6+lZi2JeGKtCraAj1rpoZfKqnQ9SptseRZioejfUOLM= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.0/go.mod h1:eb3gfbVIxIoGgJsi9pGne19dhCBpK6opTYpQqAmdy44= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.2 h1:oxmDEO14NBZJbK/M8y3brhMFEIGN4j8a6Aq8eY0sqlo= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.2/go.mod h1:4hH+8QCrk1uRWDPsVfsNDUup3taAjO8Dnx63au7smAU= +github.com/aws/aws-sdk-go-v2/service/sso v1.27.0 h1:j7/jTOjWeJDolPwZ/J4yZ7dUsxsWZEsxNwH5O7F8eEA= +github.com/aws/aws-sdk-go-v2/service/sso v1.27.0/go.mod h1:M0xdEPQtgpNT7kdAX4/vOAPkFj60hSQRb7TvW9B0iug= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.32.0 h1:ywQF2N4VjqX+Psw+jLjMmUL2g1RDHlvri3NxHA08MGI= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.32.0/go.mod h1:Z+qv5Q6b7sWiclvbJyPSOT1BRVU9wfSUPaqQzZ1Xg3E= +github.com/aws/aws-sdk-go-v2/service/sts v1.36.0 h1:bRP/a9llXSSgDPk7Rqn5GD/DQCGo6uk95plBFKoXt2M= +github.com/aws/aws-sdk-go-v2/service/sts v1.36.0/go.mod h1:tgBsFzxwl65BWkuJ/x2EUs59bD4SfYKgikvFDJi1S58= +github.com/aws/smithy-go v1.22.5 h1:P9ATCXPMb2mPjYBgueqJNCA5S9UfktsW0tTxi+a7eqw= +github.com/aws/smithy-go v1.22.5/go.mod h1:t1ufH5HMublsJYulve2RKmHDC15xu1f26kHCp/HgceI= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= @@ -892,6 +892,7 @@ github.com/cncf/xds/go v0.0.0-20230105202645-06c439db220b/go.mod h1:eXthEFrGJvWH github.com/cncf/xds/go v0.0.0-20230310173818-32f1caf87195/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20240723142845-024c85f92f20/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8= github.com/cncf/xds/go v0.0.0-20240905190251-b4127c9b8d78/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8= +github.com/cncf/xds/go v0.0.0-20250501225837-2ac532fd4443 h1:aQ3y1lwWyqYPiWZThqv1aFbZMiM9vblcSArJRf2Irls= github.com/cncf/xds/go v0.0.0-20250501225837-2ac532fd4443/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8= github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= @@ -918,9 +919,11 @@ github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaB github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE= github.com/envoyproxy/go-control-plane v0.10.3/go.mod h1:fJJn/j26vwOu972OllsvAgJJM//w9BV6Fxbg2LuVd34= github.com/envoyproxy/go-control-plane v0.11.0/go.mod h1:VnHyVMpzcLvCFt9yUz1UnCwHLhwx1WguiVDV7pTG/tI= +github.com/envoyproxy/go-control-plane v0.13.4 h1:zEqyPVyku6IvWCFwux4x9RxkLOMUL+1vC9xUFv5l2/M= github.com/envoyproxy/go-control-plane v0.13.4/go.mod h1:kDfuBlDVsSj2MjrLEtRWtHlsWIFcGyB2RMO44Dc5GZA= github.com/envoyproxy/go-control-plane/envoy v1.32.2/go.mod h1:eR2SOX2IedqlPvmiKjUH7Wu//S602JKI7HPC/L3SRq8= github.com/envoyproxy/go-control-plane/envoy v1.32.3/go.mod h1:F6hWupPfh75TBXGKA++MCT/CZHFq5r9/uwt/kQYkZfE= +github.com/envoyproxy/go-control-plane/envoy v1.32.4 h1:jb83lalDRZSpPWW2Z7Mck/8kXZ5CQAFYVjQcdVIr83A= github.com/envoyproxy/go-control-plane/envoy v1.32.4/go.mod h1:Gzjc5k8JcJswLjAx1Zm+wSYE20UrLtt7JZMWiWQXQEw= github.com/envoyproxy/go-control-plane/ratelimit v0.1.0/go.mod h1:Wk+tMFAFbCXaJPzVVHnPgRKdUdwW/KdbRt94AzgRee4= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= @@ -929,6 +932,7 @@ github.com/envoyproxy/protoc-gen-validate v0.9.1/go.mod h1:OKNgG7TCp5pF4d6XftA0+ github.com/envoyproxy/protoc-gen-validate v0.10.0/go.mod h1:DRjgyB0I43LtJapqN6NiRwroiAU2PaFuvk/vjgh61ss= github.com/envoyproxy/protoc-gen-validate v1.0.4/go.mod h1:qys6tmnRsYrQqIhm2bvKZH4Blx/1gTIZ2UKVY1M+Yew= github.com/envoyproxy/protoc-gen-validate v1.1.0/go.mod h1:sXRDRVmzEbkM7CVcM06s9shE/m23dg3wzjl0UWqJ2q4= +github.com/envoyproxy/protoc-gen-validate v1.2.1 h1:DEo3O99U8j4hBFwbJfrz9VtgcDfUKS7KJ7spH3d86P8= github.com/envoyproxy/protoc-gen-validate v1.2.1/go.mod h1:d/C80l/jxXLdfEIhX1W2TmLfsJ31lvEjwamM4DxlWXU= github.com/esiqveland/notify v0.11.0/go.mod h1:63UbVSaeJwF0LVJARHFuPgUAoM7o1BEvCZyknsuonBc= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= @@ -958,7 +962,7 @@ github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2 github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20231223183121-56fa3ac82ce7/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-jose/go-jose/v4 v4.0.4/go.mod h1:NKb5HO1EZccyMpiZNbdUw/14tiXNyUJh188dfnMCAfc= -github.com/go-jose/go-jose/v4 v4.1.1/go.mod h1:BdsZGqgdO3b6tTc6LSE56wcDbMMLuPsw5d4ZD5f94kA= +github.com/go-jose/go-jose/v4 v4.1.2/go.mod h1:22cg9HWM1pOlnRiY+9cQYJ9XHmya1bYW8OeDM6Ku6Oo= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o= @@ -1109,8 +1113,8 @@ github.com/googleapis/gax-go/v2 v2.7.1/go.mod h1:4orTrqY6hXxxaUL4LHIPl6lGo8vAE38 github.com/googleapis/gax-go/v2 v2.8.0/go.mod h1:4orTrqY6hXxxaUL4LHIPl6lGo8vAE38/qKbhSAKP6QI= github.com/googleapis/gax-go/v2 v2.10.0/go.mod h1:4UOEnMCrxsSqQ940WnTiD6qJ63le2ev3xfyagutxiPw= github.com/googleapis/gax-go/v2 v2.11.0/go.mod h1:DxmR61SGKkGLa2xigwuZIQpkCI2S5iydzRfb3peWZJI= -github.com/googleapis/gax-go/v2 v2.14.2 h1:eBLnkZ9635krYIPD+ag1USrOAI0Nr0QYF3+/3GqO0k0= -github.com/googleapis/gax-go/v2 v2.14.2/go.mod h1:ON64QhlJkhVtSqp4v1uaK92VyZ2gmvDQsweuyLV+8+w= +github.com/googleapis/gax-go/v2 v2.15.0 h1:SyjDc1mGgZU5LncH8gimWo9lW1DtIfPibOG81vgd/bo= +github.com/googleapis/gax-go/v2 v2.15.0/go.mod h1:zVVkkxAQHa1RQpg9z2AUCMnKhi0Qld9rcmyfL1OZhoc= github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4= github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= @@ -1253,6 +1257,7 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA= github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= +github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 h1:GFCKgmp0tecUJ0sJuv4pzYCqS9+RGSn52M3FUwPs+uo= github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10/go.mod h1:t/avpk3KcrXxUnYOhZhMXJlSEyie6gQbtLq5NM3loB8= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= @@ -1440,8 +1445,9 @@ golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ss golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc= golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc= golang.org/x/crypto v0.38.0/go.mod h1:MvrbAqul58NNYPKnOra203SB9vpuZW0e+RRZV+Ggqjw= -golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM= golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U= +golang.org/x/crypto v0.40.0 h1:r4x+VvoG5Fm+eJcxMaY8CQM7Lb0l1lsmjGBQ6s8BfKM= +golang.org/x/crypto v0.40.0/go.mod h1:Qr1vMER5WyS2dfPHAlsOj01wgLbsyWtFn/aY+5+ZdxY= golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -1618,8 +1624,9 @@ golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k= golang.org/x/net v0.37.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8= golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds= -golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw= golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA= +golang.org/x/net v0.42.0 h1:jzkYrhi3YQWD6MLBJcsklgQsoAcw89EcZbJw8Z614hs= +golang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -1677,8 +1684,9 @@ golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sync v0.14.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= -golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8= golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw= +golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -1788,8 +1796,9 @@ golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= -golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA= +golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE= golang.org/x/telemetry v0.0.0-20240521205824-bda55230c457/go.mod h1:pRgIJT+bRLFKnoM1ldnzKoxTIn14Yxz928LQRYYgIN0= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= @@ -1818,6 +1827,7 @@ golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM= golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek= golang.org/x/term v0.30.0/go.mod h1:NYYFdzHoI5wRh/h5tDMdMqCqPJZEuNqVR5xJLd/n67g= golang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ= +golang.org/x/term v0.33.0/go.mod h1:s18+ql9tYWp1IfpV9DmCtQDDSRBUjKaw9M1eAv5UeF0= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1846,8 +1856,9 @@ golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY= golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4= golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA= -golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M= golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA= +golang.org/x/text v0.27.0 h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4= +golang.org/x/text v0.27.0/go.mod h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -1933,6 +1944,7 @@ golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxb golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c= golang.org/x/tools v0.26.0/go.mod h1:TPVVj70c7JJ3WCazhD8OdXcZg/og+b9+tH/KxylGwH0= golang.org/x/tools v0.33.0/go.mod h1:CIJMaWEY88juyUfo7UbgPqbC8rU2OqfAV1h2Qp0oMYI= +golang.org/x/tools v0.34.0/go.mod h1:pAP9OwEaY1CAW3HOmg3hLZC5Z0CCmzjAF2UQMSqNARg= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -2018,8 +2030,8 @@ google.golang.org/api v0.122.0/go.mod h1:gcitW0lvnyWjSp9nKxAbdHKIZ6vF4aajGueeslZ google.golang.org/api v0.124.0/go.mod h1:xu2HQurE5gi/3t1aFCvhPD781p0a3p11sdunTJ2BlP4= google.golang.org/api v0.125.0/go.mod h1:mBwVAtz+87bEN6CbA1GtZPDOqY2R5ONPqJeIlvyo4Aw= google.golang.org/api v0.126.0/go.mod h1:mBwVAtz+87bEN6CbA1GtZPDOqY2R5ONPqJeIlvyo4Aw= -google.golang.org/api v0.240.0 h1:PxG3AA2UIqT1ofIzWV2COM3j3JagKTKSwy7L6RHNXNU= -google.golang.org/api v0.240.0/go.mod h1:cOVEm2TpdAGHL2z+UwyS+kmlGr3bVWQQ6sYEqkKje50= +google.golang.org/api v0.245.0 h1:YliGvz1rjXB+sTLNIST6Ffeji9WlRdLQ+LPl9ruSa5Y= +google.golang.org/api v0.245.0/go.mod h1:dMVhVcylamkirHdzEBAIQWUCgqY885ivNeZYd7VAVr8= google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -2168,8 +2180,8 @@ google.golang.org/genproto v0.0.0-20230629202037-9506855d4529/go.mod h1:xZnkP7mR google.golang.org/genproto v0.0.0-20230706204954-ccb25ca9f130/go.mod h1:O9kGHb51iE/nOGvQaDUuadVYqovW56s5emA88lQnj6Y= google.golang.org/genproto v0.0.0-20230726155614-23370e0ffb3e/go.mod h1:0ggbjUrZYpy1q+ANUS30SEoGZ53cdfwtbuG7Ptgy108= google.golang.org/genproto v0.0.0-20230803162519-f966b187b2e5/go.mod h1:oH/ZOT02u4kWEp7oYBGYFFkCdKS/uYR9Z7+0/xuuFp8= -google.golang.org/genproto v0.0.0-20250707201910-8d1bb00bc6a7 h1:FGOcxvKlJgRBVbXeugjljCfCgfKWhC42FBoYmTCWVBs= -google.golang.org/genproto v0.0.0-20250707201910-8d1bb00bc6a7/go.mod h1:249YoW4b1INqFTEop2T4aJgiO7UBYJrpejsaLvjWfI8= +google.golang.org/genproto v0.0.0-20250804133106-a7a43d27e69b h1:eZTgydvqZO44zyTZAvMaSyAxccZZdraiSAGvqOczVvk= +google.golang.org/genproto v0.0.0-20250804133106-a7a43d27e69b/go.mod h1:suyz2QBHQKlGIF92HEEsCfO1SwxXdk7PFLz+Zd9Uah4= google.golang.org/genproto/googleapis/api v0.0.0-20230525234020-1aefcd67740a/go.mod h1:ts19tUU+Z0ZShN1y3aPyq2+O3d5FUNNgT6FtOzmrNn8= google.golang.org/genproto/googleapis/api v0.0.0-20230525234035-dd9d682886f9/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig= google.golang.org/genproto/googleapis/api v0.0.0-20230526203410-71b5a4ffd15e/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig= @@ -2180,8 +2192,8 @@ google.golang.org/genproto/googleapis/api v0.0.0-20230726155614-23370e0ffb3e/go. google.golang.org/genproto/googleapis/api v0.0.0-20230822172742-b8732ec3820d/go.mod h1:KjSP20unUpOx5kyQUFa7k4OJg0qeJ7DEZflGDu2p6Bk= google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142/go.mod h1:d6be+8HhtEtucleCbxpPW9PA9XwISACu8nvpPqF0BVo= google.golang.org/genproto/googleapis/api v0.0.0-20241202173237-19429a94021a/go.mod h1:jehYqy3+AhJU9ve55aNOaSml7wUXjF9x6z2LcCfpAhY= -google.golang.org/genproto/googleapis/api v0.0.0-20250707201910-8d1bb00bc6a7 h1:FiusG7LWj+4byqhbvmB+Q93B/mOxJLN2DTozDuZm4EU= -google.golang.org/genproto/googleapis/api v0.0.0-20250707201910-8d1bb00bc6a7/go.mod h1:kXqgZtrWaf6qS3jZOCnCH7WYfrvFjkC51bM8fz3RsCA= +google.golang.org/genproto/googleapis/api v0.0.0-20250804133106-a7a43d27e69b h1:ULiyYQ0FdsJhwwZUwbaXpZF5yUE3h+RA+gxvBu37ucc= +google.golang.org/genproto/googleapis/api v0.0.0-20250804133106-a7a43d27e69b/go.mod h1:oDOGiMSXHL4sDTJvFvIB9nRQCGdLP1o/iVaqQK8zB+M= google.golang.org/genproto/googleapis/bytestream v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:ylj+BE99M198VPbBh6A8d9n3w8fChvyLK3wwBOjXBFA= google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234015-3fc162c6f38a/go.mod h1:xURIpW9ES5+/GZhnV6beoEtxQrnkRGIfP5VQG2tCBLc= google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA= @@ -2198,9 +2210,9 @@ google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142/go. google.golang.org/genproto/googleapis/rpc v0.0.0-20240826202546-f6391c0de4c7/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= google.golang.org/genproto/googleapis/rpc v0.0.0-20241118233622-e639e219e697/go.mod h1:5uTbfoYQed2U9p3KIj2/Zzm02PYhndfdmML0qC3q3FU= google.golang.org/genproto/googleapis/rpc v0.0.0-20241202173237-19429a94021a/go.mod h1:5uTbfoYQed2U9p3KIj2/Zzm02PYhndfdmML0qC3q3FU= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250707201910-8d1bb00bc6a7 h1:pFyd6EwwL2TqFf8emdthzeX+gZE1ElRq3iM8pui4KBY= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250707201910-8d1bb00bc6a7/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250728155136-f173205681a0/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250804133106-a7a43d27e69b h1:zPKJod4w6F1+nRGDI9ubnXYhU9NSWoFAijkHkUXeTK8= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250804133106-a7a43d27e69b/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/grpc/examples v0.0.0-20230224211313-3775f633ce20/go.mod h1:Nr5H8+MlGWr5+xX/STzdoEqJrO+YteqFbMyCsrb6mH0= google.golang.org/grpc/stats/opencensus v1.0.0 h1:evSYcRZaSToQp+borzWE52+03joezZeXcKJvZDfkUJA= diff --git a/go.mod b/go.mod index 2ded5df83a4f..69ed077a60fa 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module google.golang.org/grpc -go 1.23.0 +go 1.24.0 require ( github.com/cespare/xxhash/v2 v2.3.0 @@ -18,12 +18,12 @@ require ( go.opentelemetry.io/otel/sdk v1.37.0 go.opentelemetry.io/otel/sdk/metric v1.37.0 go.opentelemetry.io/otel/trace v1.37.0 - golang.org/x/net v0.41.0 + golang.org/x/net v0.42.0 golang.org/x/oauth2 v0.30.0 - golang.org/x/sync v0.15.0 - golang.org/x/sys v0.33.0 + golang.org/x/sync v0.16.0 + golang.org/x/sys v0.34.0 gonum.org/v1/gonum v0.16.0 - google.golang.org/genproto/googleapis/rpc v0.0.0-20250707201910-8d1bb00bc6a7 + google.golang.org/genproto/googleapis/rpc v0.0.0-20250804133106-a7a43d27e69b google.golang.org/protobuf v1.36.6 ) @@ -33,15 +33,15 @@ require ( github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.29.0 // indirect github.com/envoyproxy/go-control-plane/ratelimit v0.1.0 // indirect github.com/envoyproxy/protoc-gen-validate v1.2.1 // indirect - github.com/go-jose/go-jose/v4 v4.1.1 // indirect + github.com/go-jose/go-jose/v4 v4.1.2 // indirect github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 // indirect github.com/zeebo/errs v1.4.0 // indirect go.opentelemetry.io/auto/sdk v1.1.0 // indirect - golang.org/x/crypto v0.39.0 // indirect - golang.org/x/text v0.26.0 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20250707201910-8d1bb00bc6a7 // indirect + golang.org/x/crypto v0.40.0 // indirect + golang.org/x/text v0.27.0 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20250804133106-a7a43d27e69b // indirect ) // v1.74.0 was published prematurely with known issues. diff --git a/go.sum b/go.sum index 8ecc160ed5f1..f5a1c044c65f 100644 --- a/go.sum +++ b/go.sum @@ -18,8 +18,8 @@ github.com/envoyproxy/go-control-plane/ratelimit v0.1.0 h1:/G9QYbddjL25KvtKTv3an github.com/envoyproxy/go-control-plane/ratelimit v0.1.0/go.mod h1:Wk+tMFAFbCXaJPzVVHnPgRKdUdwW/KdbRt94AzgRee4= github.com/envoyproxy/protoc-gen-validate v1.2.1 h1:DEo3O99U8j4hBFwbJfrz9VtgcDfUKS7KJ7spH3d86P8= github.com/envoyproxy/protoc-gen-validate v1.2.1/go.mod h1:d/C80l/jxXLdfEIhX1W2TmLfsJ31lvEjwamM4DxlWXU= -github.com/go-jose/go-jose/v4 v4.1.1 h1:JYhSgy4mXXzAdF3nUx3ygx347LRXJRrpgyU3adRmkAI= -github.com/go-jose/go-jose/v4 v4.1.1/go.mod h1:BdsZGqgdO3b6tTc6LSE56wcDbMMLuPsw5d4ZD5f94kA= +github.com/go-jose/go-jose/v4 v4.1.2 h1:TK/7NqRQZfgAh+Td8AlsrvtPoUyiHh0LqVvokh+1vHI= +github.com/go-jose/go-jose/v4 v4.1.2/go.mod h1:22cg9HWM1pOlnRiY+9cQYJ9XHmya1bYW8OeDM6Ku6Oo= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= @@ -59,24 +59,24 @@ go.opentelemetry.io/otel/trace v1.37.0 h1:HLdcFNbRQBE2imdSEgm/kwqmQj1Or1l/7bW6mx go.opentelemetry.io/otel/trace v1.37.0/go.mod h1:TlgrlQ+PtQO5XFerSPUYG0JSgGyryXewPGyayAWSBS0= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= -golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM= -golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U= -golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw= -golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA= +golang.org/x/crypto v0.40.0 h1:r4x+VvoG5Fm+eJcxMaY8CQM7Lb0l1lsmjGBQ6s8BfKM= +golang.org/x/crypto v0.40.0/go.mod h1:Qr1vMER5WyS2dfPHAlsOj01wgLbsyWtFn/aY+5+ZdxY= +golang.org/x/net v0.42.0 h1:jzkYrhi3YQWD6MLBJcsklgQsoAcw89EcZbJw8Z614hs= +golang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8= golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI= golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU= -golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8= -golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= -golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= -golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= -golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M= -golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA= +golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw= +golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA= +golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/text v0.27.0 h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4= +golang.org/x/text v0.27.0/go.mod h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU= gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk= gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E= -google.golang.org/genproto/googleapis/api v0.0.0-20250707201910-8d1bb00bc6a7 h1:FiusG7LWj+4byqhbvmB+Q93B/mOxJLN2DTozDuZm4EU= -google.golang.org/genproto/googleapis/api v0.0.0-20250707201910-8d1bb00bc6a7/go.mod h1:kXqgZtrWaf6qS3jZOCnCH7WYfrvFjkC51bM8fz3RsCA= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250707201910-8d1bb00bc6a7 h1:pFyd6EwwL2TqFf8emdthzeX+gZE1ElRq3iM8pui4KBY= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250707201910-8d1bb00bc6a7/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= +google.golang.org/genproto/googleapis/api v0.0.0-20250804133106-a7a43d27e69b h1:ULiyYQ0FdsJhwwZUwbaXpZF5yUE3h+RA+gxvBu37ucc= +google.golang.org/genproto/googleapis/api v0.0.0-20250804133106-a7a43d27e69b/go.mod h1:oDOGiMSXHL4sDTJvFvIB9nRQCGdLP1o/iVaqQK8zB+M= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250804133106-a7a43d27e69b h1:zPKJod4w6F1+nRGDI9ubnXYhU9NSWoFAijkHkUXeTK8= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250804133106-a7a43d27e69b/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= diff --git a/internal/balancergroup/balancergroup_test.go b/internal/balancergroup/balancergroup_test.go index 9dfad1a76b72..5d3029c882a8 100644 --- a/internal/balancergroup/balancergroup_test.go +++ b/internal/balancergroup/balancergroup_test.go @@ -484,6 +484,67 @@ func (s) TestBalancerGroupBuildOptions(t *testing.T) { } } +func (s) TestBalancerGroup_UpdateClientConnState_AfterClose(t *testing.T) { + balancerName := t.Name() + clientConnStateCh := make(chan struct{}, 1) + + stub.Register(balancerName, stub.BalancerFuncs{ + UpdateClientConnState: func(_ *stub.BalancerData, _ balancer.ClientConnState) error { + clientConnStateCh <- struct{}{} + return nil + }, + }) + + bg := New(Options{ + CC: testutils.NewBalancerClientConn(t), + BuildOpts: balancer.BuildOptions{}, + StateAggregator: nil, + Logger: nil, + }) + + bg.Add(testBalancerIDs[0], balancer.Get(balancerName)) + bg.Close() + + if err := bg.UpdateClientConnState(testBalancerIDs[0], balancer.ClientConnState{}); err != nil { + t.Fatalf("Expected nil error, got %v", err) + } + + select { + case <-clientConnStateCh: + t.Fatalf("UpdateClientConnState was called after BalancerGroup was closed") + case <-time.After(defaultTestShortTimeout): + } +} + +func (s) TestBalancerGroup_ResolverError_AfterClose(t *testing.T) { + balancerName := t.Name() + resolveErrorCh := make(chan struct{}, 1) + + stub.Register(balancerName, stub.BalancerFuncs{ + ResolverError: func(_ *stub.BalancerData, _ error) { + resolveErrorCh <- struct{}{} + }, + }) + + bg := New(Options{ + CC: testutils.NewBalancerClientConn(t), + BuildOpts: balancer.BuildOptions{}, + StateAggregator: nil, + Logger: nil, + }) + + bg.Add(testBalancerIDs[0], balancer.Get(balancerName)) + bg.Close() + + bg.ResolverError(errors.New("test error")) + + select { + case <-resolveErrorCh: + t.Fatalf("ResolverError was called on sub-balancer after BalancerGroup was closed") + case <-time.After(defaultTestShortTimeout): + } +} + func (s) TestBalancerExitIdleOne(t *testing.T) { const balancerName = "stub-balancer-test-balancergroup-exit-idle-one" exitIdleCh := make(chan struct{}, 1) @@ -505,7 +566,7 @@ func (s) TestBalancerExitIdleOne(t *testing.T) { builder := balancer.Get(balancerName) bg.Add(testBalancerIDs[0], builder) - // Call ExitIdle on the child policy. + // Call ExitIdleOne on the child policy. bg.ExitIdleOne(testBalancerIDs[0]) select { case <-time.After(time.Second): @@ -514,6 +575,62 @@ func (s) TestBalancerExitIdleOne(t *testing.T) { } } +func (s) TestBalancerGroup_ExitIdleOne_AfterClose(t *testing.T) { + balancerName := t.Name() + exitIdleCh := make(chan struct{}) + + stub.Register(balancerName, stub.BalancerFuncs{ + ExitIdle: func(_ *stub.BalancerData) { + close(exitIdleCh) + }, + }) + + bg := New(Options{ + CC: testutils.NewBalancerClientConn(t), + BuildOpts: balancer.BuildOptions{}, + StateAggregator: nil, + Logger: nil, + }) + + bg.Add(testBalancerIDs[0], balancer.Get(balancerName)) + bg.Close() + bg.ExitIdleOne(testBalancerIDs[0]) + + select { + case <-time.After(defaultTestShortTimeout): + case <-exitIdleCh: + t.Fatalf("ExitIdleOne called ExitIdle on sub-balancer after BalancerGroup was closed") + } +} + +func (s) TestBalancerGroup_ExitIdleOne_NonExistentID(t *testing.T) { + balancerName := t.Name() + exitIdleCh := make(chan struct{}, 1) + + stub.Register(balancerName, stub.BalancerFuncs{ + ExitIdle: func(_ *stub.BalancerData) { + exitIdleCh <- struct{}{} + }, + }) + + bg := New(Options{ + CC: testutils.NewBalancerClientConn(t), + BuildOpts: balancer.BuildOptions{}, + StateAggregator: nil, + Logger: nil, + }) + defer bg.Close() + + bg.Add(testBalancerIDs[0], balancer.Get(balancerName)) + bg.ExitIdleOne("non-existent-id") + + select { + case <-time.After(defaultTestShortTimeout): + case <-exitIdleCh: + t.Fatalf("ExitIdleOne called ExitIdle on wrong sub-balancer ID") + } +} + // TestBalancerGracefulSwitch tests the graceful switch functionality for a // child of the balancer group. At first, the child is configured as a round // robin load balancer, and thus should behave accordingly. The test then @@ -639,3 +756,92 @@ func (s) TestBalancerGracefulSwitch(t *testing.T) { } } } + +func (s) TestBalancerExitIdle_All(t *testing.T) { + balancer1 := t.Name() + "-1" + balancer2 := t.Name() + "-2" + + testID1, testID2 := testBalancerIDs[0], testBalancerIDs[1] + + exitIdleCh1, exitIdleCh2 := make(chan struct{}, 1), make(chan struct{}, 1) + + stub.Register(balancer1, stub.BalancerFuncs{ + ExitIdle: func(_ *stub.BalancerData) { + exitIdleCh1 <- struct{}{} + }, + }) + + stub.Register(balancer2, stub.BalancerFuncs{ + ExitIdle: func(_ *stub.BalancerData) { + exitIdleCh2 <- struct{}{} + }, + }) + + cc := testutils.NewBalancerClientConn(t) + bg := New(Options{ + CC: cc, + BuildOpts: balancer.BuildOptions{}, + StateAggregator: nil, + Logger: nil, + }) + defer bg.Close() + + bg.Add(testID1, balancer.Get(balancer1)) + bg.Add(testID2, balancer.Get(balancer2)) + + bg.ExitIdle() + + errCh := make(chan error, 2) + + go func() { + select { + case <-exitIdleCh1: + errCh <- nil + case <-time.After(defaultTestTimeout): + errCh <- fmt.Errorf("timeout waiting for ExitIdle on balancer1") + } + }() + + go func() { + select { + case <-exitIdleCh2: + errCh <- nil + case <-time.After(defaultTestTimeout): + errCh <- fmt.Errorf("timeout waiting for ExitIdle on balancer2") + } + }() + + for i := 0; i < 2; i++ { + if err := <-errCh; err != nil { + t.Fatal(err) + } + } +} + +func (s) TestBalancerGroup_ExitIdle_AfterClose(t *testing.T) { + balancerName := t.Name() + exitIdleCh := make(chan struct{}, 1) + + stub.Register(balancerName, stub.BalancerFuncs{ + ExitIdle: func(_ *stub.BalancerData) { + exitIdleCh <- struct{}{} + }, + }) + + bg := New(Options{ + CC: testutils.NewBalancerClientConn(t), + BuildOpts: balancer.BuildOptions{}, + StateAggregator: nil, + Logger: nil, + }) + + bg.Add(testBalancerIDs[0], balancer.Get(balancerName)) + bg.Close() + bg.ExitIdle() + + select { + case <-exitIdleCh: + t.Fatalf("ExitIdle was called on sub-balancer even after BalancerGroup was closed") + case <-time.After(defaultTestShortTimeout): + } +} diff --git a/internal/buffer/unbounded.go b/internal/buffer/unbounded.go index 11f91668ac9b..467392b8d455 100644 --- a/internal/buffer/unbounded.go +++ b/internal/buffer/unbounded.go @@ -83,6 +83,7 @@ func (b *Unbounded) Load() { default: } } else if b.closing && !b.closed { + b.closed = true close(b.c) } } diff --git a/internal/channelz/trace.go b/internal/channelz/trace.go index 2bffe4777684..3b7ba5966253 100644 --- a/internal/channelz/trace.go +++ b/internal/channelz/trace.go @@ -194,7 +194,7 @@ func (r RefChannelType) String() string { // If channelz is not turned ON, this will simply log the event descriptions. func AddTraceEvent(l grpclog.DepthLoggerV2, e Entity, depth int, desc *TraceEvent) { // Log only the trace description associated with the bottom most entity. - d := fmt.Sprintf("[%s]%s", e, desc.Desc) + d := fmt.Sprintf("[%s] %s", e, desc.Desc) switch desc.Severity { case CtUnknown, CtInfo: l.InfoDepth(depth+1, d) diff --git a/internal/envconfig/xds.go b/internal/envconfig/xds.go index e87551552ad7..b1f883bcac1e 100644 --- a/internal/envconfig/xds.go +++ b/internal/envconfig/xds.go @@ -68,4 +68,10 @@ var ( // trust. For more details, see: // https://github.com/grpc/proposal/blob/master/A87-mtls-spiffe-support.md XDSSPIFFEEnabled = boolFromEnv("GRPC_EXPERIMENTAL_XDS_MTLS_SPIFFE", false) + + // XDSHTTPConnectEnabled is true if gRPC should parse custom Metadata + // configuring use of an HTTP CONNECT proxy via xDS from cluster resources. + // For more details, see: + // https://github.com/grpc/proposal/blob/master/A86-xds-http-connect.md + XDSHTTPConnectEnabled = boolFromEnv("GRPC_EXPERIMENTAL_XDS_HTTP_CONNECT", false) ) diff --git a/internal/grpcsync/callback_serializer.go b/internal/grpcsync/callback_serializer.go index 8e8e861280a0..9b6d8a1fa3fe 100644 --- a/internal/grpcsync/callback_serializer.go +++ b/internal/grpcsync/callback_serializer.go @@ -80,25 +80,11 @@ func (cs *CallbackSerializer) ScheduleOr(f func(ctx context.Context), onFailure func (cs *CallbackSerializer) run(ctx context.Context) { defer close(cs.done) - // TODO: when Go 1.21 is the oldest supported version, this loop and Close - // can be replaced with: - // - // context.AfterFunc(ctx, cs.callbacks.Close) - for ctx.Err() == nil { - select { - case <-ctx.Done(): - // Do nothing here. Next iteration of the for loop will not happen, - // since ctx.Err() would be non-nil. - case cb := <-cs.callbacks.Get(): - cs.callbacks.Load() - cb.(func(context.Context))(ctx) - } - } - - // Close the buffer to prevent new callbacks from being added. - cs.callbacks.Close() + // Close the buffer when the context is canceled + // to prevent new callbacks from being added. + context.AfterFunc(ctx, cs.callbacks.Close) - // Run all pending callbacks. + // Run all callbacks. for cb := range cs.callbacks.Get() { cs.callbacks.Load() cb.(func(context.Context))(ctx) diff --git a/internal/transport/handler_server.go b/internal/transport/handler_server.go index 3dea23573518..d954a64c38f4 100644 --- a/internal/transport/handler_server.go +++ b/internal/transport/handler_server.go @@ -277,11 +277,13 @@ func (ht *serverHandlerTransport) writeStatus(s *ServerStream, st *status.Status if err == nil { // transport has not been closed // Note: The trailer fields are compressed with hpack after this call returns. // No WireLength field is set here. + s.hdrMu.Lock() for _, sh := range ht.stats { sh.HandleRPC(s.Context(), &stats.OutTrailer{ Trailer: s.trailer.Copy(), }) } + s.hdrMu.Unlock() } ht.Close(errors.New("finished writing status")) return err diff --git a/internal/transport/handler_server_test.go b/internal/transport/handler_server_test.go index 911022834322..e64af27411da 100644 --- a/internal/transport/handler_server_test.go +++ b/internal/transport/handler_server_test.go @@ -35,6 +35,7 @@ import ( "google.golang.org/grpc/codes" "google.golang.org/grpc/mem" "google.golang.org/grpc/metadata" + "google.golang.org/grpc/stats" "google.golang.org/grpc/status" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/protoadapt" @@ -246,7 +247,26 @@ type handleStreamTest struct { ht *serverHandlerTransport } -func newHandleStreamTest(t *testing.T) *handleStreamTest { +type mockStatsHandler struct { + rpcStatsCh chan stats.RPCStats +} + +func (h *mockStatsHandler) TagRPC(ctx context.Context, _ *stats.RPCTagInfo) context.Context { + return ctx +} + +func (h *mockStatsHandler) HandleRPC(_ context.Context, s stats.RPCStats) { + h.rpcStatsCh <- s +} + +func (h *mockStatsHandler) TagConn(ctx context.Context, _ *stats.ConnTagInfo) context.Context { + return ctx +} + +func (h *mockStatsHandler) HandleConn(context.Context, stats.ConnStats) { +} + +func newHandleStreamTest(t *testing.T, statsHandlers []stats.Handler) *handleStreamTest { bodyr, bodyw := io.Pipe() req := &http.Request{ ProtoMajor: 2, @@ -260,7 +280,7 @@ func newHandleStreamTest(t *testing.T) *handleStreamTest { Body: bodyr, } rw := newTestHandlerResponseWriter().(testHandlerResponseWriter) - ht, err := NewServerHandlerTransport(rw, req, nil, mem.DefaultBufferPool()) + ht, err := NewServerHandlerTransport(rw, req, statsHandlers, mem.DefaultBufferPool()) if err != nil { t.Fatal(err) } @@ -273,7 +293,7 @@ func newHandleStreamTest(t *testing.T) *handleStreamTest { } func (s) TestHandlerTransport_HandleStreams(t *testing.T) { - st := newHandleStreamTest(t) + st := newHandleStreamTest(t, nil) handleStream := func(s *ServerStream) { if want := "/service/foo.bar"; s.method != want { t.Errorf("stream method = %q; want %q", s.method, want) @@ -342,7 +362,7 @@ func (s) TestHandlerTransport_HandleStreams_InvalidArgument(t *testing.T) { } func handleStreamCloseBodyTest(t *testing.T, statusCode codes.Code, msg string) { - st := newHandleStreamTest(t) + st := newHandleStreamTest(t, nil) handleStream := func(s *ServerStream) { s.WriteStatus(status.New(statusCode, msg)) @@ -451,7 +471,7 @@ func (s) TestHandlerTransport_HandleStreams_WriteStatusWrite(t *testing.T) { } func testHandlerTransportHandleStreams(t *testing.T, handleStream func(st *handleStreamTest, s *ServerStream)) { - st := newHandleStreamTest(t) + st := newHandleStreamTest(t, nil) ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) t.Cleanup(cancel) st.ht.HandleStreams( @@ -483,7 +503,7 @@ func (s) TestHandlerTransport_HandleStreams_ErrDetails(t *testing.T) { t.Fatal(err) } - hst := newHandleStreamTest(t) + hst := newHandleStreamTest(t, nil) handleStream := func(s *ServerStream) { s.WriteStatus(st) } @@ -506,11 +526,81 @@ func (s) TestHandlerTransport_HandleStreams_ErrDetails(t *testing.T) { checkHeaderAndTrailer(t, hst.rw, wantHeader, wantTrailer) } +// Tests the use of stats handlers and ensures there are no data races while +// accessing trailers. +func (s) TestHandlerTransport_HandleStreams_StatsHandlers(t *testing.T) { + errDetails := []protoadapt.MessageV1{ + &epb.RetryInfo{ + RetryDelay: &durationpb.Duration{Seconds: 60}, + }, + &epb.ResourceInfo{ + ResourceType: "foo bar", + ResourceName: "service.foo.bar", + Owner: "User", + }, + } + + statusCode := codes.ResourceExhausted + msg := "you are being throttled" + st, err := status.New(statusCode, msg).WithDetails(errDetails...) + if err != nil { + t.Fatal(err) + } + + stBytes, err := proto.Marshal(st.Proto()) + if err != nil { + t.Fatal(err) + } + // Add mock stats handlers to exercise the stats handler code path. + statsHandler := &mockStatsHandler{ + rpcStatsCh: make(chan stats.RPCStats, 2), + } + hst := newHandleStreamTest(t, []stats.Handler{statsHandler}) + handleStream := func(s *ServerStream) { + if err := s.SendHeader(metadata.New(map[string]string{})); err != nil { + t.Error(err) + } + if err := s.SetTrailer(metadata.Pairs("custom-trailer", "Custom trailer value")); err != nil { + t.Error(err) + } + s.WriteStatus(st) + } + ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) + defer cancel() + hst.ht.HandleStreams( + ctx, func(s *ServerStream) { go handleStream(s) }, + ) + wantHeader := http.Header{ + "Date": nil, + "Content-Type": {"application/grpc"}, + "Trailer": {"Grpc-Status", "Grpc-Message", "Grpc-Status-Details-Bin"}, + } + wantTrailer := http.Header{ + "Grpc-Status": {fmt.Sprint(uint32(statusCode))}, + "Grpc-Message": {encodeGrpcMessage(msg)}, + "Grpc-Status-Details-Bin": {encodeBinHeader(stBytes)}, + "Custom-Trailer": []string{"Custom trailer value"}, + } + + checkHeaderAndTrailer(t, hst.rw, wantHeader, wantTrailer) + wantStatTypes := []stats.RPCStats{&stats.OutHeader{}, &stats.OutTrailer{}} + for _, wantType := range wantStatTypes { + select { + case <-ctx.Done(): + t.Fatal("Context timed out waiting for statsHandler.HandleRPC() to be called.") + case s := <-statsHandler.rpcStatsCh: + if reflect.TypeOf(s) != reflect.TypeOf(wantType) { + t.Fatalf("Received RPCStats of type %T, want %T", s, wantType) + } + } + } +} + // TestHandlerTransport_Drain verifies that Drain() is not implemented // by `serverHandlerTransport`. func (s) TestHandlerTransport_Drain(t *testing.T) { defer func() { recover() }() - st := newHandleStreamTest(t) + st := newHandleStreamTest(t, nil) st.ht.Drain("whatever") t.Errorf("serverHandlerTransport.Drain() should have panicked") } diff --git a/internal/transport/http2_client.go b/internal/transport/http2_client.go index 5467fe9715a3..7cb238794fb5 100644 --- a/internal/transport/http2_client.go +++ b/internal/transport/http2_client.go @@ -556,6 +556,19 @@ func (t *http2Client) createHeaderFields(ctx context.Context, callHdr *CallHdr) // Make the slice of certain predictable size to reduce allocations made by append. hfLen := 7 // :method, :scheme, :path, :authority, content-type, user-agent, te hfLen += len(authData) + len(callAuthData) + registeredCompressors := t.registeredCompressors + if callHdr.PreviousAttempts > 0 { + hfLen++ + } + if callHdr.SendCompress != "" { + hfLen++ + } + if registeredCompressors != "" { + hfLen++ + } + if _, ok := ctx.Deadline(); ok { + hfLen++ + } headerFields := make([]hpack.HeaderField, 0, hfLen) headerFields = append(headerFields, hpack.HeaderField{Name: ":method", Value: "POST"}) headerFields = append(headerFields, hpack.HeaderField{Name: ":scheme", Value: t.scheme}) @@ -568,7 +581,6 @@ func (t *http2Client) createHeaderFields(ctx context.Context, callHdr *CallHdr) headerFields = append(headerFields, hpack.HeaderField{Name: "grpc-previous-rpc-attempts", Value: strconv.Itoa(callHdr.PreviousAttempts)}) } - registeredCompressors := t.registeredCompressors if callHdr.SendCompress != "" { headerFields = append(headerFields, hpack.HeaderField{Name: "grpc-encoding", Value: callHdr.SendCompress}) // Include the outgoing compressor name when compressor is not registered @@ -1499,13 +1511,6 @@ func (t *http2Client) operateHeaders(frame *http2.MetaHeadersFrame) { case "grpc-message": grpcMessage = decodeGrpcMessage(hf.Value) case ":status": - if hf.Value == "200" { - httpStatusErr = "" - statusCode := 200 - httpStatusCode = &statusCode - break - } - c, err := strconv.ParseInt(hf.Value, 10, 32) if err != nil { se := status.New(codes.Internal, fmt.Sprintf("transport: malformed http-status: %v", err)) @@ -1513,7 +1518,19 @@ func (t *http2Client) operateHeaders(frame *http2.MetaHeadersFrame) { return } statusCode := int(c) + if statusCode >= 100 && statusCode < 200 { + if endStream { + se := status.New(codes.Internal, fmt.Sprintf( + "protocol error: informational header with status code %d must not have END_STREAM set", statusCode)) + t.closeStream(s, se.Err(), true, http2.ErrCodeProtocol, se, nil, endStream) + } + return + } httpStatusCode = &statusCode + if statusCode == 200 { + httpStatusErr = "" + break + } httpStatusErr = fmt.Sprintf( "unexpected HTTP status code received from server: %d (%s)", diff --git a/internal/transport/http2_server.go b/internal/transport/http2_server.go index 9f725e15a812..83cee314c8f4 100644 --- a/internal/transport/http2_server.go +++ b/internal/transport/http2_server.go @@ -1353,10 +1353,10 @@ func (t *http2Server) closeStream(s *ServerStream, rst bool, rstCode http2.ErrCo // called to interrupt the potential blocking on other goroutines. s.cancel() - oldState := s.swapState(streamDone) - if oldState == streamDone { - return - } + // We can't return early even if the stream's state is "done" as the state + // might have been set by the `finishStream` method. Deleting the stream via + // `finishStream` can get blocked on flow control. + s.swapState(streamDone) t.deleteStream(s, eosReceived) t.controlBuf.put(&cleanupStream{ diff --git a/internal/transport/transport_test.go b/internal/transport/transport_test.go index b8f97c3c9464..d0c8a88d6abf 100644 --- a/internal/transport/transport_test.go +++ b/internal/transport/transport_test.go @@ -3125,3 +3125,82 @@ func (s) TestServerSendsRSTAfterDeadlineToMisbehavedClient(t *testing.T) { t.Fatalf("RST frame received earlier than expected by duration: %v", want-got) } } + +// TestClientTransport_Handle1xxHeaders validates that 1xx HTTP status headers +// are ignored and treated as a protocol error if END_STREAM is set. +func (s) TestClientTransport_Handle1xxHeaders(t *testing.T) { + testStream := func() *ClientStream { + return &ClientStream{ + Stream: &Stream{ + buf: &recvBuffer{ + c: make(chan recvMsg), + mu: sync.Mutex{}, + }, + }, + done: make(chan struct{}), + headerChan: make(chan struct{}), + } + } + + testClient := func(ts *ClientStream) *http2Client { + return &http2Client{ + mu: sync.Mutex{}, + activeStreams: map[uint32]*ClientStream{ + 0: ts, + }, + controlBuf: newControlBuffer(make(<-chan struct{})), + } + } + + for _, test := range []struct { + name string + metaHeaderFrame *http2.MetaHeadersFrame + httpFlags http2.Flags + wantStatus *status.Status + }{ + { + name: "1xx with END_STREAM is error", + metaHeaderFrame: &http2.MetaHeadersFrame{ + Fields: []hpack.HeaderField{ + {Name: ":status", Value: "100"}, + }, + }, + httpFlags: http2.FlagHeadersEndStream, + wantStatus: status.New( + codes.Internal, + "protocol error: informational header with status code 100 must not have END_STREAM set", + ), + }, + { + name: "1xx without END_STREAM is ignored", + metaHeaderFrame: &http2.MetaHeadersFrame{ + Fields: []hpack.HeaderField{ + {Name: ":status", Value: "100"}, + }, + }, + httpFlags: 0, + wantStatus: nil, + }, + } { + t.Run(test.name, func(t *testing.T) { + ts := testStream() + s := testClient(ts) + + test.metaHeaderFrame.HeadersFrame = &http2.HeadersFrame{ + FrameHeader: http2.FrameHeader{ + StreamID: 0, + Flags: test.httpFlags, + }, + } + + s.operateHeaders(test.metaHeaderFrame) + + got := ts.status + want := test.wantStatus + + if got.Code() != want.Code() || got.Message() != want.Message() { + t.Fatalf("operateHeaders(%v); status = %v, want %v", test.metaHeaderFrame, got, want) + } + }) + } +} diff --git a/xds/internal/balancer/balancer.go b/internal/xds/balancer/balancer.go similarity index 75% rename from xds/internal/balancer/balancer.go rename to internal/xds/balancer/balancer.go index ff27af026db5..af3f999a1204 100644 --- a/xds/internal/balancer/balancer.go +++ b/internal/xds/balancer/balancer.go @@ -22,10 +22,10 @@ package balancer import ( _ "google.golang.org/grpc/balancer/leastrequest" // Register the least_request_experimental balancer _ "google.golang.org/grpc/balancer/weightedtarget" // Register the weighted_target balancer - _ "google.golang.org/grpc/xds/internal/balancer/cdsbalancer" // Register the CDS balancer - _ "google.golang.org/grpc/xds/internal/balancer/clusterimpl" // Register the xds_cluster_impl balancer - _ "google.golang.org/grpc/xds/internal/balancer/clustermanager" // Register the xds_cluster_manager balancer - _ "google.golang.org/grpc/xds/internal/balancer/clusterresolver" // Register the xds_cluster_resolver balancer - _ "google.golang.org/grpc/xds/internal/balancer/outlierdetection" // Register the outlier_detection balancer - _ "google.golang.org/grpc/xds/internal/balancer/priority" // Register the priority balancer + _ "google.golang.org/grpc/internal/xds/balancer/cdsbalancer" // Register the CDS balancer + _ "google.golang.org/grpc/internal/xds/balancer/clusterimpl" // Register the xds_cluster_impl balancer + _ "google.golang.org/grpc/internal/xds/balancer/clustermanager" // Register the xds_cluster_manager balancer + _ "google.golang.org/grpc/internal/xds/balancer/clusterresolver" // Register the xds_cluster_resolver balancer + _ "google.golang.org/grpc/internal/xds/balancer/outlierdetection" // Register the outlier_detection balancer + _ "google.golang.org/grpc/internal/xds/balancer/priority" // Register the priority balancer ) diff --git a/xds/internal/balancer/cdsbalancer/aggregate_cluster_test.go b/internal/xds/balancer/cdsbalancer/aggregate_cluster_test.go similarity index 93% rename from xds/internal/balancer/cdsbalancer/aggregate_cluster_test.go rename to internal/xds/balancer/cdsbalancer/aggregate_cluster_test.go index f1dead24d5ce..581f511ba34f 100644 --- a/xds/internal/balancer/cdsbalancer/aggregate_cluster_test.go +++ b/internal/xds/balancer/cdsbalancer/aggregate_cluster_test.go @@ -31,13 +31,15 @@ import ( "google.golang.org/grpc/internal/stubserver" "google.golang.org/grpc/internal/testutils" "google.golang.org/grpc/internal/testutils/xds/e2e" + xdsinternal "google.golang.org/grpc/internal/xds" + "google.golang.org/grpc/internal/xds/balancer/clusterresolver" + "google.golang.org/grpc/internal/xds/xdsclient/xdsresource/version" "google.golang.org/grpc/serviceconfig" "google.golang.org/grpc/status" - "google.golang.org/grpc/xds/internal" - "google.golang.org/grpc/xds/internal/balancer/clusterresolver" v3clusterpb "github.com/envoyproxy/go-control-plane/envoy/config/cluster/v3" v3endpointpb "github.com/envoyproxy/go-control-plane/envoy/config/endpoint/v3" + v3discoverypb "github.com/envoyproxy/go-control-plane/envoy/service/discovery/v3" testgrpc "google.golang.org/grpc/interop/grpc_testing" testpb "google.golang.org/grpc/interop/grpc_testing" ) @@ -86,7 +88,7 @@ func (s) TestAggregateClusterSuccess_LeafNode(t *testing.T) { Type: clusterresolver.DiscoveryMechanismTypeEDS, EDSServiceName: serviceName, OutlierDetection: json.RawMessage(`{}`), - TelemetryLabels: internal.UnknownCSMLabels, + TelemetryLabels: xdsinternal.UnknownCSMLabels, }}, XDSLBPolicy: json.RawMessage(`[{"xds_wrr_locality_experimental": {"childPolicy": [{"round_robin": {}}]}}]`), }, @@ -96,7 +98,7 @@ func (s) TestAggregateClusterSuccess_LeafNode(t *testing.T) { Type: clusterresolver.DiscoveryMechanismTypeEDS, EDSServiceName: serviceName + "-new", OutlierDetection: json.RawMessage(`{}`), - TelemetryLabels: internal.UnknownCSMLabels, + TelemetryLabels: xdsinternal.UnknownCSMLabels, }}, XDSLBPolicy: json.RawMessage(`[{"xds_wrr_locality_experimental": {"childPolicy": [{"round_robin": {}}]}}]`), }, @@ -111,7 +113,7 @@ func (s) TestAggregateClusterSuccess_LeafNode(t *testing.T) { Type: clusterresolver.DiscoveryMechanismTypeLogicalDNS, DNSHostname: "dns_host:8080", OutlierDetection: json.RawMessage(`{}`), - TelemetryLabels: internal.UnknownCSMLabels, + TelemetryLabels: xdsinternal.UnknownCSMLabels, }}, XDSLBPolicy: json.RawMessage(`[{"xds_wrr_locality_experimental": {"childPolicy": [{"round_robin": {}}]}}]`), }, @@ -121,7 +123,7 @@ func (s) TestAggregateClusterSuccess_LeafNode(t *testing.T) { Type: clusterresolver.DiscoveryMechanismTypeLogicalDNS, DNSHostname: "dns_host_new:8080", OutlierDetection: json.RawMessage(`{}`), - TelemetryLabels: internal.UnknownCSMLabels, + TelemetryLabels: xdsinternal.UnknownCSMLabels, }}, XDSLBPolicy: json.RawMessage(`[{"xds_wrr_locality_experimental": {"childPolicy": [{"round_robin": {}}]}}]`), }, @@ -131,7 +133,7 @@ func (s) TestAggregateClusterSuccess_LeafNode(t *testing.T) { for _, test := range tests { t.Run(test.name, func(t *testing.T) { lbCfgCh, _, _, _ := registerWrappedClusterResolverPolicy(t) - mgmtServer, nodeID, _, _, _, _, _ := setupWithManagementServer(t) + mgmtServer, nodeID, _, _, _ := setupWithManagementServer(t, nil, nil) // Push the first cluster resource through the management server and // verify the configuration pushed to the child policy. @@ -174,7 +176,7 @@ func (s) TestAggregateClusterSuccess_LeafNode(t *testing.T) { // contains the expected discovery mechanisms. func (s) TestAggregateClusterSuccess_ThenUpdateChildClusters(t *testing.T) { lbCfgCh, _, _, _ := registerWrappedClusterResolverPolicy(t) - mgmtServer, nodeID, _, _, _, _, _ := setupWithManagementServer(t) + mgmtServer, nodeID, _, _, _ := setupWithManagementServer(t, nil, nil) // Configure the management server with the aggregate cluster resource // pointing to two child clusters, one EDS and one LogicalDNS. Include the @@ -216,14 +218,14 @@ func (s) TestAggregateClusterSuccess_ThenUpdateChildClusters(t *testing.T) { Type: clusterresolver.DiscoveryMechanismTypeEDS, EDSServiceName: serviceName, OutlierDetection: json.RawMessage(`{}`), - TelemetryLabels: internal.UnknownCSMLabels, + TelemetryLabels: xdsinternal.UnknownCSMLabels, }, { Cluster: dnsClusterName, Type: clusterresolver.DiscoveryMechanismTypeLogicalDNS, DNSHostname: fmt.Sprintf("%s:%d", dnsHostName, dnsPort), OutlierDetection: json.RawMessage(`{}`), - TelemetryLabels: internal.UnknownCSMLabels, + TelemetryLabels: xdsinternal.UnknownCSMLabels, }, }, XDSLBPolicy: json.RawMessage(`[{"xds_wrr_locality_experimental": {"childPolicy": [{"round_robin": {}}]}}]`), @@ -254,14 +256,14 @@ func (s) TestAggregateClusterSuccess_ThenUpdateChildClusters(t *testing.T) { Type: clusterresolver.DiscoveryMechanismTypeEDS, EDSServiceName: serviceName, OutlierDetection: json.RawMessage(`{}`), - TelemetryLabels: internal.UnknownCSMLabels, + TelemetryLabels: xdsinternal.UnknownCSMLabels, }, { Cluster: dnsClusterNameNew, Type: clusterresolver.DiscoveryMechanismTypeLogicalDNS, DNSHostname: fmt.Sprintf("%s:%d", dnsHostNameNew, dnsPort), OutlierDetection: json.RawMessage(`{}`), - TelemetryLabels: internal.UnknownCSMLabels, + TelemetryLabels: xdsinternal.UnknownCSMLabels, }, }, XDSLBPolicy: json.RawMessage(`[{"xds_wrr_locality_experimental": {"childPolicy": [{"round_robin": {}}]}}]`), @@ -281,7 +283,7 @@ func (s) TestAggregateClusterSuccess_ThenUpdateChildClusters(t *testing.T) { // policy contains a single discovery mechanism. func (s) TestAggregateClusterSuccess_ThenChangeRootToEDS(t *testing.T) { lbCfgCh, _, _, _ := registerWrappedClusterResolverPolicy(t) - mgmtServer, nodeID, _, _, _, _, _ := setupWithManagementServer(t) + mgmtServer, nodeID, _, _, _ := setupWithManagementServer(t, nil, nil) // Configure the management server with the aggregate cluster resource // pointing to two child clusters. @@ -307,14 +309,14 @@ func (s) TestAggregateClusterSuccess_ThenChangeRootToEDS(t *testing.T) { Type: clusterresolver.DiscoveryMechanismTypeEDS, EDSServiceName: serviceName, OutlierDetection: json.RawMessage(`{}`), - TelemetryLabels: internal.UnknownCSMLabels, + TelemetryLabels: xdsinternal.UnknownCSMLabels, }, { Cluster: dnsClusterName, Type: clusterresolver.DiscoveryMechanismTypeLogicalDNS, DNSHostname: fmt.Sprintf("%s:%d", dnsHostName, dnsPort), OutlierDetection: json.RawMessage(`{}`), - TelemetryLabels: internal.UnknownCSMLabels, + TelemetryLabels: xdsinternal.UnknownCSMLabels, }, }, XDSLBPolicy: json.RawMessage(`[{"xds_wrr_locality_experimental": {"childPolicy": [{"round_robin": {}}]}}]`), @@ -340,7 +342,7 @@ func (s) TestAggregateClusterSuccess_ThenChangeRootToEDS(t *testing.T) { Type: clusterresolver.DiscoveryMechanismTypeEDS, EDSServiceName: serviceName, OutlierDetection: json.RawMessage(`{}`), - TelemetryLabels: internal.UnknownCSMLabels, + TelemetryLabels: xdsinternal.UnknownCSMLabels, }}, XDSLBPolicy: json.RawMessage(`[{"xds_wrr_locality_experimental": {"childPolicy": [{"round_robin": {}}]}}]`), } @@ -356,7 +358,7 @@ func (s) TestAggregateClusterSuccess_ThenChangeRootToEDS(t *testing.T) { // discovery mechanisms. func (s) TestAggregatedClusterSuccess_SwitchBetweenLeafAndAggregate(t *testing.T) { lbCfgCh, _, _, _ := registerWrappedClusterResolverPolicy(t) - mgmtServer, nodeID, _, _, _, _, _ := setupWithManagementServer(t) + mgmtServer, nodeID, _, _, _ := setupWithManagementServer(t, nil, nil) // Start off with the requested cluster being a leaf EDS cluster. resources := e2e.UpdateOptions{ @@ -375,7 +377,7 @@ func (s) TestAggregatedClusterSuccess_SwitchBetweenLeafAndAggregate(t *testing.T Type: clusterresolver.DiscoveryMechanismTypeEDS, EDSServiceName: serviceName, OutlierDetection: json.RawMessage(`{}`), - TelemetryLabels: internal.UnknownCSMLabels, + TelemetryLabels: xdsinternal.UnknownCSMLabels, }}, XDSLBPolicy: json.RawMessage(`[{"xds_wrr_locality_experimental": {"childPolicy": [{"round_robin": {}}]}}]`), } @@ -404,14 +406,14 @@ func (s) TestAggregatedClusterSuccess_SwitchBetweenLeafAndAggregate(t *testing.T Type: clusterresolver.DiscoveryMechanismTypeEDS, EDSServiceName: serviceName, OutlierDetection: json.RawMessage(`{}`), - TelemetryLabels: internal.UnknownCSMLabels, + TelemetryLabels: xdsinternal.UnknownCSMLabels, }, { Cluster: dnsClusterName, Type: clusterresolver.DiscoveryMechanismTypeLogicalDNS, DNSHostname: fmt.Sprintf("%s:%d", dnsHostName, dnsPort), OutlierDetection: json.RawMessage(`{}`), - TelemetryLabels: internal.UnknownCSMLabels, + TelemetryLabels: xdsinternal.UnknownCSMLabels, }, }, XDSLBPolicy: json.RawMessage(`[{"xds_wrr_locality_experimental": {"childPolicy": [{"round_robin": {}}]}}]`), @@ -435,7 +437,7 @@ func (s) TestAggregatedClusterSuccess_SwitchBetweenLeafAndAggregate(t *testing.T Type: clusterresolver.DiscoveryMechanismTypeEDS, EDSServiceName: serviceName, OutlierDetection: json.RawMessage(`{}`), - TelemetryLabels: internal.UnknownCSMLabels, + TelemetryLabels: xdsinternal.UnknownCSMLabels, }}, XDSLBPolicy: json.RawMessage(`[{"xds_wrr_locality_experimental": {"childPolicy": [{"round_robin": {}}]}}]`), } @@ -450,7 +452,7 @@ func (s) TestAggregatedClusterSuccess_SwitchBetweenLeafAndAggregate(t *testing.T // longer exceed maximum depth, but be at the maximum allowed depth, and // verifies that an RPC can be made successfully. func (s) TestAggregatedClusterFailure_ExceedsMaxStackDepth(t *testing.T) { - mgmtServer, nodeID, cc, _, _, _, _ := setupWithManagementServer(t) + mgmtServer, nodeID, cc, _, _ := setupWithManagementServer(t, nil, nil) resources := e2e.UpdateOptions{ NodeID: nodeID, @@ -538,7 +540,7 @@ func (s) TestAggregatedClusterFailure_ExceedsMaxStackDepth(t *testing.T) { // pushed only after all child clusters are resolved. func (s) TestAggregatedClusterSuccess_DiamondDependency(t *testing.T) { lbCfgCh, _, _, _ := registerWrappedClusterResolverPolicy(t) - mgmtServer, nodeID, _, _, _, _, _ := setupWithManagementServer(t) + mgmtServer, nodeID, _, _, _ := setupWithManagementServer(t, nil, nil) // Configure the management server with an aggregate cluster resource having // a diamond dependency pattern, (A->[B,C]; B->D; C->D). Includes resources @@ -588,7 +590,7 @@ func (s) TestAggregatedClusterSuccess_DiamondDependency(t *testing.T) { Type: clusterresolver.DiscoveryMechanismTypeEDS, EDSServiceName: serviceName, OutlierDetection: json.RawMessage(`{}`), - TelemetryLabels: internal.UnknownCSMLabels, + TelemetryLabels: xdsinternal.UnknownCSMLabels, }}, XDSLBPolicy: json.RawMessage(`[{"xds_wrr_locality_experimental": {"childPolicy": [{"round_robin": {}}]}}]`), } @@ -605,7 +607,7 @@ func (s) TestAggregatedClusterSuccess_DiamondDependency(t *testing.T) { // pushed only after all child clusters are resolved. func (s) TestAggregatedClusterSuccess_IgnoreDups(t *testing.T) { lbCfgCh, _, _, _ := registerWrappedClusterResolverPolicy(t) - mgmtServer, nodeID, _, _, _, _, _ := setupWithManagementServer(t) + mgmtServer, nodeID, _, _, _ := setupWithManagementServer(t, nil, nil) // Configure the management server with an aggregate cluster resource that // has duplicates in the graph, (A->[B, C]; B->[C, D]). Include resources @@ -656,14 +658,14 @@ func (s) TestAggregatedClusterSuccess_IgnoreDups(t *testing.T) { Type: clusterresolver.DiscoveryMechanismTypeEDS, EDSServiceName: serviceName, OutlierDetection: json.RawMessage(`{}`), - TelemetryLabels: internal.UnknownCSMLabels, + TelemetryLabels: xdsinternal.UnknownCSMLabels, }, { Cluster: clusterNameD, Type: clusterresolver.DiscoveryMechanismTypeEDS, EDSServiceName: serviceName, OutlierDetection: json.RawMessage(`{}`), - TelemetryLabels: internal.UnknownCSMLabels, + TelemetryLabels: xdsinternal.UnknownCSMLabels, }, }, XDSLBPolicy: json.RawMessage(`[{"xds_wrr_locality_experimental": {"childPolicy": [{"round_robin": {}}]}}]`), @@ -683,7 +685,7 @@ func (s) TestAggregatedClusterSuccess_IgnoreDups(t *testing.T) { // child policy and that an RPC can be successfully made. func (s) TestAggregatedCluster_NodeChildOfItself(t *testing.T) { lbCfgCh, _, _, _ := registerWrappedClusterResolverPolicy(t) - mgmtServer, nodeID, cc, _, _, _, _ := setupWithManagementServer(t) + mgmtServer, nodeID, cc, _, _ := setupWithManagementServer(t, nil, nil) const ( clusterNameA = clusterName // cluster name in cds LB policy config @@ -746,7 +748,7 @@ func (s) TestAggregatedCluster_NodeChildOfItself(t *testing.T) { Type: clusterresolver.DiscoveryMechanismTypeEDS, EDSServiceName: serviceName, OutlierDetection: json.RawMessage(`{}`), - TelemetryLabels: internal.UnknownCSMLabels, + TelemetryLabels: xdsinternal.UnknownCSMLabels, }}, XDSLBPolicy: json.RawMessage(`[{"xds_wrr_locality_experimental": {"childPolicy": [{"round_robin": {}}]}}]`), } @@ -768,7 +770,7 @@ func (s) TestAggregatedCluster_NodeChildOfItself(t *testing.T) { // that the aggregate cluster graph has no leaf clusters. func (s) TestAggregatedCluster_CycleWithNoLeafNode(t *testing.T) { lbCfgCh, _, _, _ := registerWrappedClusterResolverPolicy(t) - mgmtServer, nodeID, cc, _, _, _, _ := setupWithManagementServer(t) + mgmtServer, nodeID, cc, _, _ := setupWithManagementServer(t, nil, nil) const ( clusterNameA = clusterName // cluster name in cds LB policy config @@ -816,7 +818,7 @@ func (s) TestAggregatedCluster_CycleWithNoLeafNode(t *testing.T) { // child policy and RPCs should get routed to that leaf cluster. func (s) TestAggregatedCluster_CycleWithLeafNode(t *testing.T) { lbCfgCh, _, _, _ := registerWrappedClusterResolverPolicy(t) - mgmtServer, nodeID, cc, _, _, _, _ := setupWithManagementServer(t) + mgmtServer, nodeID, cc, _, _ := setupWithManagementServer(t, nil, nil) // Start a test service backend. server := stubserver.StartTestService(t, nil) @@ -852,7 +854,7 @@ func (s) TestAggregatedCluster_CycleWithLeafNode(t *testing.T) { Type: clusterresolver.DiscoveryMechanismTypeEDS, EDSServiceName: serviceName, OutlierDetection: json.RawMessage(`{}`), - TelemetryLabels: internal.UnknownCSMLabels, + TelemetryLabels: xdsinternal.UnknownCSMLabels, }}, XDSLBPolicy: json.RawMessage(`[{"xds_wrr_locality_experimental": {"childPolicy": [{"round_robin": {}}]}}]`), } @@ -872,10 +874,21 @@ func (s) TestAggregatedCluster_CycleWithLeafNode(t *testing.T) { // removed from the tree no longer has a watcher and the new cluster added has a // new watcher. func (s) TestWatchers(t *testing.T) { - mgmtServer, nodeID, _, _, _, cdsResourceRequestedCh, _ := setupWithManagementServer(t) - ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) defer cancel() + cdsResourceRequestedCh := make(chan []string, 1) + onStreamReq := func(_ int64, req *v3discoverypb.DiscoveryRequest) error { + if req.GetTypeUrl() == version.V3ClusterURL { + if len(req.GetResourceNames()) > 0 { + select { + case cdsResourceRequestedCh <- req.GetResourceNames(): + case <-ctx.Done(): + } + } + } + return nil + } + mgmtServer, nodeID, _, _, _ := setupWithManagementServer(t, nil, onStreamReq) const ( clusterA = clusterName diff --git a/xds/internal/balancer/cdsbalancer/cdsbalancer.go b/internal/xds/balancer/cdsbalancer/cdsbalancer.go similarity index 99% rename from xds/internal/balancer/cdsbalancer/cdsbalancer.go rename to internal/xds/balancer/cdsbalancer/cdsbalancer.go index b413b8acdb98..0ad77b85e9f1 100644 --- a/xds/internal/balancer/cdsbalancer/cdsbalancer.go +++ b/internal/xds/balancer/cdsbalancer/cdsbalancer.go @@ -35,11 +35,11 @@ import ( "google.golang.org/grpc/internal/grpclog" "google.golang.org/grpc/internal/grpcsync" "google.golang.org/grpc/internal/pretty" + "google.golang.org/grpc/internal/xds/balancer/clusterresolver" + "google.golang.org/grpc/internal/xds/xdsclient" + "google.golang.org/grpc/internal/xds/xdsclient/xdsresource" "google.golang.org/grpc/resolver" "google.golang.org/grpc/serviceconfig" - "google.golang.org/grpc/xds/internal/balancer/clusterresolver" - "google.golang.org/grpc/xds/internal/xdsclient" - "google.golang.org/grpc/xds/internal/xdsclient/xdsresource" ) const ( diff --git a/xds/internal/balancer/cdsbalancer/cdsbalancer_security_test.go b/internal/xds/balancer/cdsbalancer/cdsbalancer_security_test.go similarity index 99% rename from xds/internal/balancer/cdsbalancer/cdsbalancer_security_test.go rename to internal/xds/balancer/cdsbalancer/cdsbalancer_security_test.go index 2df4fbf52fdf..401a16dce69d 100644 --- a/xds/internal/balancer/cdsbalancer/cdsbalancer_security_test.go +++ b/internal/xds/balancer/cdsbalancer/cdsbalancer_security_test.go @@ -45,12 +45,12 @@ import ( "google.golang.org/grpc/internal/testutils" "google.golang.org/grpc/internal/testutils/xds/e2e" "google.golang.org/grpc/internal/xds/bootstrap" + "google.golang.org/grpc/internal/xds/xdsclient" "google.golang.org/grpc/peer" "google.golang.org/grpc/resolver" "google.golang.org/grpc/resolver/manual" "google.golang.org/grpc/serviceconfig" "google.golang.org/grpc/testdata" - "google.golang.org/grpc/xds/internal/xdsclient" v3clusterpb "github.com/envoyproxy/go-control-plane/envoy/config/cluster/v3" v3corepb "github.com/envoyproxy/go-control-plane/envoy/config/core/v3" diff --git a/xds/internal/balancer/cdsbalancer/cdsbalancer_test.go b/internal/xds/balancer/cdsbalancer/cdsbalancer_test.go similarity index 93% rename from xds/internal/balancer/cdsbalancer/cdsbalancer_test.go rename to internal/xds/balancer/cdsbalancer/cdsbalancer_test.go index a152b78d7df5..ca13655d40a2 100644 --- a/xds/internal/balancer/cdsbalancer/cdsbalancer_test.go +++ b/internal/xds/balancer/cdsbalancer/cdsbalancer_test.go @@ -39,16 +39,16 @@ import ( "google.golang.org/grpc/internal/stubserver" "google.golang.org/grpc/internal/testutils" "google.golang.org/grpc/internal/testutils/xds/e2e" + xdsinternal "google.golang.org/grpc/internal/xds" + "google.golang.org/grpc/internal/xds/balancer/clusterresolver" "google.golang.org/grpc/internal/xds/bootstrap" + "google.golang.org/grpc/internal/xds/xdsclient" + "google.golang.org/grpc/internal/xds/xdsclient/xdsresource" + "google.golang.org/grpc/internal/xds/xdsclient/xdsresource/version" "google.golang.org/grpc/resolver" "google.golang.org/grpc/resolver/manual" "google.golang.org/grpc/serviceconfig" "google.golang.org/grpc/status" - xdsinternal "google.golang.org/grpc/xds/internal" - "google.golang.org/grpc/xds/internal/balancer/clusterresolver" - "google.golang.org/grpc/xds/internal/xdsclient" - "google.golang.org/grpc/xds/internal/xdsclient/xdsresource" - "google.golang.org/grpc/xds/internal/xdsclient/xdsresource/version" "google.golang.org/protobuf/types/known/durationpb" "google.golang.org/protobuf/types/known/wrapperspb" @@ -183,7 +183,8 @@ func registerWrappedCDSPolicy(t *testing.T) chan balancer.Balancer { } // Performs the following setup required for tests: -// - Spins up an xDS management server +// - Spins up an xDS management server and and the provided onStreamRequest +// function is set to be called for every incoming request on the ADS stream. // - Creates an xDS client talking to this management server // - Creates a manual resolver that configures the cds LB policy as the // top-level policy, and pushes an initial configuration to it @@ -195,39 +196,11 @@ func registerWrappedCDSPolicy(t *testing.T) chan balancer.Balancer { // - the grpc channel to the test backend service // - the manual resolver configured on the channel // - the xDS client used the grpc channel -// - a channel on which requested cluster resource names are sent -// - a channel used to signal that previously requested cluster resources are -// no longer requested -func setupWithManagementServer(t *testing.T) (*e2e.ManagementServer, string, *grpc.ClientConn, *manual.Resolver, xdsclient.XDSClient, chan []string, chan struct{}) { - return setupWithManagementServerAndListener(t, nil) -} - -// Same as setupWithManagementServer, but also allows the caller to specify -// a listener to be used by the management server. -func setupWithManagementServerAndListener(t *testing.T, lis net.Listener) (*e2e.ManagementServer, string, *grpc.ClientConn, *manual.Resolver, xdsclient.XDSClient, chan []string, chan struct{}) { +func setupWithManagementServer(t *testing.T, lis net.Listener, onStreamRequest func(int64, *v3discoverypb.DiscoveryRequest) error) (*e2e.ManagementServer, string, *grpc.ClientConn, *manual.Resolver, xdsclient.XDSClient) { t.Helper() - - cdsResourceRequestedCh := make(chan []string, 1) - cdsResourceCanceledCh := make(chan struct{}, 1) mgmtServer := e2e.StartManagementServer(t, e2e.ManagementServerOptions{ - Listener: lis, - OnStreamRequest: func(_ int64, req *v3discoverypb.DiscoveryRequest) error { - if req.GetTypeUrl() == version.V3ClusterURL { - switch len(req.GetResourceNames()) { - case 0: - select { - case cdsResourceCanceledCh <- struct{}{}: - default: - } - default: - select { - case cdsResourceRequestedCh <- req.GetResourceNames(): - default: - } - } - } - return nil - }, + Listener: lis, + OnStreamRequest: onStreamRequest, // Required for aggregate clusters as all resources cannot be requested // at once. AllowResourceSubset: true, @@ -268,7 +241,7 @@ func setupWithManagementServerAndListener(t *testing.T, lis net.Listener) (*e2e. cc.Connect() t.Cleanup(func() { cc.Close() }) - return mgmtServer, nodeID, cc, r, xdsC, cdsResourceRequestedCh, cdsResourceCanceledCh + return mgmtServer, nodeID, cc, r, xdsC } // Helper function to compare the load balancing configuration received on the @@ -321,11 +294,23 @@ func verifyRPCError(gotErr error, wantCode codes.Code, wantErr, wantNodeID strin // configuration changes, it stops requesting the old cluster resource and // starts requesting the new one. func (s) TestConfigurationUpdate_Success(t *testing.T) { - _, _, _, r, xdsClient, cdsResourceRequestedCh, _ := setupWithManagementServer(t) - - // Verify that the specified cluster resource is requested. ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) defer cancel() + cdsResourceRequestedCh := make(chan []string, 1) + onStreamReq := func(_ int64, req *v3discoverypb.DiscoveryRequest) error { + if req.GetTypeUrl() == version.V3ClusterURL { + if len(req.GetResourceNames()) > 0 { + select { + case cdsResourceRequestedCh <- req.GetResourceNames(): + case <-ctx.Done(): + } + } + } + return nil + } + _, _, _, r, xdsClient := setupWithManagementServer(t, nil, onStreamReq) + + // Verify that the specified cluster resource is requested. wantNames := []string{clusterName} if err := waitForResourceNames(ctx, cdsResourceRequestedCh, wantNames); err != nil { t.Fatal(err) @@ -616,7 +601,7 @@ func (s) TestClusterUpdate_Success(t *testing.T) { for _, test := range tests { t.Run(test.name, func(t *testing.T) { lbCfgCh, _, _, _ := registerWrappedClusterResolverPolicy(t) - mgmtServer, nodeID, _, _, _, _, _ := setupWithManagementServer(t) + mgmtServer, nodeID, _, _, _ := setupWithManagementServer(t, nil, nil) ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) defer cancel() @@ -640,7 +625,7 @@ func (s) TestClusterUpdate_Success(t *testing.T) { // balancing configuration pushed to the child is as expected. func (s) TestClusterUpdate_SuccessWithLRS(t *testing.T) { lbCfgCh, _, _, _ := registerWrappedClusterResolverPolicy(t) - mgmtServer, nodeID, _, _, _, _, _ := setupWithManagementServer(t) + mgmtServer, nodeID, _, _, _ := setupWithManagementServer(t, nil, nil) clusterResource := e2e.ClusterResourceWithOptions(e2e.ClusterOptions{ ClusterName: clusterName, @@ -689,15 +674,21 @@ func (s) TestClusterUpdate_SuccessWithLRS(t *testing.T) { // continue using the previous good update. func (s) TestClusterUpdate_Failure(t *testing.T) { _, resolverErrCh, _, _ := registerWrappedClusterResolverPolicy(t) - mgmtServer, nodeID, cc, _, _, cdsResourceRequestedCh, cdsResourceCanceledCh := setupWithManagementServer(t) - - // Verify that the specified cluster resource is requested. ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) defer cancel() - wantNames := []string{clusterName} - if err := waitForResourceNames(ctx, cdsResourceRequestedCh, wantNames); err != nil { - t.Fatal(err) + cdsResourceCanceledCh := make(chan struct{}, 1) + onStreamReq := func(_ int64, req *v3discoverypb.DiscoveryRequest) error { + if req.GetTypeUrl() == version.V3ClusterURL { + if len(req.GetResourceNames()) == 0 { + select { + case cdsResourceCanceledCh <- struct{}{}: + case <-ctx.Done(): + } + } + } + return nil } + mgmtServer, nodeID, cc, _, _ := setupWithManagementServer(t, nil, onStreamReq) // Configure the management server to return a cluster resource that // contains a config_source_specifier for the `lrs_server` field which is not @@ -806,12 +797,31 @@ func (s) TestClusterUpdate_Failure(t *testing.T) { func (s) TestResolverError(t *testing.T) { _, resolverErrCh, _, childPolicyCloseCh := registerWrappedClusterResolverPolicy(t) lis := testutils.NewListenerWrapper(t, nil) - mgmtServer, nodeID, cc, r, _, cdsResourceRequestedCh, cdsResourceCanceledCh := setupWithManagementServerAndListener(t, lis) + ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) + defer cancel() + cdsResourceCanceledCh := make(chan struct{}, 1) + cdsResourceRequestedCh := make(chan []string, 1) + onStreamReq := func(_ int64, req *v3discoverypb.DiscoveryRequest) error { + if req.GetTypeUrl() == version.V3ClusterURL { + switch len(req.GetResourceNames()) { + case 0: + select { + case cdsResourceCanceledCh <- struct{}{}: + case <-ctx.Done(): + } + default: + select { + case cdsResourceRequestedCh <- req.GetResourceNames(): + case <-ctx.Done(): + } + } + } + return nil + } + mgmtServer, nodeID, cc, r, _ := setupWithManagementServer(t, lis, onStreamReq) // Grab the wrapped connection from the listener wrapper. This will be used // to verify the connection is closed. - ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) - defer cancel() val, err := lis.NewConnCh.Receive(ctx) if err != nil { t.Fatalf("Failed to receive new connection from wrapped listener: %v", err) @@ -949,15 +959,21 @@ func (s) TestResolverError(t *testing.T) { // - when the cluster resource is re-sent by the management server, RPCs // should start succeeding. func (s) TestClusterUpdate_ResourceNotFound(t *testing.T) { - mgmtServer, nodeID, cc, _, _, cdsResourceRequestedCh, cdsResourceCanceledCh := setupWithManagementServer(t) - - // Verify that the specified cluster resource is requested. ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) defer cancel() - wantNames := []string{clusterName} - if err := waitForResourceNames(ctx, cdsResourceRequestedCh, wantNames); err != nil { - t.Fatal(err) + cdsResourceCanceledCh := make(chan struct{}, 1) + onStreamReq := func(_ int64, req *v3discoverypb.DiscoveryRequest) error { + if req.GetTypeUrl() == version.V3ClusterURL { + if len(req.GetResourceNames()) == 0 { + select { + case cdsResourceCanceledCh <- struct{}{}: + case <-ctx.Done(): + } + } + } + return nil } + mgmtServer, nodeID, cc, _, _ := setupWithManagementServer(t, nil, onStreamReq) // Start a test service backend. server := stubserver.StartTestService(t, nil) @@ -1028,7 +1044,7 @@ func (s) TestClusterUpdate_ResourceNotFound(t *testing.T) { func (s) TestClose(t *testing.T) { cdsBalancerCh := registerWrappedCDSPolicy(t) _, _, _, childPolicyCloseCh := registerWrappedClusterResolverPolicy(t) - mgmtServer, nodeID, cc, _, _, _, _ := setupWithManagementServer(t) + mgmtServer, nodeID, cc, _, _ := setupWithManagementServer(t, nil, nil) // Start a test service backend. server := stubserver.StartTestService(t, nil) @@ -1075,7 +1091,7 @@ func (s) TestClose(t *testing.T) { func (s) TestExitIdle(t *testing.T) { cdsBalancerCh := registerWrappedCDSPolicy(t) _, _, exitIdleCh, _ := registerWrappedClusterResolverPolicy(t) - mgmtServer, nodeID, cc, _, _, _, _ := setupWithManagementServer(t) + mgmtServer, nodeID, cc, _, _ := setupWithManagementServer(t, nil, nil) // Start a test service backend. server := stubserver.StartTestService(t, nil) diff --git a/xds/internal/balancer/cdsbalancer/cluster_watcher.go b/internal/xds/balancer/cdsbalancer/cluster_watcher.go similarity index 97% rename from xds/internal/balancer/cdsbalancer/cluster_watcher.go rename to internal/xds/balancer/cdsbalancer/cluster_watcher.go index a9adea0c8040..dd702b125b32 100644 --- a/xds/internal/balancer/cdsbalancer/cluster_watcher.go +++ b/internal/xds/balancer/cdsbalancer/cluster_watcher.go @@ -19,7 +19,7 @@ package cdsbalancer import ( "context" - "google.golang.org/grpc/xds/internal/xdsclient/xdsresource" + "google.golang.org/grpc/internal/xds/xdsclient/xdsresource" ) // clusterWatcher implements the xdsresource.ClusterWatcher interface, and is diff --git a/xds/internal/balancer/cdsbalancer/logging.go b/internal/xds/balancer/cdsbalancer/logging.go similarity index 100% rename from xds/internal/balancer/cdsbalancer/logging.go rename to internal/xds/balancer/cdsbalancer/logging.go diff --git a/xds/internal/balancer/clusterimpl/balancer_test.go b/internal/xds/balancer/clusterimpl/balancer_test.go similarity index 99% rename from xds/internal/balancer/clusterimpl/balancer_test.go rename to internal/xds/balancer/clusterimpl/balancer_test.go index 454ed9313c6f..53f2debf73d8 100644 --- a/xds/internal/balancer/clusterimpl/balancer_test.go +++ b/internal/xds/balancer/clusterimpl/balancer_test.go @@ -38,14 +38,13 @@ import ( "google.golang.org/grpc/internal/grpctest" internalserviceconfig "google.golang.org/grpc/internal/serviceconfig" "google.golang.org/grpc/internal/testutils" - "google.golang.org/grpc/internal/xds" + xdsinternal "google.golang.org/grpc/internal/xds" "google.golang.org/grpc/internal/xds/bootstrap" + "google.golang.org/grpc/internal/xds/clients" + "google.golang.org/grpc/internal/xds/testutils/fakeclient" + "google.golang.org/grpc/internal/xds/xdsclient" "google.golang.org/grpc/resolver" "google.golang.org/grpc/serviceconfig" - xdsinternal "google.golang.org/grpc/xds/internal" - "google.golang.org/grpc/xds/internal/clients" - "google.golang.org/grpc/xds/internal/testutils/fakeclient" - "google.golang.org/grpc/xds/internal/xdsclient" v3orcapb "github.com/cncf/xds/go/xds/data/orca/v3" "github.com/google/go-cmp/cmp" @@ -729,7 +728,7 @@ func (s) TestClusterNameInAddressAttributes(t *testing.T) { if got, want := addrs1[0].Addr, testBackendEndpoints[0].Addresses[0].Addr; got != want { t.Fatalf("sc is created with addr %v, want %v", got, want) } - cn, ok := xds.GetXDSHandshakeClusterName(addrs1[0].Attributes) + cn, ok := xdsinternal.GetXDSHandshakeClusterName(addrs1[0].Attributes) if !ok || cn != testClusterName { t.Fatalf("sc is created with addr with cluster name %v, %v, want cluster name %v", cn, ok, testClusterName) } @@ -760,7 +759,7 @@ func (s) TestClusterNameInAddressAttributes(t *testing.T) { t.Fatalf("sc is created with addr %v, want %v", got, want) } // New addresses should have the new cluster name. - cn2, ok := xds.GetXDSHandshakeClusterName(addrs2[0].Attributes) + cn2, ok := xdsinternal.GetXDSHandshakeClusterName(addrs2[0].Attributes) if !ok || cn2 != testClusterName2 { t.Fatalf("sc is created with addr with cluster name %v, %v, want cluster name %v", cn2, ok, testClusterName2) } diff --git a/xds/internal/balancer/clusterimpl/clusterimpl.go b/internal/xds/balancer/clusterimpl/clusterimpl.go similarity index 97% rename from xds/internal/balancer/clusterimpl/clusterimpl.go rename to internal/xds/balancer/clusterimpl/clusterimpl.go index 006be4c4eef9..ffe0a3db55a8 100644 --- a/xds/internal/balancer/clusterimpl/clusterimpl.go +++ b/internal/xds/balancer/clusterimpl/clusterimpl.go @@ -38,15 +38,14 @@ import ( "google.golang.org/grpc/internal/balancer/gracefulswitch" "google.golang.org/grpc/internal/grpclog" "google.golang.org/grpc/internal/pretty" - "google.golang.org/grpc/internal/xds" + xdsinternal "google.golang.org/grpc/internal/xds" + "google.golang.org/grpc/internal/xds/balancer/loadstore" "google.golang.org/grpc/internal/xds/bootstrap" + "google.golang.org/grpc/internal/xds/clients" + "google.golang.org/grpc/internal/xds/clients/lrsclient" + "google.golang.org/grpc/internal/xds/xdsclient" "google.golang.org/grpc/resolver" "google.golang.org/grpc/serviceconfig" - xdsinternal "google.golang.org/grpc/xds/internal" - "google.golang.org/grpc/xds/internal/balancer/loadstore" - "google.golang.org/grpc/xds/internal/clients" - "google.golang.org/grpc/xds/internal/clients/lrsclient" - "google.golang.org/grpc/xds/internal/xdsclient" ) const ( @@ -436,7 +435,7 @@ func (b *clusterImplBalancer) NewSubConn(addrs []resolver.Address, opts balancer clusterName := b.getClusterName() newAddrs := make([]resolver.Address, len(addrs)) for i, addr := range addrs { - newAddrs[i] = xds.SetXDSHandshakeClusterName(addr, clusterName) + newAddrs[i] = xdsinternal.SetXDSHandshakeClusterName(addr, clusterName) } var sc balancer.SubConn scw := &scWrapper{} @@ -475,7 +474,7 @@ func (b *clusterImplBalancer) UpdateAddresses(sc balancer.SubConn, addrs []resol newAddrs := make([]resolver.Address, len(addrs)) var lID clients.Locality for i, addr := range addrs { - newAddrs[i] = xds.SetXDSHandshakeClusterName(addr, clusterName) + newAddrs[i] = xdsinternal.SetXDSHandshakeClusterName(addr, clusterName) lID = xdsinternal.GetLocalityID(newAddrs[i]) } if scw, ok := sc.(*scWrapper); ok { diff --git a/xds/internal/balancer/clusterimpl/config.go b/internal/xds/balancer/clusterimpl/config.go similarity index 100% rename from xds/internal/balancer/clusterimpl/config.go rename to internal/xds/balancer/clusterimpl/config.go diff --git a/xds/internal/balancer/clusterimpl/config_test.go b/internal/xds/balancer/clusterimpl/config_test.go similarity index 100% rename from xds/internal/balancer/clusterimpl/config_test.go rename to internal/xds/balancer/clusterimpl/config_test.go diff --git a/xds/internal/balancer/clusterimpl/logging.go b/internal/xds/balancer/clusterimpl/logging.go similarity index 100% rename from xds/internal/balancer/clusterimpl/logging.go rename to internal/xds/balancer/clusterimpl/logging.go diff --git a/xds/internal/balancer/clusterimpl/picker.go b/internal/xds/balancer/clusterimpl/picker.go similarity index 95% rename from xds/internal/balancer/clusterimpl/picker.go rename to internal/xds/balancer/clusterimpl/picker.go index 9ed16ffbe467..fab09fa0978b 100644 --- a/xds/internal/balancer/clusterimpl/picker.go +++ b/internal/xds/balancer/clusterimpl/picker.go @@ -27,10 +27,10 @@ import ( "google.golang.org/grpc/connectivity" "google.golang.org/grpc/internal/stats" "google.golang.org/grpc/internal/wrr" + xdsinternal "google.golang.org/grpc/internal/xds" + "google.golang.org/grpc/internal/xds/clients" + "google.golang.org/grpc/internal/xds/xdsclient" "google.golang.org/grpc/status" - "google.golang.org/grpc/xds/internal" - "google.golang.org/grpc/xds/internal/clients" - "google.golang.org/grpc/xds/internal/xdsclient" ) // NewRandomWRR is used when calculating drops. It's exported so that tests can @@ -155,7 +155,7 @@ func (d *picker) Pick(info balancer.PickInfo) (balancer.PickResult, error) { } if labels := telemetryLabels(info.Ctx); labels != nil { - labels["grpc.lb.locality"] = internal.LocalityString(lID) + labels["grpc.lb.locality"] = xdsinternal.LocalityString(lID) } if d.loadStore != nil { diff --git a/xds/internal/balancer/clusterimpl/tests/balancer_test.go b/internal/xds/balancer/clusterimpl/tests/balancer_test.go similarity index 100% rename from xds/internal/balancer/clusterimpl/tests/balancer_test.go rename to internal/xds/balancer/clusterimpl/tests/balancer_test.go diff --git a/xds/internal/balancer/clustermanager/balancerstateaggregator.go b/internal/xds/balancer/clustermanager/balancerstateaggregator.go similarity index 100% rename from xds/internal/balancer/clustermanager/balancerstateaggregator.go rename to internal/xds/balancer/clustermanager/balancerstateaggregator.go diff --git a/xds/internal/balancer/clustermanager/clustermanager.go b/internal/xds/balancer/clustermanager/clustermanager.go similarity index 100% rename from xds/internal/balancer/clustermanager/clustermanager.go rename to internal/xds/balancer/clustermanager/clustermanager.go diff --git a/xds/internal/balancer/clustermanager/clustermanager_test.go b/internal/xds/balancer/clustermanager/clustermanager_test.go similarity index 100% rename from xds/internal/balancer/clustermanager/clustermanager_test.go rename to internal/xds/balancer/clustermanager/clustermanager_test.go diff --git a/xds/internal/balancer/clustermanager/config.go b/internal/xds/balancer/clustermanager/config.go similarity index 100% rename from xds/internal/balancer/clustermanager/config.go rename to internal/xds/balancer/clustermanager/config.go diff --git a/xds/internal/balancer/clustermanager/config_test.go b/internal/xds/balancer/clustermanager/config_test.go similarity index 98% rename from xds/internal/balancer/clustermanager/config_test.go rename to internal/xds/balancer/clustermanager/config_test.go index ef496a2e0004..fd815dfa111b 100644 --- a/xds/internal/balancer/clustermanager/config_test.go +++ b/internal/xds/balancer/clustermanager/config_test.go @@ -25,7 +25,7 @@ import ( "google.golang.org/grpc/balancer" _ "google.golang.org/grpc/balancer/weightedtarget" internalserviceconfig "google.golang.org/grpc/internal/serviceconfig" - _ "google.golang.org/grpc/xds/internal/balancer/cdsbalancer" + _ "google.golang.org/grpc/internal/xds/balancer/cdsbalancer" ) const ( diff --git a/xds/internal/balancer/clustermanager/e2e_test/clustermanager_test.go b/internal/xds/balancer/clustermanager/e2e_test/clustermanager_test.go similarity index 100% rename from xds/internal/balancer/clustermanager/e2e_test/clustermanager_test.go rename to internal/xds/balancer/clustermanager/e2e_test/clustermanager_test.go diff --git a/xds/internal/balancer/clustermanager/picker.go b/internal/xds/balancer/clustermanager/picker.go similarity index 100% rename from xds/internal/balancer/clustermanager/picker.go rename to internal/xds/balancer/clustermanager/picker.go diff --git a/xds/internal/balancer/clusterresolver/clusterresolver.go b/internal/xds/balancer/clusterresolver/clusterresolver.go similarity index 98% rename from xds/internal/balancer/clusterresolver/clusterresolver.go rename to internal/xds/balancer/clusterresolver/clusterresolver.go index f9ce57293393..f5a30e1acbec 100644 --- a/xds/internal/balancer/clusterresolver/clusterresolver.go +++ b/internal/xds/balancer/clusterresolver/clusterresolver.go @@ -35,12 +35,12 @@ import ( "google.golang.org/grpc/internal/grpclog" "google.golang.org/grpc/internal/grpcsync" "google.golang.org/grpc/internal/pretty" + "google.golang.org/grpc/internal/xds/balancer/outlierdetection" + "google.golang.org/grpc/internal/xds/balancer/priority" + "google.golang.org/grpc/internal/xds/xdsclient" + "google.golang.org/grpc/internal/xds/xdsclient/xdsresource" "google.golang.org/grpc/resolver" "google.golang.org/grpc/serviceconfig" - "google.golang.org/grpc/xds/internal/balancer/outlierdetection" - "google.golang.org/grpc/xds/internal/balancer/priority" - "google.golang.org/grpc/xds/internal/xdsclient" - "google.golang.org/grpc/xds/internal/xdsclient/xdsresource" ) // Name is the name of the cluster_resolver balancer. diff --git a/xds/internal/balancer/clusterresolver/clusterresolver_test.go b/internal/xds/balancer/clusterresolver/clusterresolver_test.go similarity index 100% rename from xds/internal/balancer/clusterresolver/clusterresolver_test.go rename to internal/xds/balancer/clusterresolver/clusterresolver_test.go diff --git a/xds/internal/balancer/clusterresolver/config.go b/internal/xds/balancer/clusterresolver/config.go similarity index 98% rename from xds/internal/balancer/clusterresolver/config.go rename to internal/xds/balancer/clusterresolver/config.go index 7614b0fc57bd..f3b4c6bf6146 100644 --- a/xds/internal/balancer/clusterresolver/config.go +++ b/internal/xds/balancer/clusterresolver/config.go @@ -23,9 +23,9 @@ import ( "fmt" internalserviceconfig "google.golang.org/grpc/internal/serviceconfig" + "google.golang.org/grpc/internal/xds/balancer/outlierdetection" "google.golang.org/grpc/internal/xds/bootstrap" "google.golang.org/grpc/serviceconfig" - "google.golang.org/grpc/xds/internal/balancer/outlierdetection" ) // DiscoveryMechanismType is the type of discovery mechanism. diff --git a/xds/internal/balancer/clusterresolver/config_test.go b/internal/xds/balancer/clusterresolver/config_test.go similarity index 99% rename from xds/internal/balancer/clusterresolver/config_test.go rename to internal/xds/balancer/clusterresolver/config_test.go index 79c135a63200..964359aaf368 100644 --- a/xds/internal/balancer/clusterresolver/config_test.go +++ b/internal/xds/balancer/clusterresolver/config_test.go @@ -30,8 +30,8 @@ import ( "google.golang.org/grpc/balancer/roundrobin" iringhash "google.golang.org/grpc/internal/ringhash" iserviceconfig "google.golang.org/grpc/internal/serviceconfig" + "google.golang.org/grpc/internal/xds/balancer/outlierdetection" "google.golang.org/grpc/internal/xds/bootstrap" - "google.golang.org/grpc/xds/internal/balancer/outlierdetection" ) func TestDiscoveryMechanismTypeMarshalJSON(t *testing.T) { diff --git a/xds/internal/balancer/clusterresolver/configbuilder.go b/internal/xds/balancer/clusterresolver/configbuilder.go similarity index 96% rename from xds/internal/balancer/clusterresolver/configbuilder.go rename to internal/xds/balancer/clusterresolver/configbuilder.go index 9c7fed8629ba..3d8e08972c1d 100644 --- a/xds/internal/balancer/clusterresolver/configbuilder.go +++ b/internal/xds/balancer/clusterresolver/configbuilder.go @@ -26,14 +26,14 @@ import ( "google.golang.org/grpc/internal/balancer/weight" "google.golang.org/grpc/internal/hierarchy" internalserviceconfig "google.golang.org/grpc/internal/serviceconfig" + xdsinternal "google.golang.org/grpc/internal/xds" + "google.golang.org/grpc/internal/xds/balancer/clusterimpl" + "google.golang.org/grpc/internal/xds/balancer/outlierdetection" + "google.golang.org/grpc/internal/xds/balancer/priority" + "google.golang.org/grpc/internal/xds/balancer/wrrlocality" + "google.golang.org/grpc/internal/xds/xdsclient/xdsresource" "google.golang.org/grpc/resolver" "google.golang.org/grpc/resolver/ringhash" - "google.golang.org/grpc/xds/internal" - "google.golang.org/grpc/xds/internal/balancer/clusterimpl" - "google.golang.org/grpc/xds/internal/balancer/outlierdetection" - "google.golang.org/grpc/xds/internal/balancer/priority" - "google.golang.org/grpc/xds/internal/balancer/wrrlocality" - "google.golang.org/grpc/xds/internal/xdsclient/xdsresource" ) const million = 1000000 @@ -257,7 +257,7 @@ func priorityLocalitiesToClusterImpl(localities []xdsresource.Locality, priority if locality.Weight != 0 { lw = locality.Weight } - localityStr := internal.LocalityString(locality.ID) + localityStr := xdsinternal.LocalityString(locality.ID) for _, endpoint := range locality.Endpoints { // Filter out all "unhealthy" endpoints (unknown and healthy are // both considered to be healthy: @@ -270,7 +270,7 @@ func priorityLocalitiesToClusterImpl(localities []xdsresource.Locality, priority resolverEndpoint.Addresses = append(resolverEndpoint.Addresses, resolver.Address{Addr: as}) } resolverEndpoint = hierarchy.SetInEndpoint(resolverEndpoint, []string{priorityName, localityStr}) - resolverEndpoint = internal.SetLocalityIDInEndpoint(resolverEndpoint, locality.ID) + resolverEndpoint = xdsinternal.SetLocalityIDInEndpoint(resolverEndpoint, locality.ID) // "To provide the xds_wrr_locality load balancer information about // locality weights received from EDS, the cluster resolver will // populate a new locality weight attribute for each address The diff --git a/xds/internal/balancer/clusterresolver/configbuilder_childname.go b/internal/xds/balancer/clusterresolver/configbuilder_childname.go similarity index 96% rename from xds/internal/balancer/clusterresolver/configbuilder_childname.go rename to internal/xds/balancer/clusterresolver/configbuilder_childname.go index bf4e33496ec7..296ed740e401 100644 --- a/xds/internal/balancer/clusterresolver/configbuilder_childname.go +++ b/internal/xds/balancer/clusterresolver/configbuilder_childname.go @@ -20,8 +20,8 @@ package clusterresolver import ( "fmt" - "google.golang.org/grpc/xds/internal/clients" - "google.golang.org/grpc/xds/internal/xdsclient/xdsresource" + "google.golang.org/grpc/internal/xds/clients" + "google.golang.org/grpc/internal/xds/xdsclient/xdsresource" ) // nameGenerator generates a child name for a list of priorities (each priority diff --git a/xds/internal/balancer/clusterresolver/configbuilder_childname_test.go b/internal/xds/balancer/clusterresolver/configbuilder_childname_test.go similarity index 96% rename from xds/internal/balancer/clusterresolver/configbuilder_childname_test.go rename to internal/xds/balancer/clusterresolver/configbuilder_childname_test.go index f056b6bdaa6c..c5abcd8fe929 100644 --- a/xds/internal/balancer/clusterresolver/configbuilder_childname_test.go +++ b/internal/xds/balancer/clusterresolver/configbuilder_childname_test.go @@ -21,8 +21,8 @@ import ( "testing" "github.com/google/go-cmp/cmp" - "google.golang.org/grpc/xds/internal/clients" - "google.golang.org/grpc/xds/internal/xdsclient/xdsresource" + "google.golang.org/grpc/internal/xds/clients" + "google.golang.org/grpc/internal/xds/xdsclient/xdsresource" ) func Test_nameGenerator_generate(t *testing.T) { diff --git a/xds/internal/balancer/clusterresolver/configbuilder_test.go b/internal/xds/balancer/clusterresolver/configbuilder_test.go similarity index 97% rename from xds/internal/balancer/clusterresolver/configbuilder_test.go rename to internal/xds/balancer/clusterresolver/configbuilder_test.go index 656596f95bbc..571b756484e2 100644 --- a/xds/internal/balancer/clusterresolver/configbuilder_test.go +++ b/internal/xds/balancer/clusterresolver/configbuilder_test.go @@ -35,15 +35,15 @@ import ( "google.golang.org/grpc/internal/hierarchy" iringhash "google.golang.org/grpc/internal/ringhash" iserviceconfig "google.golang.org/grpc/internal/serviceconfig" + xdsinternal "google.golang.org/grpc/internal/xds" + "google.golang.org/grpc/internal/xds/balancer/clusterimpl" + "google.golang.org/grpc/internal/xds/balancer/outlierdetection" + "google.golang.org/grpc/internal/xds/balancer/priority" + "google.golang.org/grpc/internal/xds/balancer/wrrlocality" "google.golang.org/grpc/internal/xds/bootstrap" + "google.golang.org/grpc/internal/xds/clients" + "google.golang.org/grpc/internal/xds/xdsclient/xdsresource" "google.golang.org/grpc/resolver" - "google.golang.org/grpc/xds/internal" - "google.golang.org/grpc/xds/internal/balancer/clusterimpl" - "google.golang.org/grpc/xds/internal/balancer/outlierdetection" - "google.golang.org/grpc/xds/internal/balancer/priority" - "google.golang.org/grpc/xds/internal/balancer/wrrlocality" - "google.golang.org/grpc/xds/internal/clients" - "google.golang.org/grpc/xds/internal/xdsclient/xdsresource" ) const ( @@ -642,8 +642,8 @@ func testEndpointWithAttrs(addrStrs []string, localityWeight, endpointWeight uin } path := []string{priority} if lID != nil { - path = append(path, internal.LocalityString(*lID)) - endpoint = internal.SetLocalityIDInEndpoint(endpoint, *lID) + path = append(path, xdsinternal.LocalityString(*lID)) + endpoint = xdsinternal.SetLocalityIDInEndpoint(endpoint, *lID) } endpoint = hierarchy.SetInEndpoint(endpoint, path) endpoint = wrrlocality.SetAddrInfoInEndpoint(endpoint, wrrlocality.AddrInfo{LocalityWeight: localityWeight}) diff --git a/xds/internal/balancer/clusterresolver/e2e_test/aggregate_cluster_test.go b/internal/xds/balancer/clusterresolver/e2e_test/aggregate_cluster_test.go similarity index 99% rename from xds/internal/balancer/clusterresolver/e2e_test/aggregate_cluster_test.go rename to internal/xds/balancer/clusterresolver/e2e_test/aggregate_cluster_test.go index 36d22abfa132..523b5259eb40 100644 --- a/xds/internal/balancer/clusterresolver/e2e_test/aggregate_cluster_test.go +++ b/internal/xds/balancer/clusterresolver/e2e_test/aggregate_cluster_test.go @@ -37,13 +37,13 @@ import ( "google.golang.org/grpc/internal/testutils/pickfirst" "google.golang.org/grpc/internal/testutils/xds/e2e" "google.golang.org/grpc/internal/xds/bootstrap" + "google.golang.org/grpc/internal/xds/xdsclient" + "google.golang.org/grpc/internal/xds/xdsclient/xdsresource/version" "google.golang.org/grpc/peer" "google.golang.org/grpc/resolver" "google.golang.org/grpc/resolver/manual" "google.golang.org/grpc/serviceconfig" "google.golang.org/grpc/status" - "google.golang.org/grpc/xds/internal/xdsclient" - "google.golang.org/grpc/xds/internal/xdsclient/xdsresource/version" "google.golang.org/protobuf/types/known/wrapperspb" v3clusterpb "github.com/envoyproxy/go-control-plane/envoy/config/cluster/v3" diff --git a/xds/internal/balancer/clusterresolver/e2e_test/balancer_test.go b/internal/xds/balancer/clusterresolver/e2e_test/balancer_test.go similarity index 97% rename from xds/internal/balancer/clusterresolver/e2e_test/balancer_test.go rename to internal/xds/balancer/clusterresolver/e2e_test/balancer_test.go index 8e7f3d1fd8da..50801330ef24 100644 --- a/xds/internal/balancer/clusterresolver/e2e_test/balancer_test.go +++ b/internal/xds/balancer/clusterresolver/e2e_test/balancer_test.go @@ -38,18 +38,18 @@ import ( "google.golang.org/grpc/internal/stubserver" "google.golang.org/grpc/internal/testutils" "google.golang.org/grpc/internal/testutils/xds/e2e" + xdsinternal "google.golang.org/grpc/internal/xds" + "google.golang.org/grpc/internal/xds/balancer/clusterimpl" + "google.golang.org/grpc/internal/xds/balancer/outlierdetection" + "google.golang.org/grpc/internal/xds/balancer/priority" + "google.golang.org/grpc/internal/xds/balancer/wrrlocality" "google.golang.org/grpc/internal/xds/bootstrap" + "google.golang.org/grpc/internal/xds/xdsclient" + "google.golang.org/grpc/internal/xds/xdsclient/xdsresource/version" "google.golang.org/grpc/resolver" "google.golang.org/grpc/resolver/manual" "google.golang.org/grpc/serviceconfig" "google.golang.org/grpc/status" - xdsinternal "google.golang.org/grpc/xds/internal" - "google.golang.org/grpc/xds/internal/balancer/clusterimpl" - "google.golang.org/grpc/xds/internal/balancer/outlierdetection" - "google.golang.org/grpc/xds/internal/balancer/priority" - "google.golang.org/grpc/xds/internal/balancer/wrrlocality" - "google.golang.org/grpc/xds/internal/xdsclient" - "google.golang.org/grpc/xds/internal/xdsclient/xdsresource/version" "google.golang.org/protobuf/types/known/durationpb" "google.golang.org/protobuf/types/known/wrapperspb" @@ -60,7 +60,7 @@ import ( testgrpc "google.golang.org/grpc/interop/grpc_testing" testpb "google.golang.org/grpc/interop/grpc_testing" - _ "google.golang.org/grpc/xds/internal/balancer/cdsbalancer" // Register the "cds_experimental" LB policy. + _ "google.golang.org/grpc/internal/xds/balancer/cdsbalancer" // Register the "cds_experimental" LB policy. ) // setupAndDial performs common setup across all tests diff --git a/xds/internal/balancer/clusterresolver/e2e_test/eds_impl_test.go b/internal/xds/balancer/clusterresolver/e2e_test/eds_impl_test.go similarity index 99% rename from xds/internal/balancer/clusterresolver/e2e_test/eds_impl_test.go rename to internal/xds/balancer/clusterresolver/e2e_test/eds_impl_test.go index dfcb793dd121..477601ecd59c 100644 --- a/xds/internal/balancer/clusterresolver/e2e_test/eds_impl_test.go +++ b/internal/xds/balancer/clusterresolver/e2e_test/eds_impl_test.go @@ -41,13 +41,13 @@ import ( rrutil "google.golang.org/grpc/internal/testutils/roundrobin" "google.golang.org/grpc/internal/testutils/xds/e2e" "google.golang.org/grpc/internal/xds/bootstrap" + "google.golang.org/grpc/internal/xds/xdsclient" + "google.golang.org/grpc/internal/xds/xdsclient/xdsresource/version" "google.golang.org/grpc/peer" "google.golang.org/grpc/resolver" "google.golang.org/grpc/resolver/manual" "google.golang.org/grpc/serviceconfig" "google.golang.org/grpc/status" - "google.golang.org/grpc/xds/internal/xdsclient" - "google.golang.org/grpc/xds/internal/xdsclient/xdsresource/version" "google.golang.org/protobuf/types/known/wrapperspb" v3clusterpb "github.com/envoyproxy/go-control-plane/envoy/config/cluster/v3" @@ -57,8 +57,8 @@ import ( testgrpc "google.golang.org/grpc/interop/grpc_testing" testpb "google.golang.org/grpc/interop/grpc_testing" - _ "google.golang.org/grpc/xds/internal/balancer/clusterresolver" // Register the "cluster_resolver_experimental" LB policy. - "google.golang.org/grpc/xds/internal/balancer/priority" + _ "google.golang.org/grpc/internal/xds/balancer/clusterresolver" // Register the "cluster_resolver_experimental" LB policy. + "google.golang.org/grpc/internal/xds/balancer/priority" ) const ( diff --git a/xds/internal/balancer/clusterresolver/logging.go b/internal/xds/balancer/clusterresolver/logging.go similarity index 100% rename from xds/internal/balancer/clusterresolver/logging.go rename to internal/xds/balancer/clusterresolver/logging.go diff --git a/xds/internal/balancer/clusterresolver/resource_resolver.go b/internal/xds/balancer/clusterresolver/resource_resolver.go similarity index 99% rename from xds/internal/balancer/clusterresolver/resource_resolver.go rename to internal/xds/balancer/clusterresolver/resource_resolver.go index c1a656c59726..90e950c73332 100644 --- a/xds/internal/balancer/clusterresolver/resource_resolver.go +++ b/internal/xds/balancer/clusterresolver/resource_resolver.go @@ -24,8 +24,8 @@ import ( "google.golang.org/grpc/internal/grpclog" "google.golang.org/grpc/internal/grpcsync" + "google.golang.org/grpc/internal/xds/xdsclient/xdsresource" "google.golang.org/grpc/resolver" - "google.golang.org/grpc/xds/internal/xdsclient/xdsresource" ) // resourceUpdate is a combined update from all the resources, in the order of diff --git a/xds/internal/balancer/clusterresolver/resource_resolver_dns.go b/internal/xds/balancer/clusterresolver/resource_resolver_dns.go similarity index 100% rename from xds/internal/balancer/clusterresolver/resource_resolver_dns.go rename to internal/xds/balancer/clusterresolver/resource_resolver_dns.go diff --git a/xds/internal/balancer/clusterresolver/resource_resolver_eds.go b/internal/xds/balancer/clusterresolver/resource_resolver_eds.go similarity index 98% rename from xds/internal/balancer/clusterresolver/resource_resolver_eds.go rename to internal/xds/balancer/clusterresolver/resource_resolver_eds.go index 043def95079d..18b517f111d9 100644 --- a/xds/internal/balancer/clusterresolver/resource_resolver_eds.go +++ b/internal/xds/balancer/clusterresolver/resource_resolver_eds.go @@ -23,7 +23,7 @@ import ( "google.golang.org/grpc/internal/grpclog" "google.golang.org/grpc/internal/grpcsync" - "google.golang.org/grpc/xds/internal/xdsclient/xdsresource" + "google.golang.org/grpc/internal/xds/xdsclient/xdsresource" ) type edsDiscoveryMechanism struct { diff --git a/xds/internal/balancer/loadstore/load_store_wrapper.go b/internal/xds/balancer/loadstore/load_store_wrapper.go similarity index 97% rename from xds/internal/balancer/loadstore/load_store_wrapper.go rename to internal/xds/balancer/loadstore/load_store_wrapper.go index 48a2b7d1ed49..89d5ad8751a1 100644 --- a/xds/internal/balancer/loadstore/load_store_wrapper.go +++ b/internal/xds/balancer/loadstore/load_store_wrapper.go @@ -22,8 +22,8 @@ package loadstore import ( "sync" - "google.golang.org/grpc/xds/internal/clients" - "google.golang.org/grpc/xds/internal/clients/lrsclient" + "google.golang.org/grpc/internal/xds/clients" + "google.golang.org/grpc/internal/xds/clients/lrsclient" ) // NewWrapper creates a Wrapper. diff --git a/xds/internal/balancer/outlierdetection/balancer.go b/internal/xds/balancer/outlierdetection/balancer.go similarity index 100% rename from xds/internal/balancer/outlierdetection/balancer.go rename to internal/xds/balancer/outlierdetection/balancer.go diff --git a/xds/internal/balancer/outlierdetection/balancer_test.go b/internal/xds/balancer/outlierdetection/balancer_test.go similarity index 99% rename from xds/internal/balancer/outlierdetection/balancer_test.go rename to internal/xds/balancer/outlierdetection/balancer_test.go index 25b6a22152f9..be3f03cdc0eb 100644 --- a/xds/internal/balancer/outlierdetection/balancer_test.go +++ b/internal/xds/balancer/outlierdetection/balancer_test.go @@ -46,12 +46,12 @@ import ( "google.golang.org/grpc/internal/stubserver" "google.golang.org/grpc/internal/testutils" "google.golang.org/grpc/internal/testutils/roundrobin" + "google.golang.org/grpc/internal/xds/balancer/clusterimpl" "google.golang.org/grpc/peer" "google.golang.org/grpc/resolver" "google.golang.org/grpc/resolver/manual" "google.golang.org/grpc/serviceconfig" "google.golang.org/grpc/status" - "google.golang.org/grpc/xds/internal/balancer/clusterimpl" testgrpc "google.golang.org/grpc/interop/grpc_testing" testpb "google.golang.org/grpc/interop/grpc_testing" diff --git a/xds/internal/balancer/outlierdetection/callcounter.go b/internal/xds/balancer/outlierdetection/callcounter.go similarity index 100% rename from xds/internal/balancer/outlierdetection/callcounter.go rename to internal/xds/balancer/outlierdetection/callcounter.go diff --git a/xds/internal/balancer/outlierdetection/callcounter_test.go b/internal/xds/balancer/outlierdetection/callcounter_test.go similarity index 100% rename from xds/internal/balancer/outlierdetection/callcounter_test.go rename to internal/xds/balancer/outlierdetection/callcounter_test.go diff --git a/xds/internal/balancer/outlierdetection/config.go b/internal/xds/balancer/outlierdetection/config.go similarity index 100% rename from xds/internal/balancer/outlierdetection/config.go rename to internal/xds/balancer/outlierdetection/config.go diff --git a/xds/internal/balancer/outlierdetection/config_test.go b/internal/xds/balancer/outlierdetection/config_test.go similarity index 100% rename from xds/internal/balancer/outlierdetection/config_test.go rename to internal/xds/balancer/outlierdetection/config_test.go diff --git a/xds/internal/balancer/outlierdetection/e2e_test/outlierdetection_test.go b/internal/xds/balancer/outlierdetection/e2e_test/outlierdetection_test.go similarity index 99% rename from xds/internal/balancer/outlierdetection/e2e_test/outlierdetection_test.go rename to internal/xds/balancer/outlierdetection/e2e_test/outlierdetection_test.go index 161c364d93ee..51a3013df298 100644 --- a/xds/internal/balancer/outlierdetection/e2e_test/outlierdetection_test.go +++ b/internal/xds/balancer/outlierdetection/e2e_test/outlierdetection_test.go @@ -42,7 +42,7 @@ import ( testgrpc "google.golang.org/grpc/interop/grpc_testing" testpb "google.golang.org/grpc/interop/grpc_testing" - _ "google.golang.org/grpc/xds/internal/balancer/outlierdetection" // To register helper functions which register/unregister Outlier Detection LB Policy. + _ "google.golang.org/grpc/internal/xds/balancer/outlierdetection" // To register helper functions which register/unregister Outlier Detection LB Policy. ) var ( diff --git a/xds/internal/balancer/outlierdetection/logging.go b/internal/xds/balancer/outlierdetection/logging.go similarity index 100% rename from xds/internal/balancer/outlierdetection/logging.go rename to internal/xds/balancer/outlierdetection/logging.go diff --git a/xds/internal/balancer/outlierdetection/subconn_wrapper.go b/internal/xds/balancer/outlierdetection/subconn_wrapper.go similarity index 100% rename from xds/internal/balancer/outlierdetection/subconn_wrapper.go rename to internal/xds/balancer/outlierdetection/subconn_wrapper.go diff --git a/xds/internal/balancer/priority/balancer.go b/internal/xds/balancer/priority/balancer.go similarity index 100% rename from xds/internal/balancer/priority/balancer.go rename to internal/xds/balancer/priority/balancer.go diff --git a/xds/internal/balancer/priority/balancer_child.go b/internal/xds/balancer/priority/balancer_child.go similarity index 100% rename from xds/internal/balancer/priority/balancer_child.go rename to internal/xds/balancer/priority/balancer_child.go diff --git a/xds/internal/balancer/priority/balancer_priority.go b/internal/xds/balancer/priority/balancer_priority.go similarity index 100% rename from xds/internal/balancer/priority/balancer_priority.go rename to internal/xds/balancer/priority/balancer_priority.go diff --git a/xds/internal/balancer/priority/balancer_test.go b/internal/xds/balancer/priority/balancer_test.go similarity index 100% rename from xds/internal/balancer/priority/balancer_test.go rename to internal/xds/balancer/priority/balancer_test.go diff --git a/xds/internal/balancer/priority/config.go b/internal/xds/balancer/priority/config.go similarity index 100% rename from xds/internal/balancer/priority/config.go rename to internal/xds/balancer/priority/config.go diff --git a/xds/internal/balancer/priority/config_test.go b/internal/xds/balancer/priority/config_test.go similarity index 100% rename from xds/internal/balancer/priority/config_test.go rename to internal/xds/balancer/priority/config_test.go diff --git a/xds/internal/balancer/priority/ignore_resolve_now.go b/internal/xds/balancer/priority/ignore_resolve_now.go similarity index 77% rename from xds/internal/balancer/priority/ignore_resolve_now.go rename to internal/xds/balancer/priority/ignore_resolve_now.go index 792ee4b3f242..df9ec46c5706 100644 --- a/xds/internal/balancer/priority/ignore_resolve_now.go +++ b/internal/xds/balancer/priority/ignore_resolve_now.go @@ -29,29 +29,21 @@ import ( // ResolveNow() method to ignore those calls if the ignoreResolveNow bit is set. type ignoreResolveNowClientConn struct { balancer.ClientConn - ignoreResolveNow *uint32 + ignoreResolveNow atomic.Bool } func newIgnoreResolveNowClientConn(cc balancer.ClientConn, ignore bool) *ignoreResolveNowClientConn { - ret := &ignoreResolveNowClientConn{ - ClientConn: cc, - ignoreResolveNow: new(uint32), - } + ret := &ignoreResolveNowClientConn{ClientConn: cc} ret.updateIgnoreResolveNow(ignore) return ret } func (i *ignoreResolveNowClientConn) updateIgnoreResolveNow(b bool) { - if b { - atomic.StoreUint32(i.ignoreResolveNow, 1) - return - } - atomic.StoreUint32(i.ignoreResolveNow, 0) - + i.ignoreResolveNow.Store(b) } -func (i ignoreResolveNowClientConn) ResolveNow(o resolver.ResolveNowOptions) { - if atomic.LoadUint32(i.ignoreResolveNow) != 0 { +func (i *ignoreResolveNowClientConn) ResolveNow(o resolver.ResolveNowOptions) { + if i.ignoreResolveNow.Load() { return } i.ClientConn.ResolveNow(o) diff --git a/xds/internal/balancer/priority/ignore_resolve_now_test.go b/internal/xds/balancer/priority/ignore_resolve_now_test.go similarity index 100% rename from xds/internal/balancer/priority/ignore_resolve_now_test.go rename to internal/xds/balancer/priority/ignore_resolve_now_test.go diff --git a/xds/internal/balancer/priority/logging.go b/internal/xds/balancer/priority/logging.go similarity index 100% rename from xds/internal/balancer/priority/logging.go rename to internal/xds/balancer/priority/logging.go diff --git a/xds/internal/balancer/wrrlocality/balancer.go b/internal/xds/balancer/wrrlocality/balancer.go similarity index 98% rename from xds/internal/balancer/wrrlocality/balancer.go rename to internal/xds/balancer/wrrlocality/balancer.go index 0c99c108f769..b11aaa17e550 100644 --- a/xds/internal/balancer/wrrlocality/balancer.go +++ b/internal/xds/balancer/wrrlocality/balancer.go @@ -31,9 +31,9 @@ import ( "google.golang.org/grpc/balancer/weightedtarget" "google.golang.org/grpc/internal/grpclog" internalserviceconfig "google.golang.org/grpc/internal/serviceconfig" + xdsinternal "google.golang.org/grpc/internal/xds" "google.golang.org/grpc/resolver" "google.golang.org/grpc/serviceconfig" - "google.golang.org/grpc/xds/internal" ) // Name is the name of wrr_locality balancer. @@ -171,7 +171,7 @@ func (b *wrrLocalityBalancer) UpdateClientConnState(s balancer.ClientConnState) // shouldn't happen though (this attribute that is set actually gets // used to build localities in the first place), and thus don't error // out, and just build a weighted target with undefined behavior. - locality := internal.LocalityString(internal.GetLocalityID(addr)) + locality := xdsinternal.LocalityString(xdsinternal.GetLocalityID(addr)) ai, ok := getAddrInfo(addr) if !ok { return fmt.Errorf("xds_wrr_locality: missing locality weight information in address %q", addr) diff --git a/xds/internal/balancer/wrrlocality/balancer_test.go b/internal/xds/balancer/wrrlocality/balancer_test.go similarity index 97% rename from xds/internal/balancer/wrrlocality/balancer_test.go rename to internal/xds/balancer/wrrlocality/balancer_test.go index 9c3a499e6540..b006a52b2eaa 100644 --- a/xds/internal/balancer/wrrlocality/balancer_test.go +++ b/internal/xds/balancer/wrrlocality/balancer_test.go @@ -34,10 +34,10 @@ import ( "google.golang.org/grpc/internal/grpctest" internalserviceconfig "google.golang.org/grpc/internal/serviceconfig" "google.golang.org/grpc/internal/testutils" + xdsinternal "google.golang.org/grpc/internal/xds" + "google.golang.org/grpc/internal/xds/clients" "google.golang.org/grpc/resolver" "google.golang.org/grpc/serviceconfig" - "google.golang.org/grpc/xds/internal" - "google.golang.org/grpc/xds/internal/clients" ) const ( @@ -179,7 +179,7 @@ func (s) TestUpdateClientConnState(t *testing.T) { addr1 := resolver.Address{ Addr: "locality-1", } - addr1 = internal.SetLocalityID(addr1, clients.Locality{ + addr1 = xdsinternal.SetLocalityID(addr1, clients.Locality{ Region: "region-1", Zone: "zone-1", SubZone: "subzone-1", @@ -189,7 +189,7 @@ func (s) TestUpdateClientConnState(t *testing.T) { addr2 := resolver.Address{ Addr: "locality-2", } - addr2 = internal.SetLocalityID(addr2, clients.Locality{ + addr2 = xdsinternal.SetLocalityID(addr2, clients.Locality{ Region: "region-2", Zone: "zone-2", SubZone: "subzone-2", diff --git a/xds/internal/balancer/wrrlocality/logging.go b/internal/xds/balancer/wrrlocality/logging.go similarity index 100% rename from xds/internal/balancer/wrrlocality/logging.go rename to internal/xds/balancer/wrrlocality/logging.go diff --git a/xds/internal/clients/config.go b/internal/xds/clients/config.go similarity index 100% rename from xds/internal/clients/config.go rename to internal/xds/clients/config.go diff --git a/xds/internal/clients/grpctransport/examples_test.go b/internal/xds/clients/grpctransport/examples_test.go similarity index 92% rename from xds/internal/clients/grpctransport/examples_test.go rename to internal/xds/clients/grpctransport/examples_test.go index 57191d1fcc36..09f96782d4e2 100644 --- a/xds/internal/clients/grpctransport/examples_test.go +++ b/internal/xds/clients/grpctransport/examples_test.go @@ -21,8 +21,8 @@ package grpctransport_test import ( "fmt" - "google.golang.org/grpc/xds/internal/clients" - "google.golang.org/grpc/xds/internal/clients/grpctransport" + "google.golang.org/grpc/internal/xds/clients" + "google.golang.org/grpc/internal/xds/clients/grpctransport" ) // ExampleServerIdentifierExtension demonstrates how to create diff --git a/xds/internal/clients/grpctransport/grpc_transport.go b/internal/xds/clients/grpctransport/grpc_transport.go similarity index 99% rename from xds/internal/clients/grpctransport/grpc_transport.go rename to internal/xds/clients/grpctransport/grpc_transport.go index 2659c301e5bf..841029dc2eee 100644 --- a/xds/internal/clients/grpctransport/grpc_transport.go +++ b/internal/xds/clients/grpctransport/grpc_transport.go @@ -29,8 +29,8 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/credentials" "google.golang.org/grpc/grpclog" + "google.golang.org/grpc/internal/xds/clients" "google.golang.org/grpc/keepalive" - "google.golang.org/grpc/xds/internal/clients" ) var ( diff --git a/xds/internal/clients/grpctransport/grpc_transport_ext_test.go b/internal/xds/clients/grpctransport/grpc_transport_ext_test.go similarity index 98% rename from xds/internal/clients/grpctransport/grpc_transport_ext_test.go rename to internal/xds/clients/grpctransport/grpc_transport_ext_test.go index 75ac5146223d..5c3050f8d0fe 100644 --- a/xds/internal/clients/grpctransport/grpc_transport_ext_test.go +++ b/internal/xds/clients/grpctransport/grpc_transport_ext_test.go @@ -28,10 +28,10 @@ import ( "google.golang.org/grpc/credentials/insecure" "google.golang.org/grpc/credentials/local" "google.golang.org/grpc/internal/grpctest" - "google.golang.org/grpc/xds/internal/clients" - "google.golang.org/grpc/xds/internal/clients/grpctransport" - "google.golang.org/grpc/xds/internal/clients/internal/testutils" - "google.golang.org/grpc/xds/internal/clients/internal/testutils/e2e" + "google.golang.org/grpc/internal/xds/clients" + "google.golang.org/grpc/internal/xds/clients/grpctransport" + "google.golang.org/grpc/internal/xds/clients/internal/testutils" + "google.golang.org/grpc/internal/xds/clients/internal/testutils/e2e" ) const ( diff --git a/xds/internal/clients/grpctransport/grpc_transport_test.go b/internal/xds/clients/grpctransport/grpc_transport_test.go similarity index 99% rename from xds/internal/clients/grpctransport/grpc_transport_test.go rename to internal/xds/clients/grpctransport/grpc_transport_test.go index 23e752577b41..e33e889efa03 100644 --- a/xds/internal/clients/grpctransport/grpc_transport_test.go +++ b/internal/xds/clients/grpctransport/grpc_transport_test.go @@ -31,7 +31,7 @@ import ( "google.golang.org/grpc/credentials/insecure" "google.golang.org/grpc/credentials/local" "google.golang.org/grpc/internal/grpctest" - "google.golang.org/grpc/xds/internal/clients" + "google.golang.org/grpc/internal/xds/clients" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/testing/protocmp" diff --git a/xds/internal/clients/internal/backoff/backoff.go b/internal/xds/clients/internal/backoff/backoff.go similarity index 100% rename from xds/internal/clients/internal/backoff/backoff.go rename to internal/xds/clients/internal/backoff/backoff.go diff --git a/xds/internal/clients/internal/buffer/unbounded.go b/internal/xds/clients/internal/buffer/unbounded.go similarity index 100% rename from xds/internal/clients/internal/buffer/unbounded.go rename to internal/xds/clients/internal/buffer/unbounded.go diff --git a/xds/internal/clients/internal/buffer/unbounded_test.go b/internal/xds/clients/internal/buffer/unbounded_test.go similarity index 100% rename from xds/internal/clients/internal/buffer/unbounded_test.go rename to internal/xds/clients/internal/buffer/unbounded_test.go diff --git a/xds/internal/clients/internal/internal.go b/internal/xds/clients/internal/internal.go similarity index 97% rename from xds/internal/clients/internal/internal.go rename to internal/xds/clients/internal/internal.go index 371b4d19d691..60cf82b2e443 100644 --- a/xds/internal/clients/internal/internal.go +++ b/internal/xds/clients/internal/internal.go @@ -20,7 +20,7 @@ package internal import ( - "google.golang.org/grpc/xds/internal/clients" + "google.golang.org/grpc/internal/xds/clients" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/types/known/structpb" diff --git a/xds/internal/clients/internal/internal_test.go b/internal/xds/clients/internal/internal_test.go similarity index 99% rename from xds/internal/clients/internal/internal_test.go rename to internal/xds/clients/internal/internal_test.go index 5b7889b7e217..99deb5c2cca0 100644 --- a/xds/internal/clients/internal/internal_test.go +++ b/internal/xds/clients/internal/internal_test.go @@ -23,7 +23,7 @@ import ( "github.com/google/go-cmp/cmp" "google.golang.org/grpc/internal/grpctest" - "google.golang.org/grpc/xds/internal/clients" + "google.golang.org/grpc/internal/xds/clients" "google.golang.org/protobuf/testing/protocmp" "google.golang.org/protobuf/types/known/structpb" diff --git a/xds/internal/clients/internal/pretty/pretty.go b/internal/xds/clients/internal/pretty/pretty.go similarity index 100% rename from xds/internal/clients/internal/pretty/pretty.go rename to internal/xds/clients/internal/pretty/pretty.go diff --git a/xds/internal/clients/internal/syncutil/callback_serializer.go b/internal/xds/clients/internal/syncutil/callback_serializer.go similarity index 84% rename from xds/internal/clients/internal/syncutil/callback_serializer.go rename to internal/xds/clients/internal/syncutil/callback_serializer.go index 9ad1be517c94..baab133f2443 100644 --- a/xds/internal/clients/internal/syncutil/callback_serializer.go +++ b/internal/xds/clients/internal/syncutil/callback_serializer.go @@ -21,7 +21,7 @@ package syncutil import ( "context" - "google.golang.org/grpc/xds/internal/clients/internal/buffer" + "google.golang.org/grpc/internal/xds/clients/internal/buffer" ) // CallbackSerializer provides a mechanism to schedule callbacks in a @@ -80,25 +80,11 @@ func (cs *CallbackSerializer) ScheduleOr(f func(ctx context.Context), onFailure func (cs *CallbackSerializer) run(ctx context.Context) { defer close(cs.done) - // TODO: when Go 1.21 is the oldest supported version, this loop and Close - // can be replaced with: - // - // context.AfterFunc(ctx, cs.callbacks.Close) - for ctx.Err() == nil { - select { - case <-ctx.Done(): - // Do nothing here. Next iteration of the for loop will not happen, - // since ctx.Err() would be non-nil. - case cb := <-cs.callbacks.Get(): - cs.callbacks.Load() - cb.(func(context.Context))(ctx) - } - } - - // Close the buffer to prevent new callbacks from being added. - cs.callbacks.Close() + // Close the buffer when the context is canceled + // to prevent new callbacks from being added. + context.AfterFunc(ctx, cs.callbacks.Close) - // Run all pending callbacks. + // Run all callbacks. for cb := range cs.callbacks.Get() { cs.callbacks.Load() cb.(func(context.Context))(ctx) diff --git a/xds/internal/clients/internal/syncutil/callback_serializer_test.go b/internal/xds/clients/internal/syncutil/callback_serializer_test.go similarity index 100% rename from xds/internal/clients/internal/syncutil/callback_serializer_test.go rename to internal/xds/clients/internal/syncutil/callback_serializer_test.go diff --git a/xds/internal/clients/internal/syncutil/event.go b/internal/xds/clients/internal/syncutil/event.go similarity index 100% rename from xds/internal/clients/internal/syncutil/event.go rename to internal/xds/clients/internal/syncutil/event.go diff --git a/xds/internal/clients/internal/syncutil/event_test.go b/internal/xds/clients/internal/syncutil/event_test.go similarity index 100% rename from xds/internal/clients/internal/syncutil/event_test.go rename to internal/xds/clients/internal/syncutil/event_test.go diff --git a/xds/internal/clients/internal/testutils/channel.go b/internal/xds/clients/internal/testutils/channel.go similarity index 100% rename from xds/internal/clients/internal/testutils/channel.go rename to internal/xds/clients/internal/testutils/channel.go diff --git a/xds/internal/clients/internal/testutils/e2e/clientresources.go b/internal/xds/clients/internal/testutils/e2e/clientresources.go similarity index 100% rename from xds/internal/clients/internal/testutils/e2e/clientresources.go rename to internal/xds/clients/internal/testutils/e2e/clientresources.go diff --git a/xds/internal/clients/internal/testutils/e2e/logging.go b/internal/xds/clients/internal/testutils/e2e/logging.go similarity index 100% rename from xds/internal/clients/internal/testutils/e2e/logging.go rename to internal/xds/clients/internal/testutils/e2e/logging.go diff --git a/xds/internal/clients/internal/testutils/e2e/server.go b/internal/xds/clients/internal/testutils/e2e/server.go similarity index 99% rename from xds/internal/clients/internal/testutils/e2e/server.go rename to internal/xds/clients/internal/testutils/e2e/server.go index f2903f53b946..3426bbc84867 100644 --- a/xds/internal/clients/internal/testutils/e2e/server.go +++ b/internal/xds/clients/internal/testutils/e2e/server.go @@ -30,7 +30,7 @@ import ( "github.com/envoyproxy/go-control-plane/pkg/cache/types" "google.golang.org/grpc" - "google.golang.org/grpc/xds/internal/clients/internal/testutils/fakeserver" + "google.golang.org/grpc/internal/xds/clients/internal/testutils/fakeserver" v3clusterpb "github.com/envoyproxy/go-control-plane/envoy/config/cluster/v3" v3corepb "github.com/envoyproxy/go-control-plane/envoy/config/core/v3" diff --git a/xds/internal/clients/internal/testutils/fakeserver/server.go b/internal/xds/clients/internal/testutils/fakeserver/server.go similarity index 99% rename from xds/internal/clients/internal/testutils/fakeserver/server.go rename to internal/xds/clients/internal/testutils/fakeserver/server.go index 6aa66a897b6e..8adb2e866dbe 100644 --- a/xds/internal/clients/internal/testutils/fakeserver/server.go +++ b/internal/xds/clients/internal/testutils/fakeserver/server.go @@ -31,8 +31,8 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/codes" + "google.golang.org/grpc/internal/xds/clients/internal/testutils" "google.golang.org/grpc/status" - "google.golang.org/grpc/xds/internal/clients/internal/testutils" "google.golang.org/protobuf/proto" v3discoverygrpc "github.com/envoyproxy/go-control-plane/envoy/service/discovery/v3" diff --git a/xds/internal/clients/internal/testutils/marshal_any.go b/internal/xds/clients/internal/testutils/marshal_any.go similarity index 100% rename from xds/internal/clients/internal/testutils/marshal_any.go rename to internal/xds/clients/internal/testutils/marshal_any.go diff --git a/xds/internal/clients/internal/testutils/restartable_listener.go b/internal/xds/clients/internal/testutils/restartable_listener.go similarity index 100% rename from xds/internal/clients/internal/testutils/restartable_listener.go rename to internal/xds/clients/internal/testutils/restartable_listener.go diff --git a/xds/internal/clients/internal/testutils/wrappers.go b/internal/xds/clients/internal/testutils/wrappers.go similarity index 100% rename from xds/internal/clients/internal/testutils/wrappers.go rename to internal/xds/clients/internal/testutils/wrappers.go diff --git a/xds/internal/clients/lrsclient/internal/internal.go b/internal/xds/clients/lrsclient/internal/internal.go similarity index 100% rename from xds/internal/clients/lrsclient/internal/internal.go rename to internal/xds/clients/lrsclient/internal/internal.go diff --git a/xds/internal/clients/lrsclient/load_store.go b/internal/xds/clients/lrsclient/load_store.go similarity index 99% rename from xds/internal/clients/lrsclient/load_store.go rename to internal/xds/clients/lrsclient/load_store.go index 6b35fd979aab..fcc6247ed784 100644 --- a/xds/internal/clients/lrsclient/load_store.go +++ b/internal/xds/clients/lrsclient/load_store.go @@ -24,8 +24,8 @@ import ( "sync/atomic" "time" - "google.golang.org/grpc/xds/internal/clients" - lrsclientinternal "google.golang.org/grpc/xds/internal/clients/lrsclient/internal" + "google.golang.org/grpc/internal/xds/clients" + lrsclientinternal "google.golang.org/grpc/internal/xds/clients/lrsclient/internal" ) // A LoadStore aggregates loads for multiple clusters and services that are diff --git a/xds/internal/clients/lrsclient/load_store_test.go b/internal/xds/clients/lrsclient/load_store_test.go similarity index 99% rename from xds/internal/clients/lrsclient/load_store_test.go rename to internal/xds/clients/lrsclient/load_store_test.go index ecbc2ccf5dd0..abe1bc48b5b2 100644 --- a/xds/internal/clients/lrsclient/load_store_test.go +++ b/internal/xds/clients/lrsclient/load_store_test.go @@ -26,8 +26,8 @@ import ( "github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp/cmpopts" - "google.golang.org/grpc/xds/internal/clients" - lrsclientinternal "google.golang.org/grpc/xds/internal/clients/lrsclient/internal" + "google.golang.org/grpc/internal/xds/clients" + lrsclientinternal "google.golang.org/grpc/internal/xds/clients/lrsclient/internal" ) var ( diff --git a/xds/internal/clients/lrsclient/loadreport_test.go b/internal/xds/clients/lrsclient/loadreport_test.go similarity index 98% rename from xds/internal/clients/lrsclient/loadreport_test.go rename to internal/xds/clients/lrsclient/loadreport_test.go index cdddb39f98ed..b4d489ef8d70 100644 --- a/xds/internal/clients/lrsclient/loadreport_test.go +++ b/internal/xds/clients/lrsclient/loadreport_test.go @@ -30,14 +30,14 @@ import ( "google.golang.org/grpc/codes" "google.golang.org/grpc/credentials/insecure" "google.golang.org/grpc/internal/grpctest" + "google.golang.org/grpc/internal/xds/clients" + "google.golang.org/grpc/internal/xds/clients/grpctransport" + "google.golang.org/grpc/internal/xds/clients/internal/testutils" + "google.golang.org/grpc/internal/xds/clients/internal/testutils/e2e" + "google.golang.org/grpc/internal/xds/clients/internal/testutils/fakeserver" + "google.golang.org/grpc/internal/xds/clients/lrsclient" + lrsclientinternal "google.golang.org/grpc/internal/xds/clients/lrsclient/internal" "google.golang.org/grpc/status" - "google.golang.org/grpc/xds/internal/clients" - "google.golang.org/grpc/xds/internal/clients/grpctransport" - "google.golang.org/grpc/xds/internal/clients/internal/testutils" - "google.golang.org/grpc/xds/internal/clients/internal/testutils/e2e" - "google.golang.org/grpc/xds/internal/clients/internal/testutils/fakeserver" - "google.golang.org/grpc/xds/internal/clients/lrsclient" - lrsclientinternal "google.golang.org/grpc/xds/internal/clients/lrsclient/internal" "google.golang.org/protobuf/testing/protocmp" "google.golang.org/protobuf/types/known/durationpb" diff --git a/xds/internal/clients/lrsclient/logging.go b/internal/xds/clients/lrsclient/logging.go similarity index 100% rename from xds/internal/clients/lrsclient/logging.go rename to internal/xds/clients/lrsclient/logging.go diff --git a/xds/internal/clients/lrsclient/lrs_stream.go b/internal/xds/clients/lrsclient/lrs_stream.go similarity index 99% rename from xds/internal/clients/lrsclient/lrs_stream.go rename to internal/xds/clients/lrsclient/lrs_stream.go index bb275bdb468e..9a95983b0f69 100644 --- a/xds/internal/clients/lrsclient/lrs_stream.go +++ b/internal/xds/clients/lrsclient/lrs_stream.go @@ -27,7 +27,7 @@ import ( "google.golang.org/grpc/internal/backoff" igrpclog "google.golang.org/grpc/internal/grpclog" "google.golang.org/grpc/internal/pretty" - "google.golang.org/grpc/xds/internal/clients" + "google.golang.org/grpc/internal/xds/clients" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/types/known/durationpb" diff --git a/xds/internal/clients/lrsclient/lrsclient.go b/internal/xds/clients/lrsclient/lrsclient.go similarity index 94% rename from xds/internal/clients/lrsclient/lrsclient.go rename to internal/xds/clients/lrsclient/lrsclient.go index af163e22019c..3e4594957619 100644 --- a/xds/internal/clients/lrsclient/lrsclient.go +++ b/internal/xds/clients/lrsclient/lrsclient.go @@ -30,9 +30,9 @@ import ( "google.golang.org/grpc/grpclog" igrpclog "google.golang.org/grpc/internal/grpclog" - "google.golang.org/grpc/xds/internal/clients" - clientsinternal "google.golang.org/grpc/xds/internal/clients/internal" - "google.golang.org/grpc/xds/internal/clients/internal/backoff" + "google.golang.org/grpc/internal/xds/clients" + clientsinternal "google.golang.org/grpc/internal/xds/clients/internal" + "google.golang.org/grpc/internal/xds/clients/internal/backoff" ) const ( @@ -61,10 +61,7 @@ type LRSClient struct { // New returns a new LRS Client configured with the provided config. func New(config Config) (*LRSClient, error) { - switch { - case config.Node.ID == "": - return nil, errors.New("lrsclient: node ID in node is empty") - case config.TransportBuilder == nil: + if config.TransportBuilder == nil { return nil, errors.New("lrsclient: transport builder is nil") } diff --git a/xds/internal/clients/lrsclient/lrsconfig.go b/internal/xds/clients/lrsclient/lrsconfig.go similarity index 95% rename from xds/internal/clients/lrsclient/lrsconfig.go rename to internal/xds/clients/lrsclient/lrsconfig.go index c4862ff76794..6dde1b46bf9d 100644 --- a/xds/internal/clients/lrsclient/lrsconfig.go +++ b/internal/xds/clients/lrsclient/lrsconfig.go @@ -19,7 +19,7 @@ package lrsclient import ( - "google.golang.org/grpc/xds/internal/clients" + "google.golang.org/grpc/internal/xds/clients" ) // Config is used to configure an LRS client. After one has been passed to the diff --git a/xds/internal/clients/transport_builder.go b/internal/xds/clients/transport_builder.go similarity index 100% rename from xds/internal/clients/transport_builder.go rename to internal/xds/clients/transport_builder.go diff --git a/xds/internal/clients/xdsclient/ads_stream.go b/internal/xds/clients/xdsclient/ads_stream.go similarity index 97% rename from xds/internal/clients/xdsclient/ads_stream.go rename to internal/xds/clients/xdsclient/ads_stream.go index 9f5e99ac2d85..83f8a5df03f1 100644 --- a/xds/internal/clients/xdsclient/ads_stream.go +++ b/internal/xds/clients/xdsclient/ads_stream.go @@ -27,11 +27,11 @@ import ( "google.golang.org/grpc/grpclog" igrpclog "google.golang.org/grpc/internal/grpclog" - "google.golang.org/grpc/xds/internal/clients" - "google.golang.org/grpc/xds/internal/clients/internal/backoff" - "google.golang.org/grpc/xds/internal/clients/internal/buffer" - "google.golang.org/grpc/xds/internal/clients/internal/pretty" - "google.golang.org/grpc/xds/internal/clients/xdsclient/internal/xdsresource" + "google.golang.org/grpc/internal/xds/clients" + "google.golang.org/grpc/internal/xds/clients/internal/backoff" + "google.golang.org/grpc/internal/xds/clients/internal/buffer" + "google.golang.org/grpc/internal/xds/clients/internal/pretty" + "google.golang.org/grpc/internal/xds/clients/xdsclient/internal/xdsresource" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/types/known/anypb" @@ -71,7 +71,6 @@ type adsStreamEventHandler interface { onStreamError(error) // Called when the ADS stream breaks. onWatchExpiry(ResourceType, string) // Called when the watch timer expires for a resource. onResponse(response, func()) ([]string, error) // Called when a response is received on the ADS stream. - onRequest(typeURL string) // Called when a request is about to be sent on the ADS stream. } // state corresponding to a resource type. @@ -445,11 +444,6 @@ func (s *adsStreamImpl) sendMessageLocked(stream clients.Stream, names []string, } } - // Call the event handler to remove unsubscribed cache entries. It is to - // ensure the cache entries are deleted even if discovery request fails. In - // case of failure when the stream restarts, nonce is reset anyways. - s.eventHandler.onRequest(url) - msg, err := proto.Marshal(req) if err != nil { s.logger.Warningf("Failed to marshal DiscoveryRequest: %v", err) diff --git a/xds/internal/clients/xdsclient/authority.go b/internal/xds/clients/xdsclient/authority.go similarity index 93% rename from xds/internal/clients/xdsclient/authority.go rename to internal/xds/clients/xdsclient/authority.go index f50e0ba5f1db..49a4480cf154 100644 --- a/xds/internal/clients/xdsclient/authority.go +++ b/internal/xds/clients/xdsclient/authority.go @@ -20,16 +20,17 @@ package xdsclient import ( "context" + "errors" "fmt" "sync" "sync/atomic" "google.golang.org/grpc/grpclog" igrpclog "google.golang.org/grpc/internal/grpclog" - "google.golang.org/grpc/xds/internal/clients" - "google.golang.org/grpc/xds/internal/clients/internal/syncutil" - "google.golang.org/grpc/xds/internal/clients/xdsclient/internal/xdsresource" - "google.golang.org/grpc/xds/internal/clients/xdsclient/metrics" + "google.golang.org/grpc/internal/xds/clients" + "google.golang.org/grpc/internal/xds/clients/internal/syncutil" + "google.golang.org/grpc/internal/xds/clients/xdsclient/internal/xdsresource" + "google.golang.org/grpc/internal/xds/clients/xdsclient/metrics" "google.golang.org/protobuf/types/known/anypb" "google.golang.org/protobuf/types/known/timestamppb" @@ -293,9 +294,6 @@ func (a *authority) fallbackToServer(xc *xdsChannelWithConfig) bool { // Subscribe to all existing resources from the new management server. for typ, resources := range a.resources { for name, state := range resources { - if len(state.watchers) == 0 { - continue - } if a.logger.V(2) { a.logger.Infof("Resubscribing to resource of type %q and name %q", typ.TypeName, name) } @@ -685,17 +683,6 @@ func (a *authority) watchResource(rType ResourceType, resourceName string, watch } resources[resourceName] = state xdsChannel.channel.subscribe(rType, resourceName) - } else if len(state.watchers) == 0 { - if a.logger.V(2) { - a.logger.Infof("Re-watch for type %q, resource name %q before unsubscription", rType.TypeName, resourceName) - } - // Add the active channel to the resource's channel configs if not - // already present. - state.xdsChannelConfigs[xdsChannel] = true - // Ensure the resource is subscribed on the active channel. We do this - // even if resource is present in cache as re-watches might occur - // after unsubscribes or channel changes. - xdsChannel.channel.subscribe(rType, resourceName) } // Always add the new watcher to the set of watchers. state.watchers[watcher] = true @@ -773,16 +760,32 @@ func (a *authority) unwatchResource(rType ResourceType, resourceName string, wat } // There are no more watchers for this resource. Unsubscribe this - // resource from all channels where it was subscribed to but do not - // delete the state associated with it in case the resource is - // re-requested later before un-subscription request is completed by - // the management server. + // resource from all channels where it was subscribed to and delete + // the state associated with it. if a.logger.V(2) { a.logger.Infof("Removing last watch for resource name %q", resourceName) } for xcc := range state.xdsChannelConfigs { xcc.channel.unsubscribe(rType, resourceName) } + delete(resources, resourceName) + + // If there are no more watchers for this resource type, delete the + // resource type from the top-level map. + if len(resources) == 0 { + if a.logger.V(2) { + a.logger.Infof("Removing last watch for resource type %q", rType.TypeName) + } + delete(a.resources, rType) + } + // If there are no more watchers for any resource type, release the + // reference to the xdsChannels. + if len(a.resources) == 0 { + if a.logger.V(2) { + a.logger.Infof("Removing last watch for for any resource type, releasing reference to the xdsChannel") + } + a.closeXDSChannels() + } }, func() { close(done) }) <-done }) @@ -834,7 +837,7 @@ func (a *authority) closeXDSChannels() { func (a *authority) watcherExistsForUncachedResource() bool { for _, resourceStates := range a.resources { for _, state := range resourceStates { - if len(state.watchers) > 0 && state.md.Status == xdsresource.ServiceStatusRequested { + if state.md.Status == xdsresource.ServiceStatusRequested { return true } } @@ -866,9 +869,6 @@ func (a *authority) resourceConfig() []*v3statuspb.ClientConfig_GenericXdsConfig for rType, resourceStates := range a.resources { typeURL := rType.TypeURL for name, state := range resourceStates { - if len(state.watchers) == 0 { - continue - } var raw *anypb.Any if state.cache != nil { raw = &anypb.Any{TypeUrl: typeURL, Value: state.cache.Bytes()} @@ -902,43 +902,6 @@ func (a *authority) close() { } } -// removeUnsubscribedCacheEntries iterates through all resources of the given type and -// removes the state for resources that have no active watchers. This is called -// after sending a discovery request to ensure that resources that were -// unsubscribed (and thus have no watchers) are eventually removed from the -// authority's cache. -// -// This method is only executed in the context of a serializer callback. -func (a *authority) removeUnsubscribedCacheEntries(rType ResourceType) { - resources := a.resources[rType] - if resources == nil { - return - } - - for name, state := range resources { - if len(state.watchers) == 0 { - if a.logger.V(2) { - a.logger.Infof("Removing resource state for %q of type %q as it has no watchers", name, rType.TypeName) - } - delete(resources, name) - } - } - - if len(resources) == 0 { - if a.logger.V(2) { - a.logger.Infof("Removing resource type %q from cache as it has no more resources", rType.TypeName) - } - delete(a.resources, rType) - } - - if len(a.resources) == 0 { - if a.logger.V(2) { - a.logger.Infof("Removing last watch for any resource type, releasing reference to the xdsChannels") - } - a.closeXDSChannels() - } -} - func serviceStatusToProto(serviceStatus xdsresource.ServiceStatus) v3adminpb.ClientResourceStatus { switch serviceStatus { case xdsresource.ServiceStatusUnknown: @@ -955,3 +918,17 @@ func serviceStatusToProto(serviceStatus xdsresource.ServiceStatus) v3adminpb.Cli return v3adminpb.ClientResourceStatus_UNKNOWN } } + +func (a *authority) resourceWatchStateForTesting(rType ResourceType, resourceName string) (state xdsresource.ResourceWatchState, err error) { + done := make(chan struct{}) + a.xdsClientSerializer.ScheduleOr(func(context.Context) { + state, err = a.activeXDSChannel.channel.ads.adsResourceWatchStateForTesting(rType, resourceName) + close(done) + }, func() { + err = errors.New("failed to retrieve resource watch state because the xDS client is closed") + close(done) + }) + <-done + + return state, err +} diff --git a/xds/internal/clients/xdsclient/channel.go b/internal/xds/clients/xdsclient/channel.go similarity index 86% rename from xds/internal/clients/xdsclient/channel.go rename to internal/xds/clients/xdsclient/channel.go index 3d65ce6b4eab..e36e362201d6 100644 --- a/xds/internal/clients/xdsclient/channel.go +++ b/internal/xds/clients/xdsclient/channel.go @@ -26,11 +26,11 @@ import ( "google.golang.org/grpc/grpclog" igrpclog "google.golang.org/grpc/internal/grpclog" - "google.golang.org/grpc/xds/internal/clients" - "google.golang.org/grpc/xds/internal/clients/internal" - "google.golang.org/grpc/xds/internal/clients/internal/backoff" - "google.golang.org/grpc/xds/internal/clients/internal/syncutil" - "google.golang.org/grpc/xds/internal/clients/xdsclient/internal/xdsresource" + "google.golang.org/grpc/internal/xds/clients" + "google.golang.org/grpc/internal/xds/clients/internal" + "google.golang.org/grpc/internal/xds/clients/internal/backoff" + "google.golang.org/grpc/internal/xds/clients/internal/syncutil" + "google.golang.org/grpc/internal/xds/clients/xdsclient/internal/xdsresource" ) const ( @@ -59,10 +59,6 @@ type xdsChannelEventHandler interface { // adsResourceDoesNotExist is called when the xdsChannel determines that a // requested ADS resource does not exist. adsResourceDoesNotExist(ResourceType, string) - - // adsResourceRemoveUnsubscribedCacheEntries is called when the xdsChannel - // needs to remove unsubscribed cache entries. - adsResourceRemoveUnsubscribedCacheEntries(ResourceType) } // xdsChannelOpts holds the options for creating a new xdsChannel. @@ -140,32 +136,8 @@ type xdsChannel struct { } func (xc *xdsChannel) close() { - if xc.closed.HasFired() { - return - } xc.closed.Fire() - - // Get the resource types that this specific ADS stream was handling - // before stopping it. - // - // TODO: Revisit if we can avoid acquiring the lock of ads (another type). - xc.ads.mu.Lock() - typesHandledByStream := make([]ResourceType, 0, len(xc.ads.resourceTypeState)) - for typ := range xc.ads.resourceTypeState { - typesHandledByStream = append(typesHandledByStream, typ) - } - xc.ads.mu.Unlock() - xc.ads.Stop() - - // Schedule removeUnsubscribedCacheEntries for the types this stream was handling, - // on all authorities that were interested in this channel. - if _, ok := xc.eventHandler.(*channelState); ok { - for _, typ := range typesHandledByStream { - xc.eventHandler.adsResourceRemoveUnsubscribedCacheEntries(typ) - } - } - xc.transport.Close() xc.logger.Infof("Shutdown") } @@ -256,26 +228,6 @@ func (xc *xdsChannel) onResponse(resp response, onDone func()) ([]string, error) return names, err } -// onRequest invoked when a request is about to be sent on the ADS stream. It -// removes the cache entries for the resource type that are no longer subscribed to. -func (xc *xdsChannel) onRequest(typeURL string) { - if xc.closed.HasFired() { - if xc.logger.V(2) { - xc.logger.Infof("Received an update from the ADS stream on closed ADS stream") - } - return - } - - // Lookup the resource parser based on the resource type. - rType, ok := xc.clientConfig.ResourceTypes[typeURL] - if !ok { - logger.Warningf("Resource type URL %q unknown in response from server", typeURL) - return - } - - xc.eventHandler.adsResourceRemoveUnsubscribedCacheEntries(rType) -} - // decodeResponse decodes the resources in the given ADS response. // // The opts parameter provides configuration options for decoding the resources. diff --git a/xds/internal/clients/xdsclient/channel_test.go b/internal/xds/clients/xdsclient/channel_test.go similarity index 98% rename from xds/internal/clients/xdsclient/channel_test.go rename to internal/xds/clients/xdsclient/channel_test.go index 50f52c173d47..153e7e824fce 100644 --- a/xds/internal/clients/xdsclient/channel_test.go +++ b/internal/xds/clients/xdsclient/channel_test.go @@ -30,12 +30,12 @@ import ( "github.com/google/go-cmp/cmp/cmpopts" "github.com/google/uuid" "google.golang.org/grpc/credentials/insecure" - "google.golang.org/grpc/xds/internal/clients" - "google.golang.org/grpc/xds/internal/clients/grpctransport" - "google.golang.org/grpc/xds/internal/clients/internal/testutils" - "google.golang.org/grpc/xds/internal/clients/internal/testutils/e2e" - "google.golang.org/grpc/xds/internal/clients/internal/testutils/fakeserver" - "google.golang.org/grpc/xds/internal/clients/xdsclient/internal/xdsresource" + "google.golang.org/grpc/internal/xds/clients" + "google.golang.org/grpc/internal/xds/clients/grpctransport" + "google.golang.org/grpc/internal/xds/clients/internal/testutils" + "google.golang.org/grpc/internal/xds/clients/internal/testutils/e2e" + "google.golang.org/grpc/internal/xds/clients/internal/testutils/fakeserver" + "google.golang.org/grpc/internal/xds/clients/xdsclient/internal/xdsresource" "google.golang.org/protobuf/testing/protocmp" "google.golang.org/protobuf/types/known/anypb" @@ -772,6 +772,3 @@ func (ta *testEventHandler) waitForResourceDoesNotExist(ctx context.Context) (Re } return typ, name, nil } - -func (*testEventHandler) adsResourceRemoveUnsubscribedCacheEntries(ResourceType) { -} diff --git a/xds/internal/clients/xdsclient/clientimpl_watchers.go b/internal/xds/clients/xdsclient/clientimpl_watchers.go similarity index 98% rename from xds/internal/clients/xdsclient/clientimpl_watchers.go rename to internal/xds/clients/xdsclient/clientimpl_watchers.go index 913e313e1e24..68b29295ce28 100644 --- a/xds/internal/clients/xdsclient/clientimpl_watchers.go +++ b/internal/xds/clients/xdsclient/clientimpl_watchers.go @@ -21,7 +21,7 @@ package xdsclient import ( "fmt" - "google.golang.org/grpc/xds/internal/clients/xdsclient/internal/xdsresource" + "google.golang.org/grpc/internal/xds/clients/xdsclient/internal/xdsresource" ) // wrappingWatcher is a wrapper around an xdsresource.ResourceWatcher that adds diff --git a/xds/internal/clients/xdsclient/helpers_test.go b/internal/xds/clients/xdsclient/helpers_test.go similarity index 98% rename from xds/internal/clients/xdsclient/helpers_test.go rename to internal/xds/clients/xdsclient/helpers_test.go index efa025efb3e6..6f5f8597881d 100644 --- a/xds/internal/clients/xdsclient/helpers_test.go +++ b/internal/xds/clients/xdsclient/helpers_test.go @@ -27,8 +27,8 @@ import ( "time" "google.golang.org/grpc/internal/grpctest" - "google.golang.org/grpc/xds/internal/clients/internal/pretty" - "google.golang.org/grpc/xds/internal/clients/xdsclient/internal/xdsresource" + "google.golang.org/grpc/internal/xds/clients/internal/pretty" + "google.golang.org/grpc/internal/xds/clients/xdsclient/internal/xdsresource" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/types/known/anypb" diff --git a/xds/internal/clients/xdsclient/internal/internal.go b/internal/xds/clients/xdsclient/internal/internal.go similarity index 86% rename from xds/internal/clients/xdsclient/internal/internal.go rename to internal/xds/clients/xdsclient/internal/internal.go index 7adb67190939..38d2473e5c6c 100644 --- a/xds/internal/clients/xdsclient/internal/internal.go +++ b/internal/xds/clients/xdsclient/internal/internal.go @@ -21,10 +21,6 @@ package internal import "time" var ( - // WatchExpiryTimeout is the watch expiry timeout for xDS client. It can be - // overridden by tests to change the default watch expiry timeout. - WatchExpiryTimeout time.Duration - // StreamBackoff is the stream backoff for xDS client. It can be overridden // by tests to change the default backoff strategy. StreamBackoff func(int) time.Duration diff --git a/xds/internal/clients/xdsclient/internal/xdsresource/ads_stream.go b/internal/xds/clients/xdsclient/internal/xdsresource/ads_stream.go similarity index 100% rename from xds/internal/clients/xdsclient/internal/xdsresource/ads_stream.go rename to internal/xds/clients/xdsclient/internal/xdsresource/ads_stream.go diff --git a/xds/internal/clients/xdsclient/internal/xdsresource/errors.go b/internal/xds/clients/xdsclient/internal/xdsresource/errors.go similarity index 100% rename from xds/internal/clients/xdsclient/internal/xdsresource/errors.go rename to internal/xds/clients/xdsclient/internal/xdsresource/errors.go diff --git a/xds/internal/clients/xdsclient/internal/xdsresource/name.go b/internal/xds/clients/xdsclient/internal/xdsresource/name.go similarity index 100% rename from xds/internal/clients/xdsclient/internal/xdsresource/name.go rename to internal/xds/clients/xdsclient/internal/xdsresource/name.go diff --git a/xds/internal/clients/xdsclient/internal/xdsresource/type.go b/internal/xds/clients/xdsclient/internal/xdsresource/type.go similarity index 100% rename from xds/internal/clients/xdsclient/internal/xdsresource/type.go rename to internal/xds/clients/xdsclient/internal/xdsresource/type.go diff --git a/xds/internal/clients/xdsclient/internal/xdsresource/version.go b/internal/xds/clients/xdsclient/internal/xdsresource/version.go similarity index 100% rename from xds/internal/clients/xdsclient/internal/xdsresource/version.go rename to internal/xds/clients/xdsclient/internal/xdsresource/version.go diff --git a/xds/internal/clients/xdsclient/logging.go b/internal/xds/clients/xdsclient/logging.go similarity index 100% rename from xds/internal/clients/xdsclient/logging.go rename to internal/xds/clients/xdsclient/logging.go diff --git a/xds/internal/clients/xdsclient/metrics/metrics.go b/internal/xds/clients/xdsclient/metrics/metrics.go similarity index 100% rename from xds/internal/clients/xdsclient/metrics/metrics.go rename to internal/xds/clients/xdsclient/metrics/metrics.go diff --git a/xds/internal/clients/xdsclient/resource_type.go b/internal/xds/clients/xdsclient/resource_type.go similarity index 100% rename from xds/internal/clients/xdsclient/resource_type.go rename to internal/xds/clients/xdsclient/resource_type.go diff --git a/xds/internal/clients/xdsclient/resource_watcher.go b/internal/xds/clients/xdsclient/resource_watcher.go similarity index 100% rename from xds/internal/clients/xdsclient/resource_watcher.go rename to internal/xds/clients/xdsclient/resource_watcher.go diff --git a/xds/internal/clients/xdsclient/test/ads_stream_ack_nack_test.go b/internal/xds/clients/xdsclient/test/ads_stream_ack_nack_test.go similarity index 98% rename from xds/internal/clients/xdsclient/test/ads_stream_ack_nack_test.go rename to internal/xds/clients/xdsclient/test/ads_stream_ack_nack_test.go index 467365d2677b..75639b4c63b0 100644 --- a/xds/internal/clients/xdsclient/test/ads_stream_ack_nack_test.go +++ b/internal/xds/clients/xdsclient/test/ads_stream_ack_nack_test.go @@ -28,12 +28,12 @@ import ( "github.com/google/go-cmp/cmp" "github.com/google/uuid" "google.golang.org/grpc/credentials/insecure" - "google.golang.org/grpc/xds/internal/clients" - "google.golang.org/grpc/xds/internal/clients/grpctransport" - "google.golang.org/grpc/xds/internal/clients/internal/testutils" - "google.golang.org/grpc/xds/internal/clients/internal/testutils/e2e" - "google.golang.org/grpc/xds/internal/clients/xdsclient" - "google.golang.org/grpc/xds/internal/clients/xdsclient/internal/xdsresource" + "google.golang.org/grpc/internal/xds/clients" + "google.golang.org/grpc/internal/xds/clients/grpctransport" + "google.golang.org/grpc/internal/xds/clients/internal/testutils" + "google.golang.org/grpc/internal/xds/clients/internal/testutils/e2e" + "google.golang.org/grpc/internal/xds/clients/xdsclient" + "google.golang.org/grpc/internal/xds/clients/xdsclient/internal/xdsresource" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/testing/protocmp" diff --git a/xds/internal/clients/xdsclient/test/ads_stream_backoff_test.go b/internal/xds/clients/xdsclient/test/ads_stream_backoff_test.go similarity index 97% rename from xds/internal/clients/xdsclient/test/ads_stream_backoff_test.go rename to internal/xds/clients/xdsclient/test/ads_stream_backoff_test.go index ad5ed26f65f7..6dc2ac51b77b 100644 --- a/xds/internal/clients/xdsclient/test/ads_stream_backoff_test.go +++ b/internal/xds/clients/xdsclient/test/ads_stream_backoff_test.go @@ -27,13 +27,13 @@ import ( "time" "google.golang.org/grpc/credentials/insecure" - "google.golang.org/grpc/xds/internal/clients/grpctransport" - "google.golang.org/grpc/xds/internal/clients/internal/testutils" - "google.golang.org/grpc/xds/internal/clients/internal/testutils/e2e" - "google.golang.org/grpc/xds/internal/clients/xdsclient" - xdsclientinternal "google.golang.org/grpc/xds/internal/clients/xdsclient/internal" - "google.golang.org/grpc/xds/internal/clients/xdsclient/internal/xdsresource" - "google.golang.org/grpc/xds/internal/xdsclient/xdsresource/version" + "google.golang.org/grpc/internal/xds/clients/grpctransport" + "google.golang.org/grpc/internal/xds/clients/internal/testutils" + "google.golang.org/grpc/internal/xds/clients/internal/testutils/e2e" + "google.golang.org/grpc/internal/xds/clients/xdsclient" + xdsclientinternal "google.golang.org/grpc/internal/xds/clients/xdsclient/internal" + "google.golang.org/grpc/internal/xds/clients/xdsclient/internal/xdsresource" + "google.golang.org/grpc/internal/xds/xdsclient/xdsresource/version" "google.golang.org/protobuf/testing/protocmp" v3corepb "github.com/envoyproxy/go-control-plane/envoy/config/core/v3" diff --git a/xds/internal/clients/xdsclient/test/ads_stream_flow_control_test.go b/internal/xds/clients/xdsclient/test/ads_stream_flow_control_test.go similarity index 98% rename from xds/internal/clients/xdsclient/test/ads_stream_flow_control_test.go rename to internal/xds/clients/xdsclient/test/ads_stream_flow_control_test.go index fe53c76a3138..9c417a14b28d 100644 --- a/xds/internal/clients/xdsclient/test/ads_stream_flow_control_test.go +++ b/internal/xds/clients/xdsclient/test/ads_stream_flow_control_test.go @@ -33,10 +33,10 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/credentials/insecure" "google.golang.org/grpc/internal/testutils/xds/e2e" - "google.golang.org/grpc/xds/internal/clients" - "google.golang.org/grpc/xds/internal/clients/xdsclient" - "google.golang.org/grpc/xds/internal/clients/xdsclient/internal/xdsresource" - "google.golang.org/grpc/xds/internal/xdsclient/xdsresource/version" + "google.golang.org/grpc/internal/xds/clients" + "google.golang.org/grpc/internal/xds/clients/xdsclient" + "google.golang.org/grpc/internal/xds/clients/xdsclient/internal/xdsresource" + "google.golang.org/grpc/internal/xds/xdsclient/xdsresource/version" ) // blockingListenerWatcher implements xdsresource.ListenerWatcher. It writes to diff --git a/xds/internal/clients/xdsclient/test/ads_stream_restart_test.go b/internal/xds/clients/xdsclient/test/ads_stream_restart_test.go similarity index 96% rename from xds/internal/clients/xdsclient/test/ads_stream_restart_test.go rename to internal/xds/clients/xdsclient/test/ads_stream_restart_test.go index 9d8b876dd0b6..b205ac2d3073 100644 --- a/xds/internal/clients/xdsclient/test/ads_stream_restart_test.go +++ b/internal/xds/clients/xdsclient/test/ads_stream_restart_test.go @@ -26,10 +26,10 @@ import ( "github.com/google/uuid" "google.golang.org/grpc/credentials/insecure" "google.golang.org/grpc/internal/testutils/xds/e2e" - "google.golang.org/grpc/xds/internal/clients/grpctransport" - "google.golang.org/grpc/xds/internal/clients/internal/testutils" - "google.golang.org/grpc/xds/internal/clients/xdsclient/internal/xdsresource" - "google.golang.org/grpc/xds/internal/xdsclient/xdsresource/version" + "google.golang.org/grpc/internal/xds/clients/grpctransport" + "google.golang.org/grpc/internal/xds/clients/internal/testutils" + "google.golang.org/grpc/internal/xds/clients/xdsclient/internal/xdsresource" + "google.golang.org/grpc/internal/xds/xdsclient/xdsresource/version" v3corepb "github.com/envoyproxy/go-control-plane/envoy/config/core/v3" v3listenerpb "github.com/envoyproxy/go-control-plane/envoy/config/listener/v3" diff --git a/xds/internal/clients/xdsclient/test/ads_stream_watch_test.go b/internal/xds/clients/xdsclient/test/ads_stream_watch_test.go similarity index 83% rename from xds/internal/clients/xdsclient/test/ads_stream_watch_test.go rename to internal/xds/clients/xdsclient/test/ads_stream_watch_test.go index 178da6c59722..40ca8eaaba0e 100644 --- a/xds/internal/clients/xdsclient/test/ads_stream_watch_test.go +++ b/internal/xds/clients/xdsclient/test/ads_stream_watch_test.go @@ -28,11 +28,12 @@ import ( "github.com/google/uuid" "google.golang.org/grpc/credentials/insecure" "google.golang.org/grpc/internal/testutils/xds/e2e" - "google.golang.org/grpc/xds/internal/clients/grpctransport" - "google.golang.org/grpc/xds/internal/clients/internal/testutils" - "google.golang.org/grpc/xds/internal/clients/xdsclient" - xdsclientinternal "google.golang.org/grpc/xds/internal/clients/xdsclient/internal" - "google.golang.org/grpc/xds/internal/clients/xdsclient/internal/xdsresource" + "google.golang.org/grpc/internal/xds/clients" + "google.golang.org/grpc/internal/xds/clients/grpctransport" + "google.golang.org/grpc/internal/xds/clients/internal/testutils" + "google.golang.org/grpc/internal/xds/clients/xdsclient" + xdsclientinternal "google.golang.org/grpc/internal/xds/clients/xdsclient/internal" + "google.golang.org/grpc/internal/xds/clients/xdsclient/internal/xdsresource" v3listenerpb "github.com/envoyproxy/go-control-plane/envoy/config/listener/v3" ) @@ -175,9 +176,34 @@ func (s) TestADS_WatchState_TimerFires(t *testing.T) { // short resource expiry timeout. nodeID := uuid.New().String() configs := map[string]grpctransport.Config{"insecure": {Credentials: insecure.NewBundle()}} - overrideWatchExpiryTimeout(t, defaultTestWatchExpiryTimeout) - client := createXDSClient(t, mgmtServer.Address, nodeID, grpctransport.NewBuilder(configs)) - + resourceTypes := map[string]xdsclient.ResourceType{xdsresource.V3ListenerURL: listenerType} + si := clients.ServerIdentifier{ + ServerURI: mgmtServer.Address, + Extensions: grpctransport.ServerIdentifierExtension{ConfigName: "insecure"}, + } + + xdsClientConfig := xdsclient.Config{ + Servers: []xdsclient.ServerConfig{{ServerIdentifier: si}}, + Node: clients.Node{ID: nodeID, UserAgentName: "user-agent", UserAgentVersion: "0.0.0.0"}, + TransportBuilder: grpctransport.NewBuilder(configs), + ResourceTypes: resourceTypes, + // Xdstp resource names used in this test do not specify an + // authority. These will end up looking up an entry with the + // empty key in the authorities map. Having an entry with an + // empty key and empty configuration, results in these + // resources also using the top-level configuration. + Authorities: map[string]xdsclient.Authority{ + "": {XDSServers: []xdsclient.ServerConfig{}}, + }, + WatchExpiryTimeout: defaultTestWatchExpiryTimeout, + } + + // Create an xDS client with the above config. + client, err := xdsclient.New(xdsClientConfig) + if err != nil { + t.Fatalf("Failed to create xDS client: %v", err) + } + t.Cleanup(func() { client.Close() }) // Create a watch for the first listener resource and verify that the timer // is running and the watch state is `requested`. const listenerName = "listener" diff --git a/xds/internal/clients/xdsclient/test/authority_test.go b/internal/xds/clients/xdsclient/test/authority_test.go similarity index 97% rename from xds/internal/clients/xdsclient/test/authority_test.go rename to internal/xds/clients/xdsclient/test/authority_test.go index 0256c5bb0909..9941b989e9ab 100644 --- a/xds/internal/clients/xdsclient/test/authority_test.go +++ b/internal/xds/clients/xdsclient/test/authority_test.go @@ -25,12 +25,12 @@ import ( "github.com/google/uuid" "google.golang.org/grpc/credentials/insecure" - "google.golang.org/grpc/xds/internal/clients" - "google.golang.org/grpc/xds/internal/clients/grpctransport" - "google.golang.org/grpc/xds/internal/clients/internal/testutils" - "google.golang.org/grpc/xds/internal/clients/internal/testutils/e2e" - "google.golang.org/grpc/xds/internal/clients/xdsclient" - "google.golang.org/grpc/xds/internal/clients/xdsclient/internal/xdsresource" + "google.golang.org/grpc/internal/xds/clients" + "google.golang.org/grpc/internal/xds/clients/grpctransport" + "google.golang.org/grpc/internal/xds/clients/internal/testutils" + "google.golang.org/grpc/internal/xds/clients/internal/testutils/e2e" + "google.golang.org/grpc/internal/xds/clients/xdsclient" + "google.golang.org/grpc/internal/xds/clients/xdsclient/internal/xdsresource" v3listenerpb "github.com/envoyproxy/go-control-plane/envoy/config/listener/v3" ) @@ -105,10 +105,10 @@ func setupForAuthorityTests(ctx context.Context, t *testing.T) (*testutils.Liste testAuthority2: {XDSServers: []xdsclient.ServerConfig{}}, testAuthority3: {XDSServers: []xdsclient.ServerConfig{{ServerIdentifier: siNonDefault}}}, }, + WatchExpiryTimeout: defaultTestWatchExpiryTimeout, } // Create an xDS client with the above config. - overrideWatchExpiryTimeout(t, defaultTestWatchExpiryTimeout) client, err := xdsclient.New(xdsClientConfig) if err != nil { t.Fatalf("Failed to create xDS client: %v", err) diff --git a/xds/internal/clients/xdsclient/test/dump_test.go b/internal/xds/clients/xdsclient/test/dump_test.go similarity index 97% rename from xds/internal/clients/xdsclient/test/dump_test.go rename to internal/xds/clients/xdsclient/test/dump_test.go index 49f09453f0d5..900e91e23c4b 100644 --- a/xds/internal/clients/xdsclient/test/dump_test.go +++ b/internal/xds/clients/xdsclient/test/dump_test.go @@ -29,13 +29,13 @@ import ( "github.com/google/go-cmp/cmp" "github.com/google/uuid" "google.golang.org/grpc/credentials/insecure" - "google.golang.org/grpc/xds/internal/clients" - "google.golang.org/grpc/xds/internal/clients/grpctransport" - "google.golang.org/grpc/xds/internal/clients/internal/pretty" - "google.golang.org/grpc/xds/internal/clients/internal/testutils" - "google.golang.org/grpc/xds/internal/clients/internal/testutils/e2e" - "google.golang.org/grpc/xds/internal/clients/xdsclient" - "google.golang.org/grpc/xds/internal/clients/xdsclient/internal/xdsresource" + "google.golang.org/grpc/internal/xds/clients" + "google.golang.org/grpc/internal/xds/clients/grpctransport" + "google.golang.org/grpc/internal/xds/clients/internal/pretty" + "google.golang.org/grpc/internal/xds/clients/internal/testutils" + "google.golang.org/grpc/internal/xds/clients/internal/testutils/e2e" + "google.golang.org/grpc/internal/xds/clients/xdsclient" + "google.golang.org/grpc/internal/xds/clients/xdsclient/internal/xdsresource" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/testing/protocmp" "google.golang.org/protobuf/types/known/anypb" diff --git a/xds/internal/clients/xdsclient/test/helpers_test.go b/internal/xds/clients/xdsclient/test/helpers_test.go similarity index 97% rename from xds/internal/clients/xdsclient/test/helpers_test.go rename to internal/xds/clients/xdsclient/test/helpers_test.go index 6e7086fbd6f9..ae7d5cea6945 100644 --- a/xds/internal/clients/xdsclient/test/helpers_test.go +++ b/internal/xds/clients/xdsclient/test/helpers_test.go @@ -29,10 +29,10 @@ import ( "time" "google.golang.org/grpc/internal/grpctest" - "google.golang.org/grpc/xds/internal/clients/internal/pretty" - "google.golang.org/grpc/xds/internal/clients/internal/testutils" - "google.golang.org/grpc/xds/internal/clients/xdsclient" - "google.golang.org/grpc/xds/internal/clients/xdsclient/internal/xdsresource" + "google.golang.org/grpc/internal/xds/clients/internal/pretty" + "google.golang.org/grpc/internal/xds/clients/internal/testutils" + "google.golang.org/grpc/internal/xds/clients/xdsclient" + "google.golang.org/grpc/internal/xds/clients/xdsclient/internal/xdsresource" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/types/known/anypb" diff --git a/xds/internal/clients/xdsclient/test/lds_watchers_test.go b/internal/xds/clients/xdsclient/test/lds_watchers_test.go similarity index 97% rename from xds/internal/clients/xdsclient/test/lds_watchers_test.go rename to internal/xds/clients/xdsclient/test/lds_watchers_test.go index e31d345747d9..ae4783921aec 100644 --- a/xds/internal/clients/xdsclient/test/lds_watchers_test.go +++ b/internal/xds/clients/xdsclient/test/lds_watchers_test.go @@ -29,14 +29,13 @@ import ( "github.com/google/go-cmp/cmp/cmpopts" "github.com/google/uuid" "google.golang.org/grpc/credentials/insecure" - "google.golang.org/grpc/xds/internal/clients" - "google.golang.org/grpc/xds/internal/clients/grpctransport" - "google.golang.org/grpc/xds/internal/clients/internal/syncutil" - "google.golang.org/grpc/xds/internal/clients/internal/testutils" - "google.golang.org/grpc/xds/internal/clients/internal/testutils/e2e" - "google.golang.org/grpc/xds/internal/clients/xdsclient" - xdsclientinternal "google.golang.org/grpc/xds/internal/clients/xdsclient/internal" - "google.golang.org/grpc/xds/internal/clients/xdsclient/internal/xdsresource" + "google.golang.org/grpc/internal/xds/clients" + "google.golang.org/grpc/internal/xds/clients/grpctransport" + "google.golang.org/grpc/internal/xds/clients/internal/syncutil" + "google.golang.org/grpc/internal/xds/clients/internal/testutils" + "google.golang.org/grpc/internal/xds/clients/internal/testutils/e2e" + "google.golang.org/grpc/internal/xds/clients/xdsclient" + "google.golang.org/grpc/internal/xds/clients/xdsclient/internal/xdsresource" v3listenerpb "github.com/envoyproxy/go-control-plane/envoy/config/listener/v3" v3httppb "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/network/http_connection_manager/v3" @@ -115,12 +114,6 @@ func badListenerResource(t *testing.T, name string) *v3listenerpb.Listener { } } -func overrideWatchExpiryTimeout(t *testing.T, watchExpiryTimeout time.Duration) { - originalWatchExpiryTimeout := xdsclientinternal.WatchExpiryTimeout - xdsclientinternal.WatchExpiryTimeout = watchExpiryTimeout - t.Cleanup(func() { xdsclientinternal.WatchExpiryTimeout = originalWatchExpiryTimeout }) -} - // verifyNoListenerUpdate verifies that no listener update is received on the // provided update channel, and returns an error if an update is received. // @@ -726,11 +719,10 @@ func (s) TestLDSWatch_ExpiryTimerFiresBeforeResponse(t *testing.T) { Node: clients.Node{ID: nodeID}, TransportBuilder: grpctransport.NewBuilder(configs), ResourceTypes: resourceTypes, + // Override the default watch expiry timeout. + WatchExpiryTimeout: defaultTestWatchExpiryTimeout, } - // Create an xDS client with the above config and override the default - // watch expiry timeout. - overrideWatchExpiryTimeout(t, defaultTestWatchExpiryTimeout) client, err := xdsclient.New(xdsClientConfig) if err != nil { t.Fatalf("Failed to create xDS client: %v", err) @@ -777,11 +769,11 @@ func (s) TestLDSWatch_ValidResponseCancelsExpiryTimerBehavior(t *testing.T) { Node: clients.Node{ID: nodeID}, TransportBuilder: grpctransport.NewBuilder(configs), ResourceTypes: resourceTypes, + // Override the default watch expiry timeout. + WatchExpiryTimeout: defaultTestWatchExpiryTimeout, } - // Create an xDS client with the above config and override the default - // watch expiry timeout. - overrideWatchExpiryTimeout(t, defaultTestWatchExpiryTimeout) + // Create an xDS client with the above config. client, err := xdsclient.New(xdsClientConfig) if err != nil { t.Fatalf("Failed to create xDS client: %v", err) diff --git a/xds/internal/clients/xdsclient/test/metrics_test.go b/internal/xds/clients/xdsclient/test/metrics_test.go similarity index 97% rename from xds/internal/clients/xdsclient/test/metrics_test.go rename to internal/xds/clients/xdsclient/test/metrics_test.go index b49693bcff36..8332cc57faef 100644 --- a/xds/internal/clients/xdsclient/test/metrics_test.go +++ b/internal/xds/clients/xdsclient/test/metrics_test.go @@ -27,12 +27,12 @@ import ( "github.com/google/uuid" "google.golang.org/grpc/credentials/insecure" "google.golang.org/grpc/internal/testutils" - "google.golang.org/grpc/xds/internal/clients" - "google.golang.org/grpc/xds/internal/clients/grpctransport" - "google.golang.org/grpc/xds/internal/clients/internal/testutils/e2e" - "google.golang.org/grpc/xds/internal/clients/xdsclient" - "google.golang.org/grpc/xds/internal/clients/xdsclient/internal/xdsresource" - "google.golang.org/grpc/xds/internal/clients/xdsclient/metrics" + "google.golang.org/grpc/internal/xds/clients" + "google.golang.org/grpc/internal/xds/clients/grpctransport" + "google.golang.org/grpc/internal/xds/clients/internal/testutils/e2e" + "google.golang.org/grpc/internal/xds/clients/xdsclient" + "google.golang.org/grpc/internal/xds/clients/xdsclient/internal/xdsresource" + "google.golang.org/grpc/internal/xds/clients/xdsclient/metrics" v3listenerpb "github.com/envoyproxy/go-control-plane/envoy/config/listener/v3" v3discoverypb "github.com/envoyproxy/go-control-plane/envoy/service/discovery/v3" diff --git a/xds/internal/clients/xdsclient/test/misc_watchers_test.go b/internal/xds/clients/xdsclient/test/misc_watchers_test.go similarity index 75% rename from xds/internal/clients/xdsclient/test/misc_watchers_test.go rename to internal/xds/clients/xdsclient/test/misc_watchers_test.go index 824d54befa5f..e611c2240c43 100644 --- a/xds/internal/clients/xdsclient/test/misc_watchers_test.go +++ b/internal/xds/clients/xdsclient/test/misc_watchers_test.go @@ -27,13 +27,13 @@ import ( "github.com/google/uuid" "google.golang.org/grpc/credentials/insecure" - "google.golang.org/grpc/xds/internal/clients" - "google.golang.org/grpc/xds/internal/clients/grpctransport" - "google.golang.org/grpc/xds/internal/clients/internal/testutils" - "google.golang.org/grpc/xds/internal/clients/internal/testutils/e2e" - "google.golang.org/grpc/xds/internal/clients/internal/testutils/fakeserver" - "google.golang.org/grpc/xds/internal/clients/xdsclient" - "google.golang.org/grpc/xds/internal/clients/xdsclient/internal/xdsresource" + "google.golang.org/grpc/internal/xds/clients" + "google.golang.org/grpc/internal/xds/clients/grpctransport" + "google.golang.org/grpc/internal/xds/clients/internal/testutils" + "google.golang.org/grpc/internal/xds/clients/internal/testutils/e2e" + "google.golang.org/grpc/internal/xds/clients/internal/testutils/fakeserver" + "google.golang.org/grpc/internal/xds/clients/xdsclient" + "google.golang.org/grpc/internal/xds/clients/xdsclient/internal/xdsresource" "google.golang.org/protobuf/types/known/anypb" v3listenerpb "github.com/envoyproxy/go-control-plane/envoy/config/listener/v3" @@ -527,139 +527,3 @@ func (s) TestWatchErrorsContainNodeID_ChannelCreationFailure(t *testing.T) { } } } - -// TestUnsubscribeAndResubscribe tests the scenario where the client is busy -// processing a response (simulating a pending ACK at a higher level by holding -// the onDone callback from watchers). During this busy state, a resource is -// unsubscribed and then immediately resubscribed which causes the -// unsubscription and new subscription requests to be buffered due to flow -// control. -// -// The test verifies the following: -// - The resubscribed resource is served from the cache. -// - No "resource does not exist" error is generated for the resubscribed -// resource. -func (s) TestRaceUnsubscribeResubscribe(t *testing.T) { - ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) - defer cancel() - - mgmtServer := e2e.StartManagementServer(t, e2e.ManagementServerOptions{}) - nodeID := uuid.New().String() - - resourceTypes := map[string]xdsclient.ResourceType{xdsresource.V3ListenerURL: listenerType} - si := clients.ServerIdentifier{ - ServerURI: mgmtServer.Address, - Extensions: grpctransport.ServerIdentifierExtension{ConfigName: "insecure"}, - } - - configs := map[string]grpctransport.Config{"insecure": {Credentials: insecure.NewBundle()}} - xdsClientConfig := xdsclient.Config{ - Servers: []xdsclient.ServerConfig{{ServerIdentifier: si}}, - Node: clients.Node{ID: nodeID}, - TransportBuilder: grpctransport.NewBuilder(configs), - ResourceTypes: resourceTypes, - // Xdstp resource names used in this test do not specify an - // authority. These will end up looking up an entry with the - // empty key in the authorities map. Having an entry with an - // empty key and empty configuration, results in these - // resources also using the top-level configuration. - Authorities: map[string]xdsclient.Authority{ - "": {XDSServers: []xdsclient.ServerConfig{}}, - }, - } - - // Create an xDS client with the above config. - client, err := xdsclient.New(xdsClientConfig) - if err != nil { - t.Fatalf("Failed to create xDS client: %v", err) - } - defer client.Close() - - const ldsResourceName1 = "test-listener-resource1" - const ldsResourceName2 = "test-listener-resource2" - const rdsName1 = "test-route-configuration-resource1" - const rdsName2 = "test-route-configuration-resource2" - listenerResource1 := e2e.DefaultClientListener(ldsResourceName1, rdsName1) - listenerResource2 := e2e.DefaultClientListener(ldsResourceName2, rdsName2) - - // Watch ldsResourceName1 with a regular watcher to ensure it's in cache - // and ACKed. - watcherInitial := newListenerWatcher() - cancelInitial := client.WatchResource(xdsresource.V3ListenerURL, ldsResourceName1, watcherInitial) - if err := mgmtServer.Update(ctx, e2e.UpdateOptions{NodeID: nodeID, Listeners: []*v3listenerpb.Listener{listenerResource1}, SkipValidation: true}); err != nil { - t.Fatalf("mgmtServer.Update() for %s failed: %v", ldsResourceName1, err) - } - if err := verifyListenerUpdate(ctx, watcherInitial.updateCh, listenerUpdateErrTuple{update: listenerUpdate{RouteConfigName: rdsName1}}); err != nil { - t.Fatalf("watcherR1Initial did not receive update for %s: %v", ldsResourceName1, err) - } - cancelInitial() - - // Watch ldsResourceName1 and ldsResourceName2 using blocking watchers. - // - Server sends {ldsResourceName1, ldsResourceName2}. - // - Watchers for both resources get the update but we HOLD on to their - // onDone callbacks. - blockingWatcherR1 := newBLockingListenerWatcher() - cancelR1 := client.WatchResource(xdsresource.V3ListenerURL, ldsResourceName1, blockingWatcherR1) - // defer cancelR1 later to create the race - - blockingWatcherR2 := newBLockingListenerWatcher() - cancelR2 := client.WatchResource(xdsresource.V3ListenerURL, ldsResourceName2, blockingWatcherR2) - defer cancelR2() - - // Configure the listener resources on the management server. - resources := e2e.UpdateOptions{ - NodeID: nodeID, - Listeners: []*v3listenerpb.Listener{listenerResource1, listenerResource2}, - SkipValidation: true} - if err := mgmtServer.Update(ctx, resources); err != nil { - t.Fatalf("mgmtServer.Update() for %s and %s failed: %v", ldsResourceName1, ldsResourceName2, err) - } - - var onDoneR1, onDoneR2 func() - select { - case <-blockingWatcherR1.updateCh: - onDoneR1 = <-blockingWatcherR1.doneNotifierCh - case <-ctx.Done(): - t.Fatalf("Timeout waiting for update for %s on blockingWatcherR1: %v", ldsResourceName1, ctx.Err()) - } - select { - case <-blockingWatcherR2.updateCh: - onDoneR2 = <-blockingWatcherR2.doneNotifierCh - case <-ctx.Done(): - t.Fatalf("Timeout waiting for update for %s on blockingWatcherR2: %v", ldsResourceName2, ctx.Err()) - } - - // At this point, ACK for {listenerResource1,listenerResource2} has been - // sent by the client but s.fc.pending.Load() is true because onDoneR1 and - // onDoneR2 are held. - // - // Unsubscribe listenerResource1. This request should be buffered by - // adsStreamImpl because s.fc.pending.Load() is true. - cancelR1() - - // Resubscribe listenerResource1 with a new regular watcher, which should - // be served from cache. - watcherR1New := newListenerWatcher() - cancelR1New := client.WatchResource(xdsresource.V3ListenerURL, ldsResourceName1, watcherR1New) - defer cancelR1New() - - if err := verifyListenerUpdate(ctx, watcherR1New.updateCh, listenerUpdateErrTuple{update: listenerUpdate{RouteConfigName: rdsName1}}); err != nil { - t.Fatalf("watcherR1New did not receive cached update for %s: %v", ldsResourceName1, err) - } - - // Release the onDone callbacks. - if onDoneR1 != nil { // onDoneR1 might be nil if cancelR1() completed very fast. - onDoneR1() - } - onDoneR2() - - // Verify watcherR1New does not get a "resource does not exist" error. - sCtx, sCancel := context.WithTimeout(ctx, defaultTestShortTimeout*10) // Slightly longer to catch delayed errors - defer sCancel() - if err := verifyNoListenerUpdate(sCtx, watcherR1New.resourceErrCh); err != nil { - t.Fatalf("watcherR1New received unexpected resource error for %s: %v", ldsResourceName1, err) - } - if err := verifyNoListenerUpdate(sCtx, watcherR1New.ambientErrCh); err != nil { - t.Fatalf("watcherR1New received unexpected ambient error for %s: %v", ldsResourceName1, err) - } -} diff --git a/xds/internal/clients/xdsclient/xdsclient.go b/internal/xds/clients/xdsclient/xdsclient.go similarity index 90% rename from xds/internal/clients/xdsclient/xdsclient.go rename to internal/xds/clients/xdsclient/xdsclient.go index 93d26217480d..cc7d5c4e264d 100644 --- a/xds/internal/clients/xdsclient/xdsclient.go +++ b/internal/xds/clients/xdsclient/xdsclient.go @@ -39,13 +39,13 @@ import ( "time" "google.golang.org/grpc/internal/grpclog" - "google.golang.org/grpc/xds/internal/clients" - clientsinternal "google.golang.org/grpc/xds/internal/clients/internal" - "google.golang.org/grpc/xds/internal/clients/internal/backoff" - "google.golang.org/grpc/xds/internal/clients/internal/syncutil" - xdsclientinternal "google.golang.org/grpc/xds/internal/clients/xdsclient/internal" - "google.golang.org/grpc/xds/internal/clients/xdsclient/internal/xdsresource" - "google.golang.org/grpc/xds/internal/clients/xdsclient/metrics" + "google.golang.org/grpc/internal/xds/clients" + clientsinternal "google.golang.org/grpc/internal/xds/clients/internal" + "google.golang.org/grpc/internal/xds/clients/internal/backoff" + "google.golang.org/grpc/internal/xds/clients/internal/syncutil" + xdsclientinternal "google.golang.org/grpc/internal/xds/clients/xdsclient/internal" + "google.golang.org/grpc/internal/xds/clients/xdsclient/internal/xdsresource" + "google.golang.org/grpc/internal/xds/clients/xdsclient/metrics" "google.golang.org/protobuf/proto" v3statuspb "github.com/envoyproxy/go-control-plane/envoy/service/status/v3" @@ -61,7 +61,6 @@ var ( ) func init() { - xdsclientinternal.WatchExpiryTimeout = defaultWatchExpiryTimeout xdsclientinternal.StreamBackoff = defaultExponentialBackoff xdsclientinternal.ResourceWatchStateForTesting = resourceWatchStateForTesting } @@ -108,7 +107,9 @@ func New(config Config) (*XDSClient, error) { case config.Authorities == nil && config.Servers == nil: return nil, errors.New("xdsclient: no servers or authorities specified") } - + if config.WatchExpiryTimeout == 0 { + config.WatchExpiryTimeout = defaultWatchExpiryTimeout + } client, err := newClient(&config, name) if err != nil { return nil, err @@ -116,12 +117,6 @@ func New(config Config) (*XDSClient, error) { return client, nil } -// SetWatchExpiryTimeoutForTesting override the default watch expiry timeout -// with provided timeout value. -func (c *XDSClient) SetWatchExpiryTimeoutForTesting(watchExpiryTimeout time.Duration) { - c.watchExpiryTimeout = watchExpiryTimeout -} - // newClient returns a new XDSClient with the given config. func newClient(config *Config, target string) (*XDSClient, error) { ctx, cancel := context.WithCancel(context.Background()) @@ -130,7 +125,7 @@ func newClient(config *Config, target string) (*XDSClient, error) { done: syncutil.NewEvent(), authorities: make(map[string]*authority), config: config, - watchExpiryTimeout: xdsclientinternal.WatchExpiryTimeout, + watchExpiryTimeout: config.WatchExpiryTimeout, backoff: xdsclientinternal.StreamBackoff, serializer: syncutil.NewCallbackSerializer(ctx), serializerClose: cancel, @@ -437,29 +432,12 @@ func (cs *channelState) adsResourceDoesNotExist(typ ResourceType, resourceName s } } -func (cs *channelState) adsResourceRemoveUnsubscribedCacheEntries(rType ResourceType) { - if cs.parent.done.HasFired() { - return - } - - cs.parent.channelsMu.Lock() - defer cs.parent.channelsMu.Unlock() - - for authority := range cs.interestedAuthorities { - authority.xdsClientSerializer.TrySchedule(func(context.Context) { - authority.removeUnsubscribedCacheEntries(rType) - }) - } -} - func resourceWatchStateForTesting(c *XDSClient, rType ResourceType, resourceName string) (xdsresource.ResourceWatchState, error) { - c.channelsMu.Lock() - defer c.channelsMu.Unlock() - - for _, state := range c.xdsActiveChannels { - if st, err := state.channel.ads.adsResourceWatchStateForTesting(rType, resourceName); err == nil { - return st, nil - } + n := xdsresource.ParseName(resourceName) + a := c.getAuthorityForResource(n) + if a == nil { + return xdsresource.ResourceWatchState{}, fmt.Errorf("unable to find authority for resource name %q", resourceName) } - return xdsresource.ResourceWatchState{}, fmt.Errorf("unable to find watch state for resource type %q and name %q", rType.TypeName, resourceName) + return a.resourceWatchStateForTesting(rType, resourceName) + } diff --git a/xds/internal/clients/xdsclient/xdsclient_test.go b/internal/xds/clients/xdsclient/xdsclient_test.go similarity index 95% rename from xds/internal/clients/xdsclient/xdsclient_test.go rename to internal/xds/clients/xdsclient/xdsclient_test.go index 073362d02a4d..d166438228ba 100644 --- a/xds/internal/clients/xdsclient/xdsclient_test.go +++ b/internal/xds/clients/xdsclient/xdsclient_test.go @@ -23,9 +23,9 @@ import ( "testing" "google.golang.org/grpc/credentials/insecure" - "google.golang.org/grpc/xds/internal/clients" - "google.golang.org/grpc/xds/internal/clients/grpctransport" - "google.golang.org/grpc/xds/internal/clients/xdsclient/internal/xdsresource" + "google.golang.org/grpc/internal/xds/clients" + "google.golang.org/grpc/internal/xds/clients/grpctransport" + "google.golang.org/grpc/internal/xds/clients/xdsclient/internal/xdsresource" ) func (s) TestXDSClient_New(t *testing.T) { diff --git a/xds/internal/clients/xdsclient/xdsconfig.go b/internal/xds/clients/xdsclient/xdsconfig.go similarity index 88% rename from xds/internal/clients/xdsclient/xdsconfig.go rename to internal/xds/clients/xdsclient/xdsconfig.go index a276309dff47..9d376e508c4f 100644 --- a/xds/internal/clients/xdsclient/xdsconfig.go +++ b/internal/xds/clients/xdsclient/xdsconfig.go @@ -19,7 +19,9 @@ package xdsclient import ( - "google.golang.org/grpc/xds/internal/clients" + "time" + + "google.golang.org/grpc/internal/xds/clients" ) // Config is used to configure an xDS client. After one has been passed to the @@ -60,6 +62,13 @@ type Config struct { // MetricsReporter is used to report registered metrics. If unset, no // metrics will be reported. MetricsReporter clients.MetricsReporter + + // WatchExpiryTimeout is the duration after which a resource watch expires + // if the requested resource is not received from the management server. + // Most users will not need to set this. If zero, a default value of 15 + // seconds is used as specified here: + // envoyproxy.io/docs/envoy/latest/api-docs/xds_protocol#knowing-when-a-requested-resource-does-not-exist + WatchExpiryTimeout time.Duration } // ServerConfig contains configuration for an xDS management server. diff --git a/xds/internal/clusterspecifier/cluster_specifier.go b/internal/xds/clusterspecifier/cluster_specifier.go similarity index 100% rename from xds/internal/clusterspecifier/cluster_specifier.go rename to internal/xds/clusterspecifier/cluster_specifier.go diff --git a/xds/internal/clusterspecifier/rls/rls.go b/internal/xds/clusterspecifier/rls/rls.go similarity index 98% rename from xds/internal/clusterspecifier/rls/rls.go rename to internal/xds/clusterspecifier/rls/rls.go index 50f58cd43a09..ce2c22537a12 100644 --- a/xds/internal/clusterspecifier/rls/rls.go +++ b/internal/xds/clusterspecifier/rls/rls.go @@ -26,7 +26,7 @@ import ( "google.golang.org/grpc/balancer" "google.golang.org/grpc/internal" rlspb "google.golang.org/grpc/internal/proto/grpc_lookup_v1" - "google.golang.org/grpc/xds/internal/clusterspecifier" + "google.golang.org/grpc/internal/xds/clusterspecifier" "google.golang.org/protobuf/encoding/protojson" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/types/known/anypb" diff --git a/xds/internal/clusterspecifier/rls/rls_test.go b/internal/xds/clusterspecifier/rls/rls_test.go similarity index 97% rename from xds/internal/clusterspecifier/rls/rls_test.go rename to internal/xds/clusterspecifier/rls/rls_test.go index 8f09ac152b90..70be4b8884a7 100644 --- a/xds/internal/clusterspecifier/rls/rls_test.go +++ b/internal/xds/clusterspecifier/rls/rls_test.go @@ -27,12 +27,12 @@ import ( "google.golang.org/grpc/internal/grpctest" rlspb "google.golang.org/grpc/internal/proto/grpc_lookup_v1" "google.golang.org/grpc/internal/testutils" - "google.golang.org/grpc/xds/internal/clusterspecifier" + "google.golang.org/grpc/internal/xds/clusterspecifier" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/types/known/durationpb" _ "google.golang.org/grpc/balancer/rls" // Register the RLS LB policy. - _ "google.golang.org/grpc/xds/internal/balancer/cdsbalancer" // Register the CDS LB policy. + _ "google.golang.org/grpc/internal/xds/balancer/cdsbalancer" // Register the CDS LB policy. ) func init() { diff --git a/xds/internal/httpfilter/fault/fault.go b/internal/xds/httpfilter/fault/fault.go similarity index 99% rename from xds/internal/httpfilter/fault/fault.go rename to internal/xds/httpfilter/fault/fault.go index 0ffa9c827279..3acd4aec6aaa 100644 --- a/xds/internal/httpfilter/fault/fault.go +++ b/internal/xds/httpfilter/fault/fault.go @@ -31,9 +31,9 @@ import ( "google.golang.org/grpc/codes" iresolver "google.golang.org/grpc/internal/resolver" + "google.golang.org/grpc/internal/xds/httpfilter" "google.golang.org/grpc/metadata" "google.golang.org/grpc/status" - "google.golang.org/grpc/xds/internal/httpfilter" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/types/known/anypb" diff --git a/xds/internal/httpfilter/fault/fault_test.go b/internal/xds/httpfilter/fault/fault_test.go similarity index 99% rename from xds/internal/httpfilter/fault/fault_test.go rename to internal/xds/httpfilter/fault/fault_test.go index 27377ccd775b..2612094baa5a 100644 --- a/xds/internal/httpfilter/fault/fault_test.go +++ b/internal/xds/httpfilter/fault/fault_test.go @@ -55,9 +55,9 @@ import ( testgrpc "google.golang.org/grpc/interop/grpc_testing" testpb "google.golang.org/grpc/interop/grpc_testing" - _ "google.golang.org/grpc/xds/internal/balancer" // Register the balancers. - _ "google.golang.org/grpc/xds/internal/httpfilter/router" // Register the router filter. - _ "google.golang.org/grpc/xds/internal/resolver" // Register the xds_resolver. + _ "google.golang.org/grpc/internal/xds/balancer" // Register the balancers. + _ "google.golang.org/grpc/internal/xds/httpfilter/router" // Register the router filter. + _ "google.golang.org/grpc/internal/xds/resolver" // Register the xds_resolver. ) const defaultTestTimeout = 10 * time.Second diff --git a/xds/internal/httpfilter/httpfilter.go b/internal/xds/httpfilter/httpfilter.go similarity index 100% rename from xds/internal/httpfilter/httpfilter.go rename to internal/xds/httpfilter/httpfilter.go diff --git a/xds/internal/httpfilter/rbac/rbac.go b/internal/xds/httpfilter/rbac/rbac.go similarity index 99% rename from xds/internal/httpfilter/rbac/rbac.go rename to internal/xds/httpfilter/rbac/rbac.go index 260dad756642..0155009034e4 100644 --- a/xds/internal/httpfilter/rbac/rbac.go +++ b/internal/xds/httpfilter/rbac/rbac.go @@ -26,8 +26,8 @@ import ( "strings" "google.golang.org/grpc/internal/resolver" + "google.golang.org/grpc/internal/xds/httpfilter" "google.golang.org/grpc/internal/xds/rbac" - "google.golang.org/grpc/xds/internal/httpfilter" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/types/known/anypb" diff --git a/xds/internal/httpfilter/router/router.go b/internal/xds/httpfilter/router/router.go similarity index 98% rename from xds/internal/httpfilter/router/router.go rename to internal/xds/httpfilter/router/router.go index a781523d371e..d3a498d67706 100644 --- a/xds/internal/httpfilter/router/router.go +++ b/internal/xds/httpfilter/router/router.go @@ -23,7 +23,7 @@ import ( "fmt" iresolver "google.golang.org/grpc/internal/resolver" - "google.golang.org/grpc/xds/internal/httpfilter" + "google.golang.org/grpc/internal/xds/httpfilter" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/types/known/anypb" diff --git a/xds/internal/resolver/cluster_specifier_plugin_test.go b/internal/xds/resolver/cluster_specifier_plugin_test.go similarity index 98% rename from xds/internal/resolver/cluster_specifier_plugin_test.go rename to internal/xds/resolver/cluster_specifier_plugin_test.go index 5fc9e08aac28..d9a3fcec9ffa 100644 --- a/xds/internal/resolver/cluster_specifier_plugin_test.go +++ b/internal/xds/resolver/cluster_specifier_plugin_test.go @@ -29,10 +29,10 @@ import ( iresolver "google.golang.org/grpc/internal/resolver" "google.golang.org/grpc/internal/testutils" "google.golang.org/grpc/internal/testutils/xds/e2e" + "google.golang.org/grpc/internal/xds/balancer/clustermanager" + "google.golang.org/grpc/internal/xds/clusterspecifier" "google.golang.org/grpc/resolver" "google.golang.org/grpc/serviceconfig" - "google.golang.org/grpc/xds/internal/balancer/clustermanager" - "google.golang.org/grpc/xds/internal/clusterspecifier" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/types/known/anypb" "google.golang.org/protobuf/types/known/wrapperspb" diff --git a/xds/internal/resolver/helpers_test.go b/internal/xds/resolver/helpers_test.go similarity index 88% rename from xds/internal/resolver/helpers_test.go rename to internal/xds/resolver/helpers_test.go index cdb9511b04ae..243bbfd99f45 100644 --- a/xds/internal/resolver/helpers_test.go +++ b/internal/xds/resolver/helpers_test.go @@ -34,12 +34,14 @@ import ( iresolver "google.golang.org/grpc/internal/resolver" "google.golang.org/grpc/internal/testutils" "google.golang.org/grpc/internal/testutils/xds/e2e" + xdsresolver "google.golang.org/grpc/internal/xds/resolver" + "google.golang.org/grpc/internal/xds/xdsclient/xdsresource/version" "google.golang.org/grpc/resolver" "google.golang.org/grpc/serviceconfig" "google.golang.org/grpc/status" - xdsresolver "google.golang.org/grpc/xds/internal/resolver" - "google.golang.org/grpc/xds/internal/xdsclient/xdsresource/version" + v3clusterpb "github.com/envoyproxy/go-control-plane/envoy/config/cluster/v3" + v3endpointpb "github.com/envoyproxy/go-control-plane/envoy/config/endpoint/v3" v3listenerpb "github.com/envoyproxy/go-control-plane/envoy/config/listener/v3" v3routepb "github.com/envoyproxy/go-control-plane/envoy/config/route/v3" v3discoverypb "github.com/envoyproxy/go-control-plane/envoy/service/discovery/v3" @@ -60,11 +62,17 @@ const ( defaultTestServiceName = "service-name" defaultTestRouteConfigName = "route-config-name" defaultTestClusterName = "cluster-name" + defaultTestEndpointName = "endpoint-name" + defaultTestHostname = "test-host" ) -// This is the expected service config when using default listener and route -// configuration resources from the e2e package using the above resource names. -var wantDefaultServiceConfig = fmt.Sprintf(`{ +var defaultTestPort = []uint32{8080} + +// wantServiceConfig returns a JSON representation of a service config with +// xds_cluster_manager_experimental LB policy with a child policy of +// cds_experimental for the provided cluster name. +func wantServiceConfig(clusterName string) string { + return fmt.Sprintf(`{ "loadBalancingConfig": [{ "xds_cluster_manager_experimental": { "children": { @@ -78,7 +86,8 @@ var wantDefaultServiceConfig = fmt.Sprintf(`{ } } }] - }`, defaultTestClusterName, defaultTestClusterName) + }`, clusterName, clusterName) +} // buildResolverForTarget builds an xDS resolver for the given target. If // the bootstrap contents are provided, it build the xDS resolver using them @@ -283,6 +292,21 @@ func configureResourcesOnManagementServer(ctx context.Context, t *testing.T, mgm } } +// Updates all the listener, route, cluster and endpoint configuration resources +// on the given management server. +func configureAllResourcesOnManagementServer(ctx context.Context, t *testing.T, mgmtServer *e2e.ManagementServer, nodeID string, listeners []*v3listenerpb.Listener, routes []*v3routepb.RouteConfiguration, clusters []*v3clusterpb.Cluster, endpoints []*v3endpointpb.ClusterLoadAssignment) { + resources := e2e.UpdateOptions{ + NodeID: nodeID, + Listeners: listeners, + Routes: routes, + Clusters: clusters, + Endpoints: endpoints, + } + if err := mgmtServer.Update(ctx, resources); err != nil { + t.Fatal(err) + } +} + // waitForResourceNames waits for the wantNames to be pushed on to namesCh. // Fails the test by calling t.Fatal if the context expires before that. func waitForResourceNames(ctx context.Context, t *testing.T, namesCh chan []string, wantNames []string) { diff --git a/xds/internal/resolver/internal/internal.go b/internal/xds/resolver/internal/internal.go similarity index 100% rename from xds/internal/resolver/internal/internal.go rename to internal/xds/resolver/internal/internal.go diff --git a/xds/internal/resolver/logging.go b/internal/xds/resolver/logging.go similarity index 100% rename from xds/internal/resolver/logging.go rename to internal/xds/resolver/logging.go diff --git a/xds/internal/resolver/serviceconfig.go b/internal/xds/resolver/serviceconfig.go similarity index 98% rename from xds/internal/resolver/serviceconfig.go rename to internal/xds/resolver/serviceconfig.go index 40f038b8a64e..2b4e5a05d892 100644 --- a/xds/internal/resolver/serviceconfig.go +++ b/internal/xds/resolver/serviceconfig.go @@ -35,11 +35,11 @@ import ( iringhash "google.golang.org/grpc/internal/ringhash" "google.golang.org/grpc/internal/serviceconfig" "google.golang.org/grpc/internal/wrr" + "google.golang.org/grpc/internal/xds/balancer/clustermanager" + "google.golang.org/grpc/internal/xds/httpfilter" + "google.golang.org/grpc/internal/xds/xdsclient/xdsresource" "google.golang.org/grpc/metadata" "google.golang.org/grpc/status" - "google.golang.org/grpc/xds/internal/balancer/clustermanager" - "google.golang.org/grpc/xds/internal/httpfilter" - "google.golang.org/grpc/xds/internal/xdsclient/xdsresource" ) const ( diff --git a/xds/internal/resolver/serviceconfig_test.go b/internal/xds/resolver/serviceconfig_test.go similarity index 97% rename from xds/internal/resolver/serviceconfig_test.go rename to internal/xds/resolver/serviceconfig_test.go index 003076dee249..3570ff2ebc9c 100644 --- a/xds/internal/resolver/serviceconfig_test.go +++ b/internal/xds/resolver/serviceconfig_test.go @@ -30,9 +30,9 @@ import ( "google.golang.org/grpc/internal/grpcutil" iresolver "google.golang.org/grpc/internal/resolver" "google.golang.org/grpc/internal/testutils" + _ "google.golang.org/grpc/internal/xds/balancer/cdsbalancer" // To parse LB config + "google.golang.org/grpc/internal/xds/xdsclient/xdsresource" "google.golang.org/grpc/metadata" - _ "google.golang.org/grpc/xds/internal/balancer/cdsbalancer" // To parse LB config - "google.golang.org/grpc/xds/internal/xdsclient/xdsresource" ) var defaultTestTimeout = 10 * time.Second diff --git a/xds/internal/resolver/watch_service.go b/internal/xds/resolver/watch_service.go similarity index 98% rename from xds/internal/resolver/watch_service.go rename to internal/xds/resolver/watch_service.go index e8d52d0e0730..44b885c44055 100644 --- a/xds/internal/resolver/watch_service.go +++ b/internal/xds/resolver/watch_service.go @@ -21,7 +21,7 @@ package resolver import ( "context" - "google.golang.org/grpc/xds/internal/xdsclient/xdsresource" + "google.golang.org/grpc/internal/xds/xdsclient/xdsresource" ) type listenerWatcher struct { diff --git a/xds/internal/resolver/watch_service_test.go b/internal/xds/resolver/watch_service_test.go similarity index 73% rename from xds/internal/resolver/watch_service_test.go rename to internal/xds/resolver/watch_service_test.go index 7df159c65c30..1c68eba32013 100644 --- a/xds/internal/resolver/watch_service_test.go +++ b/internal/xds/resolver/watch_service_test.go @@ -49,28 +49,35 @@ func (s) TestServiceWatch_ListenerPointsToNewRouteConfiguration(t *testing.T) { mgmtServer, lisCh, routeCfgCh, bc := setupManagementServerForTest(t, nodeID) // Configure resources on the management server. - listeners := []*v3listenerpb.Listener{e2e.DefaultClientListener(defaultTestServiceName, defaultTestRouteConfigName)} - routes := []*v3routepb.RouteConfiguration{e2e.DefaultRouteConfig(defaultTestRouteConfigName, defaultTestServiceName, defaultTestClusterName)} - configureResourcesOnManagementServer(ctx, t, mgmtServer, nodeID, listeners, routes) + resources := e2e.DefaultClientResources(e2e.ResourceParams{ + DialTarget: defaultTestServiceName, + NodeID: nodeID, + Host: defaultTestHostname, + Port: defaultTestPort[0], + SecLevel: e2e.SecurityLevelNone, + }) + if err := mgmtServer.Update(ctx, resources); err != nil { + t.Fatal(err) + } stateCh, _, _ := buildResolverForTarget(t, resolver.Target{URL: *testutils.MustParseURL("xds:///" + defaultTestServiceName)}, bc) // Verify initial update from the resolver. waitForResourceNames(ctx, t, lisCh, []string{defaultTestServiceName}) - waitForResourceNames(ctx, t, routeCfgCh, []string{defaultTestRouteConfigName}) - verifyUpdateFromResolver(ctx, t, stateCh, wantDefaultServiceConfig) + waitForResourceNames(ctx, t, routeCfgCh, []string{resources.Routes[0].Name}) + verifyUpdateFromResolver(ctx, t, stateCh, wantServiceConfig(resources.Clusters[0].Name)) // Update the listener resource to point to a new route configuration name. // Leave the old route configuration resource unchanged. newTestRouteConfigName := defaultTestRouteConfigName + "-new" - listeners = []*v3listenerpb.Listener{e2e.DefaultClientListener(defaultTestServiceName, newTestRouteConfigName)} - configureResourcesOnManagementServer(ctx, t, mgmtServer, nodeID, listeners, routes) + resources.Listeners = []*v3listenerpb.Listener{e2e.DefaultClientListener(defaultTestServiceName, newTestRouteConfigName)} + configureResourcesOnManagementServer(ctx, t, mgmtServer, nodeID, resources.Listeners, resources.Routes) // Verify that the new route configuration resource is requested. waitForResourceNames(ctx, t, routeCfgCh, []string{newTestRouteConfigName}) // Update the old route configuration resource by adding a new route. - routes[0].VirtualHosts[0].Routes = append(routes[0].VirtualHosts[0].Routes, &v3routepb.Route{ + resources.Routes[0].VirtualHosts[0].Routes = append(resources.Routes[0].VirtualHosts[0].Routes, &v3routepb.Route{ Match: &v3routepb.RouteMatch{ PathSpecifier: &v3routepb.RouteMatch_Prefix{Prefix: "/foo/bar"}, CaseSensitive: &wrapperspb.BoolValue{Value: false}, @@ -81,17 +88,17 @@ func (s) TestServiceWatch_ListenerPointsToNewRouteConfiguration(t *testing.T) { }, }, }) - configureResourcesOnManagementServer(ctx, t, mgmtServer, nodeID, listeners, routes) + configureResourcesOnManagementServer(ctx, t, mgmtServer, nodeID, resources.Listeners, resources.Routes) // Wait for no update from the resolver. verifyNoUpdateFromResolver(ctx, t, stateCh) // Update the management server with the new route configuration resource. - routes = append(routes, e2e.DefaultRouteConfig(newTestRouteConfigName, defaultTestServiceName, defaultTestClusterName)) - configureResourcesOnManagementServer(ctx, t, mgmtServer, nodeID, listeners, routes) + resources.Routes = append(resources.Routes, e2e.DefaultRouteConfig(newTestRouteConfigName, defaultTestServiceName, resources.Clusters[0].Name)) + configureResourcesOnManagementServer(ctx, t, mgmtServer, nodeID, resources.Listeners, resources.Routes) // Ensure update from the resolver. - verifyUpdateFromResolver(ctx, t, stateCh, wantDefaultServiceConfig) + verifyUpdateFromResolver(ctx, t, stateCh, wantServiceConfig(resources.Clusters[0].Name)) } // Tests the case where the listener resource changes to contain an inline route @@ -106,22 +113,28 @@ func (s) TestServiceWatch_ListenerPointsToInlineRouteConfiguration(t *testing.T) mgmtServer, lisCh, routeCfgCh, bc := setupManagementServerForTest(t, nodeID) // Configure resources on the management server. - listeners := []*v3listenerpb.Listener{e2e.DefaultClientListener(defaultTestServiceName, defaultTestRouteConfigName)} - routes := []*v3routepb.RouteConfiguration{e2e.DefaultRouteConfig(defaultTestRouteConfigName, defaultTestServiceName, defaultTestClusterName)} - configureResourcesOnManagementServer(ctx, t, mgmtServer, nodeID, listeners, routes) - + resources := e2e.DefaultClientResources(e2e.ResourceParams{ + DialTarget: defaultTestServiceName, + NodeID: nodeID, + Host: defaultTestHostname, + Port: defaultTestPort[0], + SecLevel: e2e.SecurityLevelNone, + }) + if err := mgmtServer.Update(ctx, resources); err != nil { + t.Fatal(err) + } stateCh, _, _ := buildResolverForTarget(t, resolver.Target{URL: *testutils.MustParseURL("xds:///" + defaultTestServiceName)}, bc) // Verify initial update from the resolver. waitForResourceNames(ctx, t, lisCh, []string{defaultTestServiceName}) - waitForResourceNames(ctx, t, routeCfgCh, []string{defaultTestRouteConfigName}) - verifyUpdateFromResolver(ctx, t, stateCh, wantDefaultServiceConfig) + waitForResourceNames(ctx, t, routeCfgCh, []string{resources.Routes[0].Name}) + verifyUpdateFromResolver(ctx, t, stateCh, wantServiceConfig(resources.Clusters[0].Name)) // Update listener to contain an inline route configuration. hcm := testutils.MarshalAny(t, &v3httppb.HttpConnectionManager{ RouteSpecifier: &v3httppb.HttpConnectionManager_RouteConfig{ RouteConfig: &v3routepb.RouteConfiguration{ - Name: defaultTestRouteConfigName, + Name: resources.Routes[0].Name, VirtualHosts: []*v3routepb.VirtualHost{{ Domains: []string{defaultTestServiceName}, Routes: []*v3routepb.Route{{ @@ -130,7 +143,7 @@ func (s) TestServiceWatch_ListenerPointsToInlineRouteConfiguration(t *testing.T) }, Action: &v3routepb.Route_Route{ Route: &v3routepb.RouteAction{ - ClusterSpecifier: &v3routepb.RouteAction_Cluster{Cluster: defaultTestClusterName}, + ClusterSpecifier: &v3routepb.RouteAction_Cluster{Cluster: resources.Clusters[0].Name}, }, }, }}, @@ -139,7 +152,7 @@ func (s) TestServiceWatch_ListenerPointsToInlineRouteConfiguration(t *testing.T) }, HttpFilters: []*v3httppb.HttpFilter{e2e.HTTPFilter("router", &v3routerpb.Router{})}, }) - listeners = []*v3listenerpb.Listener{{ + resources.Listeners = []*v3listenerpb.Listener{{ Name: defaultTestServiceName, ApiListener: &v3listenerpb.ApiListener{ApiListener: hcm}, FilterChains: []*v3listenerpb.FilterChain{{ @@ -150,19 +163,19 @@ func (s) TestServiceWatch_ListenerPointsToInlineRouteConfiguration(t *testing.T) }}, }}, }} - configureResourcesOnManagementServer(ctx, t, mgmtServer, nodeID, listeners, nil) + configureResourcesOnManagementServer(ctx, t, mgmtServer, nodeID, resources.Listeners, nil) // Verify that the old route configuration is not requested anymore. waitForResourceNames(ctx, t, routeCfgCh, []string{}) - verifyUpdateFromResolver(ctx, t, stateCh, wantDefaultServiceConfig) + verifyUpdateFromResolver(ctx, t, stateCh, wantServiceConfig(resources.Clusters[0].Name)) // Update listener back to contain a route configuration name. - listeners = []*v3listenerpb.Listener{e2e.DefaultClientListener(defaultTestServiceName, defaultTestRouteConfigName)} - configureResourcesOnManagementServer(ctx, t, mgmtServer, nodeID, listeners, routes) + resources.Listeners = []*v3listenerpb.Listener{e2e.DefaultClientListener(defaultTestServiceName, resources.Routes[0].Name)} + configureResourcesOnManagementServer(ctx, t, mgmtServer, nodeID, resources.Listeners, resources.Routes) // Verify that that route configuration resource is requested. - waitForResourceNames(ctx, t, routeCfgCh, []string{defaultTestRouteConfigName}) + waitForResourceNames(ctx, t, routeCfgCh, []string{resources.Routes[0].Name}) // Verify that appropriate SC is pushed on the channel. - verifyUpdateFromResolver(ctx, t, stateCh, wantDefaultServiceConfig) + verifyUpdateFromResolver(ctx, t, stateCh, wantServiceConfig(resources.Clusters[0].Name)) } diff --git a/xds/internal/resolver/xds_resolver.go b/internal/xds/resolver/xds_resolver.go similarity index 99% rename from xds/internal/resolver/xds_resolver.go rename to internal/xds/resolver/xds_resolver.go index a66719d0685f..70291f8ce9bc 100644 --- a/xds/internal/resolver/xds_resolver.go +++ b/internal/xds/resolver/xds_resolver.go @@ -33,10 +33,10 @@ import ( iresolver "google.golang.org/grpc/internal/resolver" "google.golang.org/grpc/internal/wrr" "google.golang.org/grpc/internal/xds/bootstrap" + rinternal "google.golang.org/grpc/internal/xds/resolver/internal" + "google.golang.org/grpc/internal/xds/xdsclient" + "google.golang.org/grpc/internal/xds/xdsclient/xdsresource" "google.golang.org/grpc/resolver" - rinternal "google.golang.org/grpc/xds/internal/resolver/internal" - "google.golang.org/grpc/xds/internal/xdsclient" - "google.golang.org/grpc/xds/internal/xdsclient/xdsresource" ) // Scheme is the xDS resolver's scheme. diff --git a/xds/internal/resolver/xds_resolver_test.go b/internal/xds/resolver/xds_resolver_test.go similarity index 88% rename from xds/internal/resolver/xds_resolver_test.go rename to internal/xds/resolver/xds_resolver_test.go index 87b6b8b4555b..b28724d37383 100644 --- a/xds/internal/resolver/xds_resolver_test.go +++ b/internal/xds/resolver/xds_resolver_test.go @@ -22,6 +22,7 @@ import ( "context" "encoding/json" "fmt" + "net/url" "strings" "sync" "testing" @@ -38,15 +39,15 @@ import ( iringhash "google.golang.org/grpc/internal/ringhash" "google.golang.org/grpc/internal/testutils" "google.golang.org/grpc/internal/testutils/xds/e2e" + "google.golang.org/grpc/internal/xds/balancer/clustermanager" "google.golang.org/grpc/internal/xds/bootstrap" + "google.golang.org/grpc/internal/xds/httpfilter" + rinternal "google.golang.org/grpc/internal/xds/resolver/internal" + "google.golang.org/grpc/internal/xds/xdsclient" + "google.golang.org/grpc/internal/xds/xdsclient/xdsresource/version" "google.golang.org/grpc/metadata" "google.golang.org/grpc/resolver" "google.golang.org/grpc/serviceconfig" - "google.golang.org/grpc/xds/internal/balancer/clustermanager" - "google.golang.org/grpc/xds/internal/httpfilter" - rinternal "google.golang.org/grpc/xds/internal/resolver/internal" - "google.golang.org/grpc/xds/internal/xdsclient" - "google.golang.org/grpc/xds/internal/xdsclient/xdsresource/version" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/types/known/anypb" "google.golang.org/protobuf/types/known/durationpb" @@ -54,15 +55,17 @@ import ( "google.golang.org/protobuf/types/known/wrapperspb" v3xdsxdstypepb "github.com/cncf/xds/go/xds/type/v3" + v3clusterpb "github.com/envoyproxy/go-control-plane/envoy/config/cluster/v3" v3corepb "github.com/envoyproxy/go-control-plane/envoy/config/core/v3" + v3endpointpb "github.com/envoyproxy/go-control-plane/envoy/config/endpoint/v3" v3listenerpb "github.com/envoyproxy/go-control-plane/envoy/config/listener/v3" v3routepb "github.com/envoyproxy/go-control-plane/envoy/config/route/v3" v3routerpb "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/http/router/v3" v3httppb "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/network/http_connection_manager/v3" v3discoverypb "github.com/envoyproxy/go-control-plane/envoy/service/discovery/v3" - _ "google.golang.org/grpc/xds/internal/balancer/cdsbalancer" // Register the cds LB policy - _ "google.golang.org/grpc/xds/internal/httpfilter/router" // Register the router filter + _ "google.golang.org/grpc/internal/xds/balancer/cdsbalancer" // Register the cds LB policy + _ "google.golang.org/grpc/internal/xds/httpfilter/router" // Register the router filter ) // Tests the case where xDS client creation is expected to fail because the @@ -318,11 +321,46 @@ func (s) TestResolverBadServiceUpdate_NACKedWithoutCache(t *testing.T) { } configureResourcesOnManagementServer(ctx, t, mgmtServer, nodeID, []*v3listenerpb.Listener{lis}, nil) - // Build the resolver and expect an error update from it. Since the - // resource is not cached, it should be received as resource error. - _, errCh, _ := buildResolverForTarget(t, resolver.Target{URL: *testutils.MustParseURL("xds:///" + defaultTestServiceName)}, bc) - if err := waitForErrorFromResolver(ctx, errCh, "no RouteSpecifier", nodeID); err != nil { - t.Fatal(err) + // Build the resolver inline (duplicating buildResolverForTarget internals) + // to avoid issues with blocked channel writes when NACKs occur. + target := resolver.Target{URL: *testutils.MustParseURL("xds:///" + defaultTestServiceName)} + + // Create an xDS resolver with the provided bootstrap configuration. + if internal.NewXDSResolverWithConfigForTesting == nil { + t.Fatalf("internal.NewXDSResolverWithConfigForTesting is nil") + } + + builder, err := internal.NewXDSResolverWithConfigForTesting.(func([]byte) (resolver.Builder, error))(bc) + if err != nil { + t.Fatalf("Failed to create xDS resolver for testing: %v", err) + } + + errCh := testutils.NewChannel() + tcc := &testutils.ResolverClientConn{Logger: t, ReportErrorF: func(err error) { errCh.Replace(err) }} + r, err := builder.Build(target, tcc, resolver.BuildOptions{ + Authority: url.PathEscape(target.Endpoint()), + }) + if err != nil { + t.Fatalf("Failed to build xDS resolver for target %q: %v", target, err) + } + defer r.Close() + + // Wait for and verify the error update from the resolver. + // Since the resource is not cached, it should be received as resource error. + select { + case <-ctx.Done(): + t.Fatalf("Timeout waiting for error to be propagated to the ClientConn") + case gotErr := <-errCh.C: + if gotErr == nil { + t.Fatalf("got nil error from resolver, want error containing 'no RouteSpecifier'") + } + errStr := fmt.Sprint(gotErr) + if !strings.Contains(errStr, "no RouteSpecifier") { + t.Fatalf("got error from resolver %q, want error containing 'no RouteSpecifier'", errStr) + } + if !strings.Contains(errStr, nodeID) { + t.Fatalf("got error from resolver %q, want nodeID %q", errStr, nodeID) + } } } @@ -350,7 +388,7 @@ func (s) TestResolverBadServiceUpdate_NACKedWithCache(t *testing.T) { configureResourcesOnManagementServer(ctx, t, mgmtServer, nodeID, listeners, routes) // Expect a good update from the resolver. - cs := verifyUpdateFromResolver(ctx, t, stateCh, wantDefaultServiceConfig) + cs := verifyUpdateFromResolver(ctx, t, stateCh, wantServiceConfig(defaultTestClusterName)) // "Make an RPC" by invoking the config selector. _, err := cs.SelectConfig(iresolver.RPCInfo{Context: ctx, Method: "/service/method"}) @@ -400,6 +438,8 @@ func (s) TestResolverGoodServiceUpdate(t *testing.T) { for _, tt := range []struct { name string routeConfig *v3routepb.RouteConfiguration + clusterConfig []*v3clusterpb.Cluster + endpointConfig []*v3endpointpb.ClusterLoadAssignment wantServiceConfig string wantClusters map[string]bool }{ @@ -411,7 +451,9 @@ func (s) TestResolverGoodServiceUpdate(t *testing.T) { ClusterSpecifierType: e2e.RouteConfigClusterSpecifierTypeCluster, ClusterName: defaultTestClusterName, }), - wantServiceConfig: wantDefaultServiceConfig, + clusterConfig: []*v3clusterpb.Cluster{e2e.DefaultCluster(defaultTestClusterName, defaultTestEndpointName, e2e.SecurityLevelNone)}, + endpointConfig: []*v3endpointpb.ClusterLoadAssignment{e2e.DefaultEndpoint(defaultTestEndpointName, defaultTestHostname, defaultTestPort)}, + wantServiceConfig: wantServiceConfig(defaultTestClusterName), wantClusters: map[string]bool{fmt.Sprintf("cluster:%s", defaultTestClusterName): true}, }, { @@ -422,6 +464,12 @@ func (s) TestResolverGoodServiceUpdate(t *testing.T) { ClusterSpecifierType: e2e.RouteConfigClusterSpecifierTypeWeightedCluster, WeightedClusters: map[string]int{"cluster_1": 75, "cluster_2": 25}, }), + clusterConfig: []*v3clusterpb.Cluster{ + e2e.DefaultCluster("cluster_1", "endpoint_1", e2e.SecurityLevelNone), + e2e.DefaultCluster("cluster_2", "endpoint_2", e2e.SecurityLevelNone)}, + endpointConfig: []*v3endpointpb.ClusterLoadAssignment{ + e2e.DefaultEndpoint("endpoint_1", defaultTestHostname, defaultTestPort), + e2e.DefaultEndpoint("endpoint_2", defaultTestHostname, defaultTestPort)}, // This update contains the cluster from the previous update as well // as this update, as the previous config selector still references // the old cluster when the new one is pushed. @@ -460,7 +508,7 @@ func (s) TestResolverGoodServiceUpdate(t *testing.T) { // route configuration resource, as specified by the test case. listeners := []*v3listenerpb.Listener{e2e.DefaultClientListener(defaultTestServiceName, defaultTestRouteConfigName)} routes := []*v3routepb.RouteConfiguration{tt.routeConfig} - configureResourcesOnManagementServer(ctx, t, mgmtServer, nodeID, listeners, routes) + configureAllResourcesOnManagementServer(ctx, t, mgmtServer, nodeID, listeners, routes, tt.clusterConfig, tt.endpointConfig) stateCh, _, _ := buildResolverForTarget(t, resolver.Target{URL: *testutils.MustParseURL("xds:///" + defaultTestServiceName)}, bc) @@ -527,7 +575,9 @@ func (s) TestResolverRequestHash(t *testing.T) { }}, }}, }} - configureResourcesOnManagementServer(ctx, t, mgmtServer, nodeID, listeners, routes) + cluster := []*v3clusterpb.Cluster{e2e.DefaultCluster(defaultTestClusterName, defaultTestEndpointName, e2e.SecurityLevelNone)} + endpoints := []*v3endpointpb.ClusterLoadAssignment{e2e.DefaultEndpoint(defaultTestEndpointName, defaultTestHostname, defaultTestPort)} + configureAllResourcesOnManagementServer(ctx, t, mgmtServer, nodeID, listeners, routes, cluster, endpoints) // Build the resolver and read the config selector out of it. stateCh, _, _ := buildResolverForTarget(t, resolver.Target{URL: *testutils.MustParseURL("xds:///" + defaultTestServiceName)}, bc) @@ -564,14 +614,19 @@ func (s) TestResolverRemovedWithRPCs(t *testing.T) { mgmtServer, _, _, bc := setupManagementServerForTest(t, nodeID) // Configure resources on the management server. - listeners := []*v3listenerpb.Listener{e2e.DefaultClientListener(defaultTestServiceName, defaultTestRouteConfigName)} - routes := []*v3routepb.RouteConfiguration{e2e.DefaultRouteConfig(defaultTestRouteConfigName, defaultTestServiceName, defaultTestClusterName)} - configureResourcesOnManagementServer(ctx, t, mgmtServer, nodeID, listeners, routes) + resources := e2e.DefaultClientResources(e2e.ResourceParams{ + DialTarget: defaultTestServiceName, + NodeID: nodeID, + Host: defaultTestHostname, + Port: defaultTestPort[0], + SecLevel: e2e.SecurityLevelNone, + }) + mgmtServer.Update(ctx, resources) stateCh, _, _ := buildResolverForTarget(t, resolver.Target{URL: *testutils.MustParseURL("xds:///" + defaultTestServiceName)}, bc) // Read the update pushed by the resolver to the ClientConn. - cs := verifyUpdateFromResolver(ctx, t, stateCh, wantDefaultServiceConfig) + cs := verifyUpdateFromResolver(ctx, t, stateCh, wantServiceConfig(resources.Clusters[0].Name)) res, err := cs.SelectConfig(iresolver.RPCInfo{Context: ctx, Method: "/service/method"}) if err != nil { @@ -588,7 +643,7 @@ func (s) TestResolverRemovedWithRPCs(t *testing.T) { // not produce an empty service config at this point. Instead it will retain // the cluster to which the RPC is ongoing in the service config, but will // return an erroring config selector which will fail new RPCs. - cs = verifyUpdateFromResolver(ctx, t, stateCh, wantDefaultServiceConfig) + cs = verifyUpdateFromResolver(ctx, t, stateCh, wantServiceConfig(resources.Clusters[0].Name)) _, err = cs.SelectConfig(iresolver.RPCInfo{Context: ctx, Method: "/service/method"}) if err := verifyResolverError(err, codes.Unavailable, "has been removed", nodeID); err != nil { t.Fatal(err) @@ -628,14 +683,14 @@ waitForStateUpdate: sCtx, sCancel := context.WithTimeout(ctx, defaultTestShortTimeout) defer sCancel() - configureResourcesOnManagementServer(ctx, t, mgmtServer, nodeID, listeners, routes) + configureResourcesOnManagementServer(ctx, t, mgmtServer, nodeID, resources.Listeners, resources.Routes) select { case state = <-stateCh: if err := state.ServiceConfig.Err; err != nil { t.Fatalf("Received error in service config: %v", state.ServiceConfig.Err) } - wantSCParsed := internal.ParseServiceConfig.(func(string) *serviceconfig.ParseResult)(wantDefaultServiceConfig) + wantSCParsed := internal.ParseServiceConfig.(func(string) *serviceconfig.ParseResult)(wantServiceConfig(resources.Clusters[0].Name)) if !internal.EqualServiceConfigForTesting(state.ServiceConfig.Config, wantSCParsed.Config) { t.Fatalf("Got service config:\n%s \nWant service config:\n%s", cmp.Diff(nil, state.ServiceConfig.Config), cmp.Diff(nil, wantSCParsed.Config)) } @@ -666,14 +721,18 @@ func (s) TestResolverRemovedResource(t *testing.T) { mgmtServer, _, _, bc := setupManagementServerForTest(t, nodeID) // Configure resources on the management server. - listeners := []*v3listenerpb.Listener{e2e.DefaultClientListener(defaultTestServiceName, defaultTestRouteConfigName)} - routes := []*v3routepb.RouteConfiguration{e2e.DefaultRouteConfig(defaultTestRouteConfigName, defaultTestServiceName, defaultTestClusterName)} - configureResourcesOnManagementServer(ctx, t, mgmtServer, nodeID, listeners, routes) - + resources := e2e.DefaultClientResources(e2e.ResourceParams{ + DialTarget: defaultTestServiceName, + NodeID: nodeID, + Host: defaultTestHostname, + Port: defaultTestPort[0], + SecLevel: e2e.SecurityLevelNone, + }) + mgmtServer.Update(ctx, resources) stateCh, errCh, _ := buildResolverForTarget(t, resolver.Target{URL: *testutils.MustParseURL("xds:///" + defaultTestServiceName)}, bc) // Read the update pushed by the resolver to the ClientConn. - cs := verifyUpdateFromResolver(ctx, t, stateCh, wantDefaultServiceConfig) + cs := verifyUpdateFromResolver(ctx, t, stateCh, wantServiceConfig(resources.Clusters[0].Name)) // "Make an RPC" by invoking the config selector. res, err := cs.SelectConfig(iresolver.RPCInfo{Context: ctx, Method: "/service/method"}) @@ -693,7 +752,7 @@ func (s) TestResolverRemovedResource(t *testing.T) { // The channel should receive the existing service config with the original // cluster but with an erroring config selector. - cs = verifyUpdateFromResolver(ctx, t, stateCh, wantDefaultServiceConfig) + cs = verifyUpdateFromResolver(ctx, t, stateCh, wantServiceConfig(resources.Clusters[0].Name)) // "Make another RPC" by invoking the config selector. _, err = cs.SelectConfig(iresolver.RPCInfo{Context: ctx, Method: "/service/method"}) @@ -821,7 +880,17 @@ func (s) TestResolverMaxStreamDuration(t *testing.T) { }, }}, }} - configureResourcesOnManagementServer(ctx, t, mgmtServer, nodeID, listeners, routes) + cluster := []*v3clusterpb.Cluster{ + e2e.DefaultCluster("A", "endpoint_A", e2e.SecurityLevelNone), + e2e.DefaultCluster("B", "endpoint_B", e2e.SecurityLevelNone), + e2e.DefaultCluster("C", "endpoint_C", e2e.SecurityLevelNone), + } + endpoints := []*v3endpointpb.ClusterLoadAssignment{ + e2e.DefaultEndpoint("endpoint_A", defaultTestHostname, defaultTestPort), + e2e.DefaultEndpoint("endpoint_B", defaultTestHostname, defaultTestPort), + e2e.DefaultEndpoint("endpoint_C", defaultTestHostname, defaultTestPort), + } + configureAllResourcesOnManagementServer(ctx, t, mgmtServer, nodeID, listeners, routes, cluster, endpoints) // Read the update pushed by the resolver to the ClientConn. cs := verifyUpdateFromResolver(ctx, t, stateCh, "") @@ -873,33 +942,43 @@ func (s) TestResolverDelayedOnCommitted(t *testing.T) { mgmtServer, _, _, bc := setupManagementServerForTest(t, nodeID) // Configure resources on the management server. - listeners := []*v3listenerpb.Listener{e2e.DefaultClientListener(defaultTestServiceName, defaultTestRouteConfigName)} - routes := []*v3routepb.RouteConfiguration{e2e.DefaultRouteConfig(defaultTestRouteConfigName, defaultTestServiceName, defaultTestClusterName)} - configureResourcesOnManagementServer(ctx, t, mgmtServer, nodeID, listeners, routes) + resources := e2e.DefaultClientResources(e2e.ResourceParams{ + DialTarget: defaultTestServiceName, + NodeID: nodeID, + Host: defaultTestHostname, + Port: defaultTestPort[0], + SecLevel: e2e.SecurityLevelNone, + }) + mgmtServer.Update(ctx, resources) stateCh, _, _ := buildResolverForTarget(t, resolver.Target{URL: *testutils.MustParseURL("xds:///" + defaultTestServiceName)}, bc) // Read the update pushed by the resolver to the ClientConn. - cs := verifyUpdateFromResolver(ctx, t, stateCh, wantDefaultServiceConfig) + cs := verifyUpdateFromResolver(ctx, t, stateCh, wantServiceConfig(resources.Clusters[0].Name)) // Make an RPC, but do not commit it yet. resOld, err := cs.SelectConfig(iresolver.RPCInfo{Context: ctx, Method: "/service/method"}) if err != nil { t.Fatalf("cs.SelectConfig(): %v", err) } - wantClusterName := fmt.Sprintf("cluster:%s", defaultTestClusterName) + wantClusterName := fmt.Sprintf("cluster:%s", resources.Clusters[0].Name) if cluster := clustermanager.GetPickedClusterForTesting(resOld.Context); cluster != wantClusterName { t.Fatalf("Picked cluster is %q, want %q", cluster, wantClusterName) } // Delay resOld.OnCommitted(). As long as there are pending RPCs to removed // clusters, they still appear in the service config. - + oldClusterName := resources.Clusters[0].Name // Update the route configuration resource on the management server to // return a new cluster. newClusterName := "new-" + defaultTestClusterName - routes = []*v3routepb.RouteConfiguration{e2e.DefaultRouteConfig(defaultTestRouteConfigName, defaultTestServiceName, newClusterName)} - configureResourcesOnManagementServer(ctx, t, mgmtServer, nodeID, listeners, routes) + newEndpointName := "new-" + defaultTestEndpointName + resources.Routes = []*v3routepb.RouteConfiguration{e2e.DefaultRouteConfig(resources.Routes[0].Name, defaultTestServiceName, newClusterName)} + resources.Clusters = []*v3clusterpb.Cluster{e2e.DefaultCluster(newClusterName, newEndpointName, e2e.SecurityLevelNone)} + resources.Endpoints = []*v3endpointpb.ClusterLoadAssignment{e2e.DefaultEndpoint(newEndpointName, defaultTestHostname, defaultTestPort)} + if err := mgmtServer.Update(ctx, resources); err != nil { + t.Fatal(err) + } // Read the update pushed by the resolver to the ClientConn and ensure the // old cluster is present in the service config. Also ensure that the newly @@ -932,7 +1011,7 @@ func (s) TestResolverDelayedOnCommitted(t *testing.T) { } } ] -}`, defaultTestClusterName, defaultTestClusterName, newClusterName, newClusterName) +}`, oldClusterName, oldClusterName, newClusterName, newClusterName) cs = verifyUpdateFromResolver(ctx, t, stateCh, wantSC) resNew, err := cs.SelectConfig(iresolver.RPCInfo{Context: ctx, Method: "/service/method"}) @@ -1050,7 +1129,15 @@ func (s) TestResolverWRR(t *testing.T) { ClusterSpecifierType: e2e.RouteConfigClusterSpecifierTypeWeightedCluster, WeightedClusters: map[string]int{"A": 75, "B": 25}, })} - configureResourcesOnManagementServer(ctx, t, mgmtServer, nodeID, listeners, routes) + clusters := []*v3clusterpb.Cluster{ + e2e.DefaultCluster("A", "endpoint_A", e2e.SecurityLevelNone), + e2e.DefaultCluster("B", "endpoint_B", e2e.SecurityLevelNone), + } + endpoints := []*v3endpointpb.ClusterLoadAssignment{ + e2e.DefaultEndpoint("endpoint_A", defaultTestHostname, defaultTestPort), + e2e.DefaultEndpoint("endpoint_B", defaultTestHostname, defaultTestPort), + } + configureAllResourcesOnManagementServer(ctx, t, mgmtServer, nodeID, listeners, routes, clusters, endpoints) // Read the update pushed by the resolver to the ClientConn. cs := verifyUpdateFromResolver(ctx, t, stateCh, "") @@ -1481,9 +1568,17 @@ func (s) TestXDSResolverHTTPFilters(t *testing.T) { // Build an xDS resolver. stateCh, _, _ := buildResolverForTarget(t, resolver.Target{URL: *testutils.MustParseURL("xds:///" + defaultTestServiceName)}, bc) + cluster := []*v3clusterpb.Cluster{ + e2e.DefaultCluster("A", "endpoint_A", e2e.SecurityLevelNone), + e2e.DefaultCluster("B", "endpoint_B", e2e.SecurityLevelNone), + } + endpoints := []*v3endpointpb.ClusterLoadAssignment{ + e2e.DefaultEndpoint("endpoint_A", defaultTestHostname, defaultTestPort), + e2e.DefaultEndpoint("endpoint_B", defaultTestHostname, defaultTestPort), + } // Update the management server with a listener resource that // contains an inline route configuration. - configureResourcesOnManagementServer(ctx, t, mgmtServer, nodeID, []*v3listenerpb.Listener{tc.listener}, nil) + configureAllResourcesOnManagementServer(ctx, t, mgmtServer, nodeID, []*v3listenerpb.Listener{tc.listener}, nil, cluster, endpoints) // Ensure that the resolver pushes a state update to the channel. cs := verifyUpdateFromResolver(ctx, t, stateCh, "") diff --git a/xds/internal/server/conn_wrapper.go b/internal/xds/server/conn_wrapper.go similarity index 99% rename from xds/internal/server/conn_wrapper.go rename to internal/xds/server/conn_wrapper.go index 92d07e7fb6d1..840da7ca68fd 100644 --- a/xds/internal/server/conn_wrapper.go +++ b/internal/xds/server/conn_wrapper.go @@ -28,7 +28,7 @@ import ( "google.golang.org/grpc/credentials/tls/certprovider" xdsinternal "google.golang.org/grpc/internal/credentials/xds" "google.golang.org/grpc/internal/transport" - "google.golang.org/grpc/xds/internal/xdsclient/xdsresource" + "google.golang.org/grpc/internal/xds/xdsclient/xdsresource" ) // connWrapper is a thin wrapper around a net.Conn returned by Accept(). It diff --git a/xds/internal/server/listener_wrapper.go b/internal/xds/server/listener_wrapper.go similarity index 99% rename from xds/internal/server/listener_wrapper.go rename to internal/xds/server/listener_wrapper.go index 2c32ace8ab05..1f7da61175e6 100644 --- a/xds/internal/server/listener_wrapper.go +++ b/internal/xds/server/listener_wrapper.go @@ -33,7 +33,7 @@ import ( internalgrpclog "google.golang.org/grpc/internal/grpclog" "google.golang.org/grpc/internal/grpcsync" "google.golang.org/grpc/internal/xds/bootstrap" - "google.golang.org/grpc/xds/internal/xdsclient/xdsresource" + "google.golang.org/grpc/internal/xds/xdsclient/xdsresource" ) var ( diff --git a/xds/internal/server/rds_handler.go b/internal/xds/server/rds_handler.go similarity index 98% rename from xds/internal/server/rds_handler.go rename to internal/xds/server/rds_handler.go index 4b8eb22de8db..bf78c37c8292 100644 --- a/xds/internal/server/rds_handler.go +++ b/internal/xds/server/rds_handler.go @@ -22,7 +22,7 @@ import ( "sync" igrpclog "google.golang.org/grpc/internal/grpclog" - "google.golang.org/grpc/xds/internal/xdsclient/xdsresource" + "google.golang.org/grpc/internal/xds/xdsclient/xdsresource" ) // rdsHandler handles any RDS queries that need to be started for a given server diff --git a/xds/internal/server/rds_handler_test.go b/internal/xds/server/rds_handler_test.go similarity index 98% rename from xds/internal/server/rds_handler_test.go rename to internal/xds/server/rds_handler_test.go index 886cf535363d..429ccaa1253b 100644 --- a/xds/internal/server/rds_handler_test.go +++ b/internal/xds/server/rds_handler_test.go @@ -30,8 +30,8 @@ import ( "google.golang.org/grpc/internal/grpctest" "google.golang.org/grpc/internal/testutils/xds/e2e" "google.golang.org/grpc/internal/xds/bootstrap" - "google.golang.org/grpc/xds/internal/xdsclient" - "google.golang.org/grpc/xds/internal/xdsclient/xdsresource/version" + "google.golang.org/grpc/internal/xds/xdsclient" + "google.golang.org/grpc/internal/xds/xdsclient/xdsresource/version" v3routepb "github.com/envoyproxy/go-control-plane/envoy/config/route/v3" v3discoverypb "github.com/envoyproxy/go-control-plane/envoy/service/discovery/v3" diff --git a/xds/internal/test/e2e/README.md b/internal/xds/test/e2e/README.md similarity index 100% rename from xds/internal/test/e2e/README.md rename to internal/xds/test/e2e/README.md diff --git a/xds/internal/test/e2e/controlplane.go b/internal/xds/test/e2e/controlplane.go similarity index 100% rename from xds/internal/test/e2e/controlplane.go rename to internal/xds/test/e2e/controlplane.go diff --git a/xds/internal/test/e2e/e2e.go b/internal/xds/test/e2e/e2e.go similarity index 100% rename from xds/internal/test/e2e/e2e.go rename to internal/xds/test/e2e/e2e.go diff --git a/xds/internal/test/e2e/e2e_test.go b/internal/xds/test/e2e/e2e_test.go similarity index 100% rename from xds/internal/test/e2e/e2e_test.go rename to internal/xds/test/e2e/e2e_test.go diff --git a/xds/internal/test/e2e/e2e_utils.go b/internal/xds/test/e2e/e2e_utils.go similarity index 100% rename from xds/internal/test/e2e/e2e_utils.go rename to internal/xds/test/e2e/e2e_utils.go diff --git a/xds/internal/test/e2e/run.sh b/internal/xds/test/e2e/run.sh similarity index 100% rename from xds/internal/test/e2e/run.sh rename to internal/xds/test/e2e/run.sh diff --git a/xds/internal/testutils/balancer_test.go b/internal/xds/testutils/balancer_test.go similarity index 100% rename from xds/internal/testutils/balancer_test.go rename to internal/xds/testutils/balancer_test.go diff --git a/xds/internal/testutils/fakeclient/client.go b/internal/xds/testutils/fakeclient/client.go similarity index 96% rename from xds/internal/testutils/fakeclient/client.go rename to internal/xds/testutils/fakeclient/client.go index bfcbf5ae9eb0..fa465139ee94 100644 --- a/xds/internal/testutils/fakeclient/client.go +++ b/internal/xds/testutils/fakeclient/client.go @@ -24,9 +24,9 @@ import ( "google.golang.org/grpc/internal/testutils" "google.golang.org/grpc/internal/xds/bootstrap" - "google.golang.org/grpc/xds/internal/clients" - "google.golang.org/grpc/xds/internal/clients/lrsclient" - "google.golang.org/grpc/xds/internal/xdsclient" + "google.golang.org/grpc/internal/xds/clients" + "google.golang.org/grpc/internal/xds/clients/lrsclient" + "google.golang.org/grpc/internal/xds/xdsclient" ) // Client is a fake implementation of an xds client. It exposes a bunch of diff --git a/xds/internal/testutils/resource_watcher.go b/internal/xds/testutils/resource_watcher.go similarity index 97% rename from xds/internal/testutils/resource_watcher.go rename to internal/xds/testutils/resource_watcher.go index e8f7830a7641..9feb8d2a5d1e 100644 --- a/xds/internal/testutils/resource_watcher.go +++ b/internal/xds/testutils/resource_watcher.go @@ -18,7 +18,7 @@ package testutils -import "google.golang.org/grpc/xds/internal/xdsclient/xdsresource" +import "google.golang.org/grpc/internal/xds/xdsclient/xdsresource" // TestResourceWatcher implements the xdsresource.ResourceWatcher interface, // used to receive updates on watches registered with the xDS client, when using diff --git a/xds/internal/testutils/testutils.go b/internal/xds/testutils/testutils.go similarity index 92% rename from xds/internal/testutils/testutils.go rename to internal/xds/testutils/testutils.go index 15049b6a6041..d806dec1e752 100644 --- a/xds/internal/testutils/testutils.go +++ b/internal/xds/testutils/testutils.go @@ -19,8 +19,8 @@ package testutils import ( - "google.golang.org/grpc/xds/internal/xdsclient/xdsresource" - "google.golang.org/grpc/xds/internal/xdsclient/xdsresource/version" + "google.golang.org/grpc/internal/xds/xdsclient/xdsresource" + "google.golang.org/grpc/internal/xds/xdsclient/xdsresource/version" ) // BuildResourceName returns the resource name in the format of an xdstp:// diff --git a/internal/xds/xds.go b/internal/xds/xds.go index 024c388b7aa7..b9a4ec90a5ed 100644 --- a/internal/xds/xds.go +++ b/internal/xds/xds.go @@ -14,12 +14,17 @@ * limitations under the License. */ -// Package xds contains methods to Get/Set handshake cluster names. It is separated -// out from the top level /internal package to avoid circular dependencies. +// Package xds contains functions, structs, and utilities for working with +// handshake cluster names, as well as shared components used by xds balancers +// and resolvers. It is separated from the top-level /internal package to +// avoid circular dependencies. package xds import ( + "fmt" + "google.golang.org/grpc/attributes" + "google.golang.org/grpc/internal/xds/clients" "google.golang.org/grpc/resolver" ) @@ -40,3 +45,60 @@ func GetXDSHandshakeClusterName(attr *attributes.Attributes) (string, bool) { name, ok := v.(string) return name, ok } + +// LocalityString generates a string representation of clients.Locality in the +// format specified in gRFC A76. +func LocalityString(l clients.Locality) string { + return fmt.Sprintf("{region=%q, zone=%q, sub_zone=%q}", l.Region, l.Zone, l.SubZone) +} + +// IsLocalityEqual allows the values to be compared by Attributes.Equal. +func IsLocalityEqual(l clients.Locality, o any) bool { + ol, ok := o.(clients.Locality) + if !ok { + return false + } + return l.Region == ol.Region && l.Zone == ol.Zone && l.SubZone == ol.SubZone +} + +// LocalityFromString converts a string representation of clients.locality as +// specified in gRFC A76, into a LocalityID struct. +func LocalityFromString(s string) (ret clients.Locality, _ error) { + _, err := fmt.Sscanf(s, "{region=%q, zone=%q, sub_zone=%q}", &ret.Region, &ret.Zone, &ret.SubZone) + if err != nil { + return clients.Locality{}, fmt.Errorf("%s is not a well formatted locality ID, error: %v", s, err) + } + return ret, nil +} + +type localityKeyType string + +const localityKey = localityKeyType("grpc.xds.internal.address.locality") + +// GetLocalityID returns the locality ID of addr. +func GetLocalityID(addr resolver.Address) clients.Locality { + path, _ := addr.BalancerAttributes.Value(localityKey).(clients.Locality) + return path +} + +// SetLocalityID sets locality ID in addr to l. +func SetLocalityID(addr resolver.Address, l clients.Locality) resolver.Address { + addr.BalancerAttributes = addr.BalancerAttributes.WithValue(localityKey, l) + return addr +} + +// SetLocalityIDInEndpoint sets locality ID in endpoint to l. +func SetLocalityIDInEndpoint(endpoint resolver.Endpoint, l clients.Locality) resolver.Endpoint { + endpoint.Attributes = endpoint.Attributes.WithValue(localityKey, l) + return endpoint +} + +// ResourceTypeMapForTesting maps TypeUrl to corresponding ResourceType. +var ResourceTypeMapForTesting map[string]any + +// UnknownCSMLabels are TelemetryLabels emitted from CDS if CSM Telemetry Label +// data is not present in the CDS Resource. +var UnknownCSMLabels = map[string]string{ + "csm.service_name": "unknown", + "csm.service_namespace_name": "unknown", +} diff --git a/xds/internal/internal_test.go b/internal/xds/xds_test.go similarity index 97% rename from xds/internal/internal_test.go rename to internal/xds/xds_test.go index 2f6893b5c657..659be1206736 100644 --- a/xds/internal/internal_test.go +++ b/internal/xds/xds_test.go @@ -15,7 +15,7 @@ * limitations under the License. */ -package internal +package xds import ( "reflect" @@ -26,7 +26,7 @@ import ( corepb "github.com/envoyproxy/go-control-plane/envoy/api/v2/core" "github.com/google/go-cmp/cmp" "google.golang.org/grpc/internal/grpctest" - "google.golang.org/grpc/xds/internal/clients" + "google.golang.org/grpc/internal/xds/clients" ) const ignorePrefix = "XXX_" diff --git a/xds/internal/xdsclient/attributes.go b/internal/xds/xdsclient/attributes.go similarity index 100% rename from xds/internal/xdsclient/attributes.go rename to internal/xds/xdsclient/attributes.go diff --git a/xds/internal/xdsclient/client.go b/internal/xds/xdsclient/client.go similarity index 95% rename from xds/internal/xdsclient/client.go rename to internal/xds/xdsclient/client.go index 42f1a28f0c08..514273164402 100644 --- a/xds/internal/xdsclient/client.go +++ b/internal/xds/xdsclient/client.go @@ -25,8 +25,8 @@ import ( v3statuspb "github.com/envoyproxy/go-control-plane/envoy/service/status/v3" "google.golang.org/grpc/internal/xds/bootstrap" - "google.golang.org/grpc/xds/internal/clients/lrsclient" - "google.golang.org/grpc/xds/internal/xdsclient/xdsresource" + "google.golang.org/grpc/internal/xds/clients/lrsclient" + "google.golang.org/grpc/internal/xds/xdsclient/xdsresource" ) // XDSClient is a full fledged gRPC client which queries a set of discovery APIs diff --git a/xds/internal/xdsclient/client_refcounted_test.go b/internal/xds/xdsclient/client_refcounted_test.go similarity index 100% rename from xds/internal/xdsclient/client_refcounted_test.go rename to internal/xds/xdsclient/client_refcounted_test.go diff --git a/xds/internal/xdsclient/client_test.go b/internal/xds/xdsclient/client_test.go similarity index 100% rename from xds/internal/xdsclient/client_test.go rename to internal/xds/xdsclient/client_test.go diff --git a/xds/internal/xdsclient/clientimpl.go b/internal/xds/xdsclient/clientimpl.go similarity index 87% rename from xds/internal/xdsclient/clientimpl.go rename to internal/xds/xdsclient/clientimpl.go index f7610341a787..b1f797993fd7 100644 --- a/xds/internal/xdsclient/clientimpl.go +++ b/internal/xds/xdsclient/clientimpl.go @@ -29,12 +29,12 @@ import ( "google.golang.org/grpc/internal/grpclog" "google.golang.org/grpc/internal/xds/bootstrap" + "google.golang.org/grpc/internal/xds/clients" + "google.golang.org/grpc/internal/xds/clients/grpctransport" + "google.golang.org/grpc/internal/xds/clients/lrsclient" + "google.golang.org/grpc/internal/xds/clients/xdsclient" + "google.golang.org/grpc/internal/xds/clients/xdsclient/metrics" xdsbootstrap "google.golang.org/grpc/xds/bootstrap" - "google.golang.org/grpc/xds/internal/clients" - "google.golang.org/grpc/xds/internal/clients/grpctransport" - "google.golang.org/grpc/xds/internal/clients/lrsclient" - "google.golang.org/grpc/xds/internal/clients/xdsclient" - "google.golang.org/grpc/xds/internal/clients/xdsclient/metrics" ) const ( @@ -120,8 +120,8 @@ func (mr *metricsReporter) ReportMetric(metric any) { } } -func newClientImpl(config *bootstrap.Config, metricsRecorder estats.MetricsRecorder, target string) (*clientImpl, error) { - gConfig, err := buildXDSClientConfig(config, metricsRecorder, target) +func newClientImpl(config *bootstrap.Config, metricsRecorder estats.MetricsRecorder, target string, watchExpiryTimeout time.Duration) (*clientImpl, error) { + gConfig, err := buildXDSClientConfig(config, metricsRecorder, target, watchExpiryTimeout) if err != nil { return nil, err } @@ -129,7 +129,21 @@ func newClientImpl(config *bootstrap.Config, metricsRecorder estats.MetricsRecor if err != nil { return nil, err } - c := &clientImpl{XDSClient: client, xdsClientConfig: gConfig, bootstrapConfig: config, target: target, refCount: 1} + lrsC, err := lrsclient.New(lrsclient.Config{ + Node: gConfig.Node, + TransportBuilder: gConfig.TransportBuilder, + }) + if err != nil { + return nil, err + } + c := &clientImpl{ + XDSClient: client, + xdsClientConfig: gConfig, + bootstrapConfig: config, + target: target, + refCount: 1, + lrsClient: lrsC, + } c.logger = prefixLogger(c) return c, nil } @@ -149,7 +163,7 @@ func (c *clientImpl) decrRef() int32 { } // buildXDSClientConfig builds the xdsclient.Config from the bootstrap.Config. -func buildXDSClientConfig(config *bootstrap.Config, metricsRecorder estats.MetricsRecorder, target string) (xdsclient.Config, error) { +func buildXDSClientConfig(config *bootstrap.Config, metricsRecorder estats.MetricsRecorder, target string, watchExpiryTimeout time.Duration) (xdsclient.Config, error) { grpcTransportConfigs := make(map[string]grpctransport.Config) gServerCfgMap := make(map[xdsclient.ServerConfig]*bootstrap.ServerConfig) @@ -204,12 +218,13 @@ func buildXDSClientConfig(config *bootstrap.Config, metricsRecorder estats.Metri } return xdsclient.Config{ - Authorities: gAuthorities, - Servers: gServerCfgs, - Node: gNode, - TransportBuilder: grpctransport.NewBuilder(grpcTransportConfigs), - ResourceTypes: supportedResourceTypes(config, gServerCfgMap), - MetricsReporter: &metricsReporter{recorder: metricsRecorder, target: target}, + Authorities: gAuthorities, + Servers: gServerCfgs, + Node: gNode, + TransportBuilder: grpctransport.NewBuilder(grpcTransportConfigs), + ResourceTypes: supportedResourceTypes(config, gServerCfgMap), + MetricsReporter: &metricsReporter{recorder: metricsRecorder, target: target}, + WatchExpiryTimeout: watchExpiryTimeout, }, nil } diff --git a/xds/internal/xdsclient/clientimpl_loadreport.go b/internal/xds/xdsclient/clientimpl_loadreport.go similarity index 73% rename from xds/internal/xdsclient/clientimpl_loadreport.go rename to internal/xds/xdsclient/clientimpl_loadreport.go index 39004ae7ef77..ffd0c90b8f54 100644 --- a/xds/internal/xdsclient/clientimpl_loadreport.go +++ b/internal/xds/xdsclient/clientimpl_loadreport.go @@ -22,9 +22,9 @@ import ( "sync" "google.golang.org/grpc/internal/xds/bootstrap" - "google.golang.org/grpc/xds/internal/clients" - "google.golang.org/grpc/xds/internal/clients/grpctransport" - "google.golang.org/grpc/xds/internal/clients/lrsclient" + "google.golang.org/grpc/internal/xds/clients" + "google.golang.org/grpc/internal/xds/clients/grpctransport" + "google.golang.org/grpc/internal/xds/clients/lrsclient" ) // ReportLoad starts a load reporting stream to the given server. All load @@ -32,18 +32,6 @@ import ( // // It returns a lrsclient.LoadStore for the user to report loads. func (c *clientImpl) ReportLoad(server *bootstrap.ServerConfig) (*lrsclient.LoadStore, func(context.Context)) { - if c.lrsClient == nil { - lrsC, err := lrsclient.New(lrsclient.Config{ - Node: c.xdsClientConfig.Node, - TransportBuilder: c.xdsClientConfig.TransportBuilder, - }) - if err != nil { - c.logger.Warningf("Failed to create an lrs client to the management server to report load: %v", server, err) - return nil, func(context.Context) {} - } - c.lrsClient = lrsC - } - load, err := c.lrsClient.ReportLoad(clients.ServerIdentifier{ ServerURI: server.ServerURI(), Extensions: grpctransport.ServerIdentifierExtension{ diff --git a/xds/internal/xdsclient/clientimpl_test.go b/internal/xds/xdsclient/clientimpl_test.go similarity index 97% rename from xds/internal/xdsclient/clientimpl_test.go rename to internal/xds/xdsclient/clientimpl_test.go index fbfc24a074ec..d2fc8f7f9332 100644 --- a/xds/internal/xdsclient/clientimpl_test.go +++ b/internal/xds/xdsclient/clientimpl_test.go @@ -31,11 +31,11 @@ import ( "google.golang.org/grpc/credentials/insecure" "google.golang.org/grpc/internal/testutils/stats" "google.golang.org/grpc/internal/xds/bootstrap" - "google.golang.org/grpc/xds/internal/clients" - "google.golang.org/grpc/xds/internal/clients/grpctransport" - "google.golang.org/grpc/xds/internal/clients/xdsclient" - "google.golang.org/grpc/xds/internal/xdsclient/xdsresource" - "google.golang.org/grpc/xds/internal/xdsclient/xdsresource/version" + "google.golang.org/grpc/internal/xds/clients" + "google.golang.org/grpc/internal/xds/clients/grpctransport" + "google.golang.org/grpc/internal/xds/clients/xdsclient" + "google.golang.org/grpc/internal/xds/xdsclient/xdsresource" + "google.golang.org/grpc/internal/xds/xdsclient/xdsresource/version" "google.golang.org/protobuf/testing/protocmp" ) @@ -208,7 +208,7 @@ func (s) TestBuildXDSClientConfig_Success(t *testing.T) { if err != nil { t.Fatalf("Failed to create bootstrap config: %v", err) } - gotCfg, err := buildXDSClientConfig(bootstrapConfig, stats.NewTestMetricsRecorder(), testTargetName) + gotCfg, err := buildXDSClientConfig(bootstrapConfig, stats.NewTestMetricsRecorder(), testTargetName, 0) if err != nil { t.Fatalf("Failed to build XDSClientConfig: %v", err) } diff --git a/xds/internal/xdsclient/clientimpl_watchers.go b/internal/xds/xdsclient/clientimpl_watchers.go similarity index 95% rename from xds/internal/xdsclient/clientimpl_watchers.go rename to internal/xds/xdsclient/clientimpl_watchers.go index 29435993f135..398de1ed73b6 100644 --- a/xds/internal/xdsclient/clientimpl_watchers.go +++ b/internal/xds/xdsclient/clientimpl_watchers.go @@ -18,7 +18,7 @@ package xdsclient import ( - "google.golang.org/grpc/xds/internal/xdsclient/xdsresource" + "google.golang.org/grpc/internal/xds/xdsclient/xdsresource" ) // WatchResource uses xDS to discover the resource associated with the provided diff --git a/xds/internal/xdsclient/internal/internal.go b/internal/xds/xdsclient/internal/internal.go similarity index 100% rename from xds/internal/xdsclient/internal/internal.go rename to internal/xds/xdsclient/internal/internal.go diff --git a/xds/internal/xdsclient/logging.go b/internal/xds/xdsclient/logging.go similarity index 100% rename from xds/internal/xdsclient/logging.go rename to internal/xds/xdsclient/logging.go diff --git a/xds/internal/xdsclient/metrics_test.go b/internal/xds/xdsclient/metrics_test.go similarity index 99% rename from xds/internal/xdsclient/metrics_test.go rename to internal/xds/xdsclient/metrics_test.go index f876aa1a9831..26a38aea381e 100644 --- a/xds/internal/xdsclient/metrics_test.go +++ b/internal/xds/xdsclient/metrics_test.go @@ -30,12 +30,12 @@ import ( "google.golang.org/grpc/internal/testutils/stats" "google.golang.org/grpc/internal/testutils/xds/e2e" "google.golang.org/grpc/internal/xds/bootstrap" - "google.golang.org/grpc/xds/internal/xdsclient/xdsresource" + "google.golang.org/grpc/internal/xds/xdsclient/xdsresource" v3listenerpb "github.com/envoyproxy/go-control-plane/envoy/config/listener/v3" v3discoverypb "github.com/envoyproxy/go-control-plane/envoy/service/discovery/v3" - _ "google.golang.org/grpc/xds/internal/httpfilter/router" // Register the router filter. + _ "google.golang.org/grpc/internal/xds/httpfilter/router" // Register the router filter. ) type noopListenerWatcher struct{} diff --git a/xds/internal/xdsclient/pool.go b/internal/xds/xdsclient/pool.go similarity index 97% rename from xds/internal/xdsclient/pool.go rename to internal/xds/xdsclient/pool.go index d1cc84762307..eb0197e09a7f 100644 --- a/xds/internal/xdsclient/pool.go +++ b/internal/xds/xdsclient/pool.go @@ -99,7 +99,7 @@ func NewPool(config *bootstrap.Config) *Pool { // expected to invoke once they are done using the client. It is safe for the // caller to invoke this close function multiple times. func (p *Pool) NewClient(name string, metricsRecorder estats.MetricsRecorder) (XDSClient, func(), error) { - return p.newRefCounted(name, metricsRecorder) + return p.newRefCounted(name, metricsRecorder, defaultWatchExpiryTimeout) } // NewClientForTesting returns an xDS client configured with the provided @@ -126,11 +126,10 @@ func (p *Pool) NewClientForTesting(opts OptionsForTesting) (XDSClient, func(), e if opts.MetricsRecorder == nil { opts.MetricsRecorder = istats.NewMetricsRecorderList(nil) } - c, cancel, err := p.newRefCounted(opts.Name, opts.MetricsRecorder) + c, cancel, err := p.newRefCounted(opts.Name, opts.MetricsRecorder, opts.WatchExpiryTimeout) if err != nil { return nil, nil, err } - c.SetWatchExpiryTimeoutForTesting(opts.WatchExpiryTimeout) return c, cancel, nil } @@ -252,7 +251,7 @@ func (p *Pool) clientRefCountedClose(name string) { // newRefCounted creates a new reference counted xDS client implementation for // name, if one does not exist already. If an xDS client for the given name // exists, it gets a reference to it and returns it. -func (p *Pool) newRefCounted(name string, metricsRecorder estats.MetricsRecorder) (*clientImpl, func(), error) { +func (p *Pool) newRefCounted(name string, metricsRecorder estats.MetricsRecorder, watchExpiryTimeout time.Duration) (*clientImpl, func(), error) { p.mu.Lock() defer p.mu.Unlock() @@ -276,7 +275,7 @@ func (p *Pool) newRefCounted(name string, metricsRecorder estats.MetricsRecorder return c, sync.OnceFunc(func() { p.clientRefCountedClose(name) }), nil } - c, err := newClientImpl(config, metricsRecorder, name) + c, err := newClientImpl(config, metricsRecorder, name, watchExpiryTimeout) if err != nil { return nil, nil, err } diff --git a/xds/internal/xdsclient/pool/pool_ext_test.go b/internal/xds/xdsclient/pool/pool_ext_test.go similarity index 99% rename from xds/internal/xdsclient/pool/pool_ext_test.go rename to internal/xds/xdsclient/pool/pool_ext_test.go index 6bd00b15f41c..2150a2703f8b 100644 --- a/xds/internal/xdsclient/pool/pool_ext_test.go +++ b/internal/xds/xdsclient/pool/pool_ext_test.go @@ -34,8 +34,8 @@ import ( "google.golang.org/grpc/internal/testutils/stats" "google.golang.org/grpc/internal/testutils/xds/e2e" "google.golang.org/grpc/internal/xds/bootstrap" + "google.golang.org/grpc/internal/xds/xdsclient" _ "google.golang.org/grpc/xds" - "google.golang.org/grpc/xds/internal/xdsclient" v3clusterpb "github.com/envoyproxy/go-control-plane/envoy/config/cluster/v3" v3endpointpb "github.com/envoyproxy/go-control-plane/envoy/config/endpoint/v3" diff --git a/xds/internal/xdsclient/requests_counter.go b/internal/xds/xdsclient/requests_counter.go similarity index 100% rename from xds/internal/xdsclient/requests_counter.go rename to internal/xds/xdsclient/requests_counter.go diff --git a/xds/internal/xdsclient/requests_counter_test.go b/internal/xds/xdsclient/requests_counter_test.go similarity index 100% rename from xds/internal/xdsclient/requests_counter_test.go rename to internal/xds/xdsclient/requests_counter_test.go diff --git a/xds/internal/xdsclient/resource_types.go b/internal/xds/xdsclient/resource_types.go similarity index 91% rename from xds/internal/xdsclient/resource_types.go rename to internal/xds/xdsclient/resource_types.go index 2f76c83c8445..88451ab8257e 100644 --- a/xds/internal/xdsclient/resource_types.go +++ b/internal/xds/xdsclient/resource_types.go @@ -19,9 +19,9 @@ package xdsclient import ( "google.golang.org/grpc/internal/xds/bootstrap" - "google.golang.org/grpc/xds/internal/clients/xdsclient" - "google.golang.org/grpc/xds/internal/xdsclient/xdsresource" - "google.golang.org/grpc/xds/internal/xdsclient/xdsresource/version" + "google.golang.org/grpc/internal/xds/clients/xdsclient" + "google.golang.org/grpc/internal/xds/xdsclient/xdsresource" + "google.golang.org/grpc/internal/xds/xdsclient/xdsresource/version" ) func supportedResourceTypes(config *bootstrap.Config, gServerCfgMap map[xdsclient.ServerConfig]*bootstrap.ServerConfig) map[string]xdsclient.ResourceType { diff --git a/xds/internal/xdsclient/tests/ads_stream_ack_nack_test.go b/internal/xds/xdsclient/tests/ads_stream_ack_nack_test.go similarity index 99% rename from xds/internal/xdsclient/tests/ads_stream_ack_nack_test.go rename to internal/xds/xdsclient/tests/ads_stream_ack_nack_test.go index 09e9b39edc0d..29ddae55aa47 100644 --- a/xds/internal/xdsclient/tests/ads_stream_ack_nack_test.go +++ b/internal/xds/xdsclient/tests/ads_stream_ack_nack_test.go @@ -31,8 +31,8 @@ import ( "google.golang.org/grpc/internal/testutils" "google.golang.org/grpc/internal/testutils/xds/e2e" "google.golang.org/grpc/internal/xds/bootstrap" - "google.golang.org/grpc/xds/internal/xdsclient" - "google.golang.org/grpc/xds/internal/xdsclient/xdsresource" + "google.golang.org/grpc/internal/xds/xdsclient" + "google.golang.org/grpc/internal/xds/xdsclient/xdsresource" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/testing/protocmp" diff --git a/xds/internal/xdsclient/tests/ads_stream_restart_test.go b/internal/xds/xdsclient/tests/ads_stream_restart_test.go similarity index 97% rename from xds/internal/xdsclient/tests/ads_stream_restart_test.go rename to internal/xds/xdsclient/tests/ads_stream_restart_test.go index a53f96fb6623..58fad8028f80 100644 --- a/xds/internal/xdsclient/tests/ads_stream_restart_test.go +++ b/internal/xds/xdsclient/tests/ads_stream_restart_test.go @@ -30,9 +30,9 @@ import ( "google.golang.org/grpc/internal/testutils" "google.golang.org/grpc/internal/testutils/xds/e2e" "google.golang.org/grpc/internal/xds/bootstrap" - "google.golang.org/grpc/xds/internal/xdsclient" - "google.golang.org/grpc/xds/internal/xdsclient/xdsresource" - "google.golang.org/grpc/xds/internal/xdsclient/xdsresource/version" + "google.golang.org/grpc/internal/xds/xdsclient" + "google.golang.org/grpc/internal/xds/xdsclient/xdsresource" + "google.golang.org/grpc/internal/xds/xdsclient/xdsresource/version" v3clusterpb "github.com/envoyproxy/go-control-plane/envoy/config/cluster/v3" v3corepb "github.com/envoyproxy/go-control-plane/envoy/config/core/v3" diff --git a/xds/internal/xdsclient/tests/authority_test.go b/internal/xds/xdsclient/tests/authority_test.go similarity index 98% rename from xds/internal/xdsclient/tests/authority_test.go rename to internal/xds/xdsclient/tests/authority_test.go index 187fb4d1956d..fbea7cb8ec3c 100644 --- a/xds/internal/xdsclient/tests/authority_test.go +++ b/internal/xds/xdsclient/tests/authority_test.go @@ -30,9 +30,9 @@ import ( "google.golang.org/grpc/internal/testutils" "google.golang.org/grpc/internal/testutils/xds/e2e" "google.golang.org/grpc/internal/xds/bootstrap" - xdstestutils "google.golang.org/grpc/xds/internal/testutils" - "google.golang.org/grpc/xds/internal/xdsclient" - "google.golang.org/grpc/xds/internal/xdsclient/xdsresource" + xdstestutils "google.golang.org/grpc/internal/xds/testutils" + "google.golang.org/grpc/internal/xds/xdsclient" + "google.golang.org/grpc/internal/xds/xdsclient/xdsresource" v3clusterpb "github.com/envoyproxy/go-control-plane/envoy/config/cluster/v3" ) diff --git a/xds/internal/xdsclient/tests/cds_watchers_test.go b/internal/xds/xdsclient/tests/cds_watchers_test.go similarity index 99% rename from xds/internal/xdsclient/tests/cds_watchers_test.go rename to internal/xds/xdsclient/tests/cds_watchers_test.go index 3df630e5be8d..e6368340294f 100644 --- a/xds/internal/xdsclient/tests/cds_watchers_test.go +++ b/internal/xds/xdsclient/tests/cds_watchers_test.go @@ -34,8 +34,8 @@ import ( "google.golang.org/grpc/internal/testutils" "google.golang.org/grpc/internal/testutils/xds/e2e" "google.golang.org/grpc/internal/xds/bootstrap" - "google.golang.org/grpc/xds/internal/xdsclient" - "google.golang.org/grpc/xds/internal/xdsclient/xdsresource" + "google.golang.org/grpc/internal/xds/xdsclient" + "google.golang.org/grpc/internal/xds/xdsclient/xdsresource" v3clusterpb "github.com/envoyproxy/go-control-plane/envoy/config/cluster/v3" v3corepb "github.com/envoyproxy/go-control-plane/envoy/config/core/v3" diff --git a/xds/internal/xdsclient/tests/client_custom_dialopts_test.go b/internal/xds/xdsclient/tests/client_custom_dialopts_test.go similarity index 98% rename from xds/internal/xdsclient/tests/client_custom_dialopts_test.go rename to internal/xds/xdsclient/tests/client_custom_dialopts_test.go index 0f65b69cd029..39deb1240fe0 100644 --- a/xds/internal/xdsclient/tests/client_custom_dialopts_test.go +++ b/internal/xds/xdsclient/tests/client_custom_dialopts_test.go @@ -34,11 +34,11 @@ import ( "google.golang.org/grpc/internal/testutils" "google.golang.org/grpc/internal/testutils/xds/e2e" internalbootstrap "google.golang.org/grpc/internal/xds/bootstrap" + xci "google.golang.org/grpc/internal/xds/xdsclient/internal" testgrpc "google.golang.org/grpc/interop/grpc_testing" testpb "google.golang.org/grpc/interop/grpc_testing" "google.golang.org/grpc/resolver" "google.golang.org/grpc/xds/bootstrap" - xci "google.golang.org/grpc/xds/internal/xdsclient/internal" ) // nopDialOption is a no-op grpc.DialOption with a name. diff --git a/xds/internal/xdsclient/tests/dump_test.go b/internal/xds/xdsclient/tests/dump_test.go similarity index 99% rename from xds/internal/xdsclient/tests/dump_test.go rename to internal/xds/xdsclient/tests/dump_test.go index 117c810b1deb..a476c29bca7c 100644 --- a/xds/internal/xdsclient/tests/dump_test.go +++ b/internal/xds/xdsclient/tests/dump_test.go @@ -34,8 +34,8 @@ import ( "google.golang.org/grpc/internal/testutils" "google.golang.org/grpc/internal/testutils/xds/e2e" "google.golang.org/grpc/internal/xds/bootstrap" - "google.golang.org/grpc/xds/internal/xdsclient" - "google.golang.org/grpc/xds/internal/xdsclient/xdsresource" + "google.golang.org/grpc/internal/xds/xdsclient" + "google.golang.org/grpc/internal/xds/xdsclient/xdsresource" "google.golang.org/protobuf/testing/protocmp" "google.golang.org/protobuf/types/known/anypb" diff --git a/xds/internal/xdsclient/tests/eds_watchers_test.go b/internal/xds/xdsclient/tests/eds_watchers_test.go similarity index 99% rename from xds/internal/xdsclient/tests/eds_watchers_test.go rename to internal/xds/xdsclient/tests/eds_watchers_test.go index d551562c1606..a76c58641439 100644 --- a/xds/internal/xdsclient/tests/eds_watchers_test.go +++ b/internal/xds/xdsclient/tests/eds_watchers_test.go @@ -33,9 +33,9 @@ import ( "google.golang.org/grpc/internal/testutils" "google.golang.org/grpc/internal/testutils/xds/e2e" "google.golang.org/grpc/internal/xds/bootstrap" - "google.golang.org/grpc/xds/internal/clients" - "google.golang.org/grpc/xds/internal/xdsclient" - "google.golang.org/grpc/xds/internal/xdsclient/xdsresource" + "google.golang.org/grpc/internal/xds/clients" + "google.golang.org/grpc/internal/xds/xdsclient" + "google.golang.org/grpc/internal/xds/xdsclient/xdsresource" "google.golang.org/protobuf/types/known/wrapperspb" v3endpointpb "github.com/envoyproxy/go-control-plane/envoy/config/endpoint/v3" diff --git a/xds/internal/xdsclient/tests/fallback_test.go b/internal/xds/xdsclient/tests/fallback_test.go similarity index 80% rename from xds/internal/xdsclient/tests/fallback_test.go rename to internal/xds/xdsclient/tests/fallback_test.go index 5fad4b07bdc5..d4e2d8072943 100644 --- a/xds/internal/xdsclient/tests/fallback_test.go +++ b/internal/xds/xdsclient/tests/fallback_test.go @@ -34,11 +34,11 @@ import ( "google.golang.org/grpc/internal/testutils" "google.golang.org/grpc/internal/testutils/xds/e2e" "google.golang.org/grpc/internal/xds/bootstrap" + "google.golang.org/grpc/internal/xds/xdsclient" + "google.golang.org/grpc/internal/xds/xdsclient/xdsresource/version" "google.golang.org/grpc/peer" "google.golang.org/grpc/resolver" "google.golang.org/grpc/status" - "google.golang.org/grpc/xds/internal/xdsclient" - "google.golang.org/grpc/xds/internal/xdsclient/xdsresource/version" v3clusterpb "github.com/envoyproxy/go-control-plane/envoy/config/cluster/v3" v3endpointpb "github.com/envoyproxy/go-control-plane/envoy/config/endpoint/v3" @@ -728,3 +728,177 @@ func (s) TestFallback_OnStartup_RPCSuccess(t *testing.T) { t.Fatal(err) } } + +// TestXDSFallback_ThreeServerPromotion verifies that when the primary +// management server is unavailable, the system attempts to connect to the +// first fallback server, and if that is also down, to the second fallback +// server. It also ensures that the system switches back to the first fallback +// server once it becomes available again, and eventually returns to the +// primary server when it comes back online, closing connections to the +// fallback servers accordingly. +func (s) TestXDSFallback_ThreeServerPromotion(t *testing.T) { + ctx, cancel := context.WithTimeout(context.Background(), defaultFallbackTestTimeout) + defer cancel() + + // Create three listener wrappers for three management servers. + primaryWrappedLis := testutils.NewListenerWrapper(t, nil) + primaryLis := testutils.NewRestartableListener(primaryWrappedLis) + + secondaryWrappedLis := testutils.NewListenerWrapper(t, nil) + secondaryLis := testutils.NewRestartableListener(secondaryWrappedLis) + + tertiaryWrappedLis := testutils.NewListenerWrapper(t, nil) + tertiaryLis := testutils.NewRestartableListener(tertiaryWrappedLis) + + // Start the three management servers. + primaryManagementServer := e2e.StartManagementServer(t, e2e.ManagementServerOptions{Listener: primaryLis}) + secondaryManagementServer := e2e.StartManagementServer(t, e2e.ManagementServerOptions{Listener: secondaryLis}) + tertiaryManagementServer := e2e.StartManagementServer(t, e2e.ManagementServerOptions{Listener: tertiaryLis}) + + // Start three test service backends. + backend1 := stubserver.StartTestService(t, nil) + defer backend1.Stop() + backend2 := stubserver.StartTestService(t, nil) + defer backend2.Stop() + backend3 := stubserver.StartTestService(t, nil) + defer backend3.Stop() + + nodeID := uuid.New().String() + const serviceName = "my-service-fallback-xds" + + // Configure partial resources on the primary and secondary + // management servers. + primaryManagementServer.Update(ctx, e2e.UpdateOptions{ + NodeID: nodeID, + Listeners: []*v3listenerpb.Listener{e2e.DefaultClientListener(serviceName, "route-p")}, + }) + secondaryManagementServer.Update(ctx, e2e.UpdateOptions{ + NodeID: nodeID, + Listeners: []*v3listenerpb.Listener{e2e.DefaultClientListener(serviceName, "route-s1")}, + }) + + // Configure full resources on tertiary management server. + tertiaryManagementServer.Update(ctx, e2e.DefaultClientResources(e2e.ResourceParams{ + DialTarget: serviceName, + NodeID: nodeID, + Host: "localhost", + Port: testutils.ParsePort(t, backend3.Address), + SecLevel: e2e.SecurityLevelNone, + })) + + // Create bootstrap configuration for all three management servers. + bootstrapContents, err := bootstrap.NewContentsForTesting(bootstrap.ConfigOptionsForTesting{ + Servers: []byte(fmt.Sprintf(`[ + { + "server_uri": %q, + "channel_creds": [{"type": "insecure"}] + }, + { + "server_uri": %q, + "channel_creds": [{"type": "insecure"}] + }, + { + "server_uri": %q, + "channel_creds": [{"type": "insecure"}] + } + ]`, primaryManagementServer.Address, secondaryManagementServer.Address, tertiaryManagementServer.Address)), + Node: []byte(fmt.Sprintf(`{"id": "%s"}`, nodeID)), + }) + if err != nil { + t.Fatalf("Failed to create bootstrap file: %v", err) + } + + // Create an xDS client with the above bootstrap configuration. + config, err := bootstrap.NewConfigFromContents(bootstrapContents) + if err != nil { + t.Fatalf("Failed to parse bootstrap contents: %v", err) + } + pool := xdsclient.NewPool(config) + if err != nil { + t.Fatalf("Failed to create xDS client: %v", err) + } + + // Get the xDS resolver to use the above xDS client. + resolverBuilder := internal.NewXDSResolverWithPoolForTesting.(func(*xdsclient.Pool) (resolver.Builder, error)) + resolver, err := resolverBuilder(pool) + if err != nil { + t.Fatalf("Failed to create xDS resolver for testing: %v", err) + } + + // Start a gRPC client that uses the above xDS resolver. + cc, err := grpc.NewClient(fmt.Sprintf("xds:///%s", serviceName), grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithResolvers(resolver)) + if err != nil { + t.Fatalf("Failed to create gRPC client: %v", err) + } + defer cc.Close() + cc.Connect() + client := testgrpc.NewTestServiceClient(cc) + + // Verify that connection attempts were made to primaryWrappedLis and + // secondaryWrappedLis, before using tertiaryWrappedLis to make + // successful RPCs to backend3. + if _, err := primaryWrappedLis.NewConnCh.Receive(ctx); err != nil { + t.Fatalf("Timeout when waiting for connection to primary: %v", err) + } + + // Stop primary, client should connect to secondary. + primaryLis.Stop() + if _, err := secondaryWrappedLis.NewConnCh.Receive(ctx); err != nil { + t.Fatalf("Timeout when waiting for connection to secondary after primary stopped: %v", err) + } + + // Stop secondary, client should connect to tertiary. + secondaryLis.Stop() + tertiaryConn, err := tertiaryWrappedLis.NewConnCh.Receive(ctx) + if err != nil { + t.Fatalf("Timeout when waiting for connection to tertiary after secondary stopped: %v", err) + } + + // Tertiary has all resources, RPCs should succeed to backend3. + if err := waitForRPCsToReachBackend(ctx, client, backend3.Address); err != nil { + t.Fatal(err) + } + + // Secondary1 becomes available, RPCs go to backend2. + secondaryLis.Restart() + secondaryManagementServer.Update(ctx, e2e.UpdateOptions{ + NodeID: nodeID, + Listeners: []*v3listenerpb.Listener{e2e.DefaultClientListener(serviceName, "route-s1")}, + Routes: []*v3routepb.RouteConfiguration{e2e.DefaultRouteConfig("route-s1", serviceName, "cluster-s1")}, + Clusters: []*v3clusterpb.Cluster{e2e.DefaultCluster("cluster-s1", "endpoints-s1", e2e.SecurityLevelNone)}, + Endpoints: []*v3endpointpb.ClusterLoadAssignment{ + e2e.DefaultEndpoint("endpoints-s1", "localhost", []uint32{testutils.ParsePort(t, backend2.Address)}), + }, + }) + + secondaryConn, err := secondaryWrappedLis.NewConnCh.Receive(ctx) + if err != nil { + t.Fatalf("Timeout when waiting for new connection to secondary: %v", err) + } + if _, err := tertiaryConn.(*testutils.ConnWrapper).CloseCh.Receive(ctx); err != nil { + t.Fatalf("Timeout when waiting for connection to the tertiary to be closed after promotion to secondary: %v", err) + } + if err := waitForRPCsToReachBackend(ctx, client, backend2.Address); err != nil { + t.Fatal(err) + } + + // Primary becomes available, RPCs go to backend1. + primaryLis.Restart() + primaryManagementServer.Update(ctx, e2e.DefaultClientResources(e2e.ResourceParams{ + DialTarget: serviceName, + NodeID: nodeID, + Host: "localhost", + Port: testutils.ParsePort(t, backend1.Address), + SecLevel: e2e.SecurityLevelNone, + })) + + if _, err := primaryWrappedLis.NewConnCh.Receive(ctx); err != nil { + t.Fatalf("Timeout when waiting for new connection to primary: %v", err) + } + if _, err := secondaryConn.(*testutils.ConnWrapper).CloseCh.Receive(ctx); err != nil { + t.Fatalf("Timeout when waiting for connection to the secondary to be closed after promotion to primary: %v", err) + } + if err := waitForRPCsToReachBackend(ctx, client, backend1.Address); err != nil { + t.Fatal(err) + } +} diff --git a/xds/internal/xdsclient/tests/federation_watchers_test.go b/internal/xds/xdsclient/tests/federation_watchers_test.go similarity index 98% rename from xds/internal/xdsclient/tests/federation_watchers_test.go rename to internal/xds/xdsclient/tests/federation_watchers_test.go index 7f9babde5e51..1bf0dc554ca4 100644 --- a/xds/internal/xdsclient/tests/federation_watchers_test.go +++ b/internal/xds/xdsclient/tests/federation_watchers_test.go @@ -26,9 +26,9 @@ import ( "github.com/google/uuid" "google.golang.org/grpc/internal/testutils/xds/e2e" "google.golang.org/grpc/internal/xds/bootstrap" - "google.golang.org/grpc/xds/internal/clients" - "google.golang.org/grpc/xds/internal/xdsclient" - "google.golang.org/grpc/xds/internal/xdsclient/xdsresource" + "google.golang.org/grpc/internal/xds/clients" + "google.golang.org/grpc/internal/xds/xdsclient" + "google.golang.org/grpc/internal/xds/xdsclient/xdsresource" v3clusterpb "github.com/envoyproxy/go-control-plane/envoy/config/cluster/v3" v3endpointpb "github.com/envoyproxy/go-control-plane/envoy/config/endpoint/v3" diff --git a/xds/internal/xdsclient/tests/helpers_test.go b/internal/xds/xdsclient/tests/helpers_test.go similarity index 100% rename from xds/internal/xdsclient/tests/helpers_test.go rename to internal/xds/xdsclient/tests/helpers_test.go diff --git a/xds/internal/xdsclient/tests/lds_watchers_test.go b/internal/xds/xdsclient/tests/lds_watchers_test.go similarity index 99% rename from xds/internal/xdsclient/tests/lds_watchers_test.go rename to internal/xds/xdsclient/tests/lds_watchers_test.go index ff40de28acf8..877148639b2c 100644 --- a/xds/internal/xdsclient/tests/lds_watchers_test.go +++ b/internal/xds/xdsclient/tests/lds_watchers_test.go @@ -34,16 +34,16 @@ import ( "google.golang.org/grpc/internal/testutils" "google.golang.org/grpc/internal/testutils/xds/e2e" "google.golang.org/grpc/internal/xds/bootstrap" - "google.golang.org/grpc/xds/internal/xdsclient" - "google.golang.org/grpc/xds/internal/xdsclient/xdsresource" + "google.golang.org/grpc/internal/xds/xdsclient" + "google.golang.org/grpc/internal/xds/xdsclient/xdsresource" v3listenerpb "github.com/envoyproxy/go-control-plane/envoy/config/listener/v3" v3routerpb "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/http/router/v3" v3httppb "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/network/http_connection_manager/v3" v3discoverypb "github.com/envoyproxy/go-control-plane/envoy/service/discovery/v3" + _ "google.golang.org/grpc/internal/xds/httpfilter/router" // Register the router filter. _ "google.golang.org/grpc/xds" // To ensure internal.NewXDSResolverWithConfigForTesting is set. - _ "google.golang.org/grpc/xds/internal/httpfilter/router" // Register the router filter. ) type noopListenerWatcher struct{} diff --git a/xds/internal/xdsclient/tests/loadreport_test.go b/internal/xds/xdsclient/tests/loadreport_test.go similarity index 81% rename from xds/internal/xdsclient/tests/loadreport_test.go rename to internal/xds/xdsclient/tests/loadreport_test.go index a93b5bc1cbee..95a9354d0511 100644 --- a/xds/internal/xdsclient/tests/loadreport_test.go +++ b/internal/xds/xdsclient/tests/loadreport_test.go @@ -23,6 +23,7 @@ import ( "encoding/json" "fmt" "net" + "sync" "testing" "github.com/google/go-cmp/cmp" @@ -30,17 +31,24 @@ import ( "github.com/google/uuid" "google.golang.org/grpc" "google.golang.org/grpc/codes" + "google.golang.org/grpc/credentials/insecure" + "google.golang.org/grpc/internal" + "google.golang.org/grpc/internal/stubserver" "google.golang.org/grpc/internal/testutils" "google.golang.org/grpc/internal/testutils/xds/e2e" "google.golang.org/grpc/internal/testutils/xds/fakeserver" "google.golang.org/grpc/internal/xds/bootstrap" + "google.golang.org/grpc/internal/xds/clients" + "google.golang.org/grpc/internal/xds/xdsclient" + "google.golang.org/grpc/resolver" "google.golang.org/grpc/status" - "google.golang.org/grpc/xds/internal/clients" "google.golang.org/protobuf/testing/protocmp" v3corepb "github.com/envoyproxy/go-control-plane/envoy/config/core/v3" v3endpointpb "github.com/envoyproxy/go-control-plane/envoy/config/endpoint/v3" v3lrspb "github.com/envoyproxy/go-control-plane/envoy/service/load_stats/v3" + testgrpc "google.golang.org/grpc/interop/grpc_testing" + testpb "google.golang.org/grpc/interop/grpc_testing" "google.golang.org/protobuf/types/known/durationpb" ) @@ -437,3 +445,111 @@ func (s) TestReportLoad_StreamCreation(t *testing.T) { defer sCancel3() cancel3(sCtx3) } + +// TestConcurrentReportLoad verifies that the client can safely handle concurrent +// requests to initiate load reporting streams. It launches multiple goroutines +// that all call client.ReportLoad simultaneously. +func (s) TestConcurrentReportLoad(t *testing.T) { + ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) + defer cancel() + + mgmtServer := e2e.StartManagementServer(t, e2e.ManagementServerOptions{SupportLoadReportingService: true}) + nodeID := uuid.New().String() + bc := e2e.DefaultBootstrapContents(t, nodeID, mgmtServer.Address) + client := createXDSClient(t, bc) + + serverConfig, err := bootstrap.ServerConfigForTesting(bootstrap.ServerConfigTestingOptions{URI: mgmtServer.Address}) + if err != nil { + t.Fatalf("Failed to create server config for testing: %v", err) + } + + // Call ReportLoad() concurrently from multiple go routines. + var wg sync.WaitGroup + const numGoroutines = 10 + wg.Add(numGoroutines) + for range numGoroutines { + go func() { + defer wg.Done() + _, cancelStore := client.ReportLoad(serverConfig) + defer cancelStore(ctx) + }() + } + wg.Wait() +} + +// TestConcurrentChannels verifies that we can create multiple gRPC channels +// concurrently with a shared XDSClient, each of which will create a new LRS +// stream without any race. +func (s) TestConcurrentChannels(t *testing.T) { + ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) + defer cancel() + + mgmtServer := e2e.StartManagementServer(t, e2e.ManagementServerOptions{AllowResourceSubset: true, SupportLoadReportingService: true}) + + nodeID := uuid.New().String() + bc := e2e.DefaultBootstrapContents(t, nodeID, mgmtServer.Address) + + if internal.NewXDSResolverWithPoolForTesting == nil { + t.Fatalf("internal.NewXDSResolverWithConfigForTesting is nil") + } + + config, err := bootstrap.NewConfigFromContents(bc) + if err != nil { + t.Fatalf("Failed to parse bootstrap contents: %s, %v", string(bc), err) + } + pool := xdsclient.NewPool(config) + + resolverBuilder := internal.NewXDSResolverWithPoolForTesting.(func(*xdsclient.Pool) (resolver.Builder, error)) + xdsResolver, err := resolverBuilder(pool) + if err != nil { + t.Fatalf("Failed to create xDS resolver for testing: %v", err) + } + + server := stubserver.StartTestService(t, nil) + defer server.Stop() + + // Configure the management server with resources that enable LRS. + const serviceName = "my-service-e2e-lrs-test" + resources := e2e.DefaultClientResources(e2e.ResourceParams{ + DialTarget: serviceName, + NodeID: nodeID, + Host: "localhost", + Port: testutils.ParsePort(t, server.Address), + SecLevel: e2e.SecurityLevelNone, + }) + resources.Clusters[0].LrsServer = &v3corepb.ConfigSource{ + ConfigSourceSpecifier: &v3corepb.ConfigSource_Self{ + Self: &v3corepb.SelfConfigSource{}, + }, + } + if err := mgmtServer.Update(ctx, resources); err != nil { + t.Fatal(err) + } + + var wg sync.WaitGroup + const ( + numGoroutines = 10 + numRPCs = 10 + ) + for range numGoroutines { + wg.Add(1) + go func() { + defer wg.Done() + for range numRPCs { + cc, err := grpc.NewClient(fmt.Sprintf("xds:///%s", serviceName), grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithResolvers(xdsResolver)) + if err != nil { + t.Errorf("grpc.NewClient() failed: %v", err) + return + } + defer cc.Close() + + testClient := testgrpc.NewTestServiceClient(cc) + if _, err := testClient.EmptyCall(ctx, &testpb.Empty{}); err != nil { + t.Errorf("EmptyCall() failed: %v", err) + return + } + } + }() + } + wg.Wait() +} diff --git a/xds/internal/xdsclient/tests/rds_watchers_test.go b/internal/xds/xdsclient/tests/rds_watchers_test.go similarity index 99% rename from xds/internal/xdsclient/tests/rds_watchers_test.go rename to internal/xds/xdsclient/tests/rds_watchers_test.go index a650bd7c49aa..3ec333ad8a24 100644 --- a/xds/internal/xdsclient/tests/rds_watchers_test.go +++ b/internal/xds/xdsclient/tests/rds_watchers_test.go @@ -33,8 +33,8 @@ import ( "google.golang.org/grpc/internal/testutils" "google.golang.org/grpc/internal/testutils/xds/e2e" "google.golang.org/grpc/internal/xds/bootstrap" - "google.golang.org/grpc/xds/internal/xdsclient" - "google.golang.org/grpc/xds/internal/xdsclient/xdsresource" + "google.golang.org/grpc/internal/xds/xdsclient" + "google.golang.org/grpc/internal/xds/xdsclient/xdsresource" "google.golang.org/protobuf/types/known/wrapperspb" v3routepb "github.com/envoyproxy/go-control-plane/envoy/config/route/v3" diff --git a/xds/internal/xdsclient/tests/resource_update_test.go b/internal/xds/xdsclient/tests/resource_update_test.go similarity index 99% rename from xds/internal/xdsclient/tests/resource_update_test.go rename to internal/xds/xdsclient/tests/resource_update_test.go index 251094084d8b..90517a90841d 100644 --- a/xds/internal/xdsclient/tests/resource_update_test.go +++ b/internal/xds/xdsclient/tests/resource_update_test.go @@ -33,9 +33,9 @@ import ( "google.golang.org/grpc/internal/testutils/xds/e2e" "google.golang.org/grpc/internal/testutils/xds/fakeserver" "google.golang.org/grpc/internal/xds/bootstrap" - "google.golang.org/grpc/xds/internal/clients" - "google.golang.org/grpc/xds/internal/xdsclient" - "google.golang.org/grpc/xds/internal/xdsclient/xdsresource" + "google.golang.org/grpc/internal/xds/clients" + "google.golang.org/grpc/internal/xds/xdsclient" + "google.golang.org/grpc/internal/xds/xdsclient/xdsresource" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/testing/protocmp" "google.golang.org/protobuf/types/known/anypb" @@ -51,7 +51,7 @@ import ( v3discoverypb "github.com/envoyproxy/go-control-plane/envoy/service/discovery/v3" v3statuspb "github.com/envoyproxy/go-control-plane/envoy/service/status/v3" - _ "google.golang.org/grpc/xds/internal/httpfilter/router" // Register the router filter. + _ "google.golang.org/grpc/internal/xds/httpfilter/router" // Register the router filter. ) // startFakeManagementServer starts a fake xDS management server and registers a diff --git a/xds/internal/xdsclient/xdsclient_test.go b/internal/xds/xdsclient/xdsclient_test.go similarity index 100% rename from xds/internal/xdsclient/xdsclient_test.go rename to internal/xds/xdsclient/xdsclient_test.go diff --git a/xds/internal/xdsclient/xdslbregistry/converter/converter.go b/internal/xds/xdsclient/xdslbregistry/converter/converter.go similarity index 98% rename from xds/internal/xdsclient/xdslbregistry/converter/converter.go rename to internal/xds/xdsclient/xdslbregistry/converter/converter.go index 959c6588b000..d38b9db82431 100644 --- a/xds/internal/xdsclient/xdslbregistry/converter/converter.go +++ b/internal/xds/xdsclient/xdslbregistry/converter/converter.go @@ -35,8 +35,8 @@ import ( "google.golang.org/grpc/balancer/weightedroundrobin" iringhash "google.golang.org/grpc/internal/ringhash" internalserviceconfig "google.golang.org/grpc/internal/serviceconfig" - "google.golang.org/grpc/xds/internal/balancer/wrrlocality" - "google.golang.org/grpc/xds/internal/xdsclient/xdslbregistry" + "google.golang.org/grpc/internal/xds/balancer/wrrlocality" + "google.golang.org/grpc/internal/xds/xdsclient/xdslbregistry" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/types/known/structpb" diff --git a/xds/internal/xdsclient/xdslbregistry/xdslbregistry.go b/internal/xds/xdsclient/xdslbregistry/xdslbregistry.go similarity index 100% rename from xds/internal/xdsclient/xdslbregistry/xdslbregistry.go rename to internal/xds/xdsclient/xdslbregistry/xdslbregistry.go diff --git a/xds/internal/xdsclient/xdslbregistry/xdslbregistry_test.go b/internal/xds/xdsclient/xdslbregistry/xdslbregistry_test.go similarity index 99% rename from xds/internal/xdsclient/xdslbregistry/xdslbregistry_test.go rename to internal/xds/xdsclient/xdslbregistry/xdslbregistry_test.go index 5760e632fb59..d23f46781f72 100644 --- a/xds/internal/xdsclient/xdslbregistry/xdslbregistry_test.go +++ b/internal/xds/xdsclient/xdslbregistry/xdslbregistry_test.go @@ -31,9 +31,9 @@ import ( "google.golang.org/grpc/internal/pretty" internalserviceconfig "google.golang.org/grpc/internal/serviceconfig" "google.golang.org/grpc/internal/testutils" + "google.golang.org/grpc/internal/xds/balancer/wrrlocality" + "google.golang.org/grpc/internal/xds/xdsclient/xdslbregistry" _ "google.golang.org/grpc/xds" // Register the xDS LB Registry Converters. - "google.golang.org/grpc/xds/internal/balancer/wrrlocality" - "google.golang.org/grpc/xds/internal/xdsclient/xdslbregistry" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/types/known/anypb" "google.golang.org/protobuf/types/known/structpb" diff --git a/xds/internal/xdsclient/xdsresource/cluster_resource_type.go b/internal/xds/xdsclient/xdsresource/cluster_resource_type.go similarity index 97% rename from xds/internal/xdsclient/xdsresource/cluster_resource_type.go rename to internal/xds/xdsclient/xdsresource/cluster_resource_type.go index de6335081458..2a6a08f90647 100644 --- a/xds/internal/xdsclient/xdsresource/cluster_resource_type.go +++ b/internal/xds/xdsclient/xdsresource/cluster_resource_type.go @@ -20,8 +20,8 @@ package xdsresource import ( "google.golang.org/grpc/internal/pretty" "google.golang.org/grpc/internal/xds/bootstrap" - xdsclient "google.golang.org/grpc/xds/internal/clients/xdsclient" - "google.golang.org/grpc/xds/internal/xdsclient/xdsresource/version" + xdsclient "google.golang.org/grpc/internal/xds/clients/xdsclient" + "google.golang.org/grpc/internal/xds/xdsclient/xdsresource/version" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/types/known/anypb" ) diff --git a/xds/internal/xdsclient/xdsresource/endpoints_resource_type.go b/internal/xds/xdsclient/xdsresource/endpoints_resource_type.go similarity index 97% rename from xds/internal/xdsclient/xdsresource/endpoints_resource_type.go rename to internal/xds/xdsclient/xdsresource/endpoints_resource_type.go index dd8a3b38c7f6..7ca45ec6ad0c 100644 --- a/xds/internal/xdsclient/xdsresource/endpoints_resource_type.go +++ b/internal/xds/xdsclient/xdsresource/endpoints_resource_type.go @@ -19,8 +19,8 @@ package xdsresource import ( "google.golang.org/grpc/internal/pretty" - xdsclient "google.golang.org/grpc/xds/internal/clients/xdsclient" - "google.golang.org/grpc/xds/internal/xdsclient/xdsresource/version" + xdsclient "google.golang.org/grpc/internal/xds/clients/xdsclient" + "google.golang.org/grpc/internal/xds/xdsclient/xdsresource/version" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/types/known/anypb" ) diff --git a/xds/internal/xdsclient/xdsresource/errors.go b/internal/xds/xdsclient/xdsresource/errors.go similarity index 100% rename from xds/internal/xdsclient/xdsresource/errors.go rename to internal/xds/xdsclient/xdsresource/errors.go diff --git a/xds/internal/xdsclient/xdsresource/filter_chain.go b/internal/xds/xdsclient/xdsresource/filter_chain.go similarity index 99% rename from xds/internal/xdsclient/xdsresource/filter_chain.go rename to internal/xds/xdsclient/xdsresource/filter_chain.go index 46bbcaf4a1f2..76ace1090d68 100644 --- a/xds/internal/xdsclient/xdsresource/filter_chain.go +++ b/internal/xds/xdsclient/xdsresource/filter_chain.go @@ -25,9 +25,9 @@ import ( "google.golang.org/grpc/codes" "google.golang.org/grpc/internal/resolver" + "google.golang.org/grpc/internal/xds/httpfilter" + "google.golang.org/grpc/internal/xds/xdsclient/xdsresource/version" "google.golang.org/grpc/status" - "google.golang.org/grpc/xds/internal/httpfilter" - "google.golang.org/grpc/xds/internal/xdsclient/xdsresource/version" "google.golang.org/protobuf/proto" v3listenerpb "github.com/envoyproxy/go-control-plane/envoy/config/listener/v3" diff --git a/xds/internal/xdsclient/xdsresource/filter_chain_test.go b/internal/xds/xdsclient/xdsresource/filter_chain_test.go similarity index 99% rename from xds/internal/xdsclient/xdsresource/filter_chain_test.go rename to internal/xds/xdsclient/xdsresource/filter_chain_test.go index 67b37dffb836..a6dcacec75a5 100644 --- a/xds/internal/xdsclient/xdsresource/filter_chain_test.go +++ b/internal/xds/xdsclient/xdsresource/filter_chain_test.go @@ -43,9 +43,9 @@ import ( iresolver "google.golang.org/grpc/internal/resolver" "google.golang.org/grpc/internal/testutils" "google.golang.org/grpc/internal/testutils/xds/e2e" - "google.golang.org/grpc/xds/internal/httpfilter" - "google.golang.org/grpc/xds/internal/httpfilter/router" - "google.golang.org/grpc/xds/internal/xdsclient/xdsresource/version" + "google.golang.org/grpc/internal/xds/httpfilter" + "google.golang.org/grpc/internal/xds/httpfilter/router" + "google.golang.org/grpc/internal/xds/xdsclient/xdsresource/version" ) const ( diff --git a/xds/internal/xdsclient/xdsresource/listener_resource_type.go b/internal/xds/xdsclient/xdsresource/listener_resource_type.go similarity index 98% rename from xds/internal/xdsclient/xdsresource/listener_resource_type.go rename to internal/xds/xdsclient/xdsresource/listener_resource_type.go index 29ff88704553..100a06f97b67 100644 --- a/xds/internal/xdsclient/xdsresource/listener_resource_type.go +++ b/internal/xds/xdsclient/xdsresource/listener_resource_type.go @@ -22,8 +22,8 @@ import ( "google.golang.org/grpc/internal/pretty" "google.golang.org/grpc/internal/xds/bootstrap" - xdsclient "google.golang.org/grpc/xds/internal/clients/xdsclient" - "google.golang.org/grpc/xds/internal/xdsclient/xdsresource/version" + xdsclient "google.golang.org/grpc/internal/xds/clients/xdsclient" + "google.golang.org/grpc/internal/xds/xdsclient/xdsresource/version" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/types/known/anypb" ) diff --git a/xds/internal/xdsclient/xdsresource/logging.go b/internal/xds/xdsclient/xdsresource/logging.go similarity index 100% rename from xds/internal/xdsclient/xdsresource/logging.go rename to internal/xds/xdsclient/xdsresource/logging.go diff --git a/xds/internal/xdsclient/xdsresource/matcher.go b/internal/xds/xdsclient/xdsresource/matcher.go similarity index 100% rename from xds/internal/xdsclient/xdsresource/matcher.go rename to internal/xds/xdsclient/xdsresource/matcher.go diff --git a/xds/internal/xdsclient/xdsresource/matcher_path.go b/internal/xds/xdsclient/xdsresource/matcher_path.go similarity index 100% rename from xds/internal/xdsclient/xdsresource/matcher_path.go rename to internal/xds/xdsclient/xdsresource/matcher_path.go diff --git a/xds/internal/xdsclient/xdsresource/matcher_path_test.go b/internal/xds/xdsclient/xdsresource/matcher_path_test.go similarity index 100% rename from xds/internal/xdsclient/xdsresource/matcher_path_test.go rename to internal/xds/xdsclient/xdsresource/matcher_path_test.go diff --git a/xds/internal/xdsclient/xdsresource/matcher_test.go b/internal/xds/xdsclient/xdsresource/matcher_test.go similarity index 100% rename from xds/internal/xdsclient/xdsresource/matcher_test.go rename to internal/xds/xdsclient/xdsresource/matcher_test.go diff --git a/internal/xds/xdsclient/xdsresource/metadata.go b/internal/xds/xdsclient/xdsresource/metadata.go new file mode 100644 index 000000000000..b56c309d6f27 --- /dev/null +++ b/internal/xds/xdsclient/xdsresource/metadata.go @@ -0,0 +1,93 @@ +/* + * + * Copyright 2025 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package xdsresource + +import ( + "fmt" + "net/netip" + + v3corepb "github.com/envoyproxy/go-control-plane/envoy/config/core/v3" + "google.golang.org/protobuf/types/known/anypb" +) + +func init() { + registerMetadataConverter("type.googleapis.com/envoy.config.core.v3.Address", proxyAddressConvertor{}) +} + +var ( + // metdataRegistry is a map from proto type to metadataConverter. + metdataRegistry = make(map[string]metadataConverter) +) + +// metadataConverter converts xds metadata entries in +// Metadata.typed_filter_metadata into an internal form with the fields relevant +// to gRPC. +type metadataConverter interface { + // convert parses the Any proto into a concrete struct. + convert(*anypb.Any) (any, error) +} + +// registerMetadataConverter registers the converter to the map keyed on a proto +// type_url. Must be called at init time. Not thread safe. +func registerMetadataConverter(protoType string, c metadataConverter) { + metdataRegistry[protoType] = c +} + +// metadataConverterForType retrieves a converter based on key given. +func metadataConverterForType(typeURL string) metadataConverter { + return metdataRegistry[typeURL] +} + +// StructMetadataValue stores the values in a google.protobuf.Struct from +// FilterMetadata. +type StructMetadataValue struct { + // Data stores the parsed JSON representation of a google.protobuf.Struct. + Data map[string]any +} + +// ProxyAddressMetadataValue holds the address parsed from the +// envoy.config.core.v3.Address proto message, as specified in gRFC A86. +type ProxyAddressMetadataValue struct { + // Address stores the proxy address configured (A86). It will be in the form + // of host:port. It has to be either IPv6 or IPv4. + Address string +} + +// proxyAddressConvertor implements the metadataConverter interface to handle +// the conversion of envoy.config.core.v3.Address protobuf messages into an +// internal representation. +type proxyAddressConvertor struct{} + +func (proxyAddressConvertor) convert(anyProto *anypb.Any) (any, error) { + addressProto := &v3corepb.Address{} + if err := anyProto.UnmarshalTo(addressProto); err != nil { + return nil, fmt.Errorf("failed to unmarshal resource from Any proto: %v", err) + } + socketaddress := addressProto.GetSocketAddress() + if socketaddress == nil { + return nil, fmt.Errorf("no socket_address field in metadata") + } + if _, err := netip.ParseAddr(socketaddress.GetAddress()); err != nil { + return nil, fmt.Errorf("address field is not a valid IPv4 or IPv6 address: %q", socketaddress.GetAddress()) + } + portvalue := socketaddress.GetPortValue() + if portvalue == 0 { + return nil, fmt.Errorf("port value not set in socket_address") + } + return ProxyAddressMetadataValue{Address: parseAddress(socketaddress)}, nil +} diff --git a/internal/xds/xdsclient/xdsresource/metadata_test.go b/internal/xds/xdsclient/xdsresource/metadata_test.go new file mode 100644 index 000000000000..28de8b511af5 --- /dev/null +++ b/internal/xds/xdsclient/xdsresource/metadata_test.go @@ -0,0 +1,199 @@ +/* + * + * Copyright 2025 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package xdsresource + +import ( + "testing" + + v3corepb "github.com/envoyproxy/go-control-plane/envoy/config/core/v3" + "github.com/google/go-cmp/cmp" + "google.golang.org/grpc/internal/testutils" +) + +const proxyAddressTypeURL = "type.googleapis.com/envoy.config.core.v3.Address" + +func (s) TestProxyAddressConverterSuccess(t *testing.T) { + converter := metadataConverterForType(proxyAddressTypeURL) + if converter == nil { + t.Fatalf("Converter for %q not found in registry", proxyAddressTypeURL) + } + tests := []struct { + name string + addr *v3corepb.Address + want ProxyAddressMetadataValue + }{ + { + name: "valid IPv4 address and port", + addr: &v3corepb.Address{ + Address: &v3corepb.Address_SocketAddress{ + SocketAddress: &v3corepb.SocketAddress{ + Address: "192.168.1.1", + PortSpecifier: &v3corepb.SocketAddress_PortValue{ + PortValue: 8080, + }, + }, + }, + }, + want: ProxyAddressMetadataValue{ + Address: "192.168.1.1:8080", + }, + }, + { + name: "valid full IPv6 address and port", + addr: &v3corepb.Address{ + Address: &v3corepb.Address_SocketAddress{ + SocketAddress: &v3corepb.SocketAddress{ + Address: "2001:0db8:85a3:0000:0000:8a2e:0370:7334", + PortSpecifier: &v3corepb.SocketAddress_PortValue{ + PortValue: 9090, + }, + }, + }, + }, + want: ProxyAddressMetadataValue{ + Address: "[2001:0db8:85a3:0000:0000:8a2e:0370:7334]:9090", + }, + }, + { + name: "valid shortened IPv6 address", + addr: &v3corepb.Address{ + Address: &v3corepb.Address_SocketAddress{ + SocketAddress: &v3corepb.SocketAddress{ + Address: "2001:db8::1", + PortSpecifier: &v3corepb.SocketAddress_PortValue{ + PortValue: 9090, + }, + }, + }, + }, + want: ProxyAddressMetadataValue{ + Address: "[2001:db8::1]:9090", + }, + }, + { + name: "valid link-local IPv6 address", + addr: &v3corepb.Address{ + Address: &v3corepb.Address_SocketAddress{ + SocketAddress: &v3corepb.SocketAddress{ + Address: "fe80::1ff:fe23:4567:890a", + PortSpecifier: &v3corepb.SocketAddress_PortValue{ + PortValue: 8888, + }, + }, + }, + }, + want: ProxyAddressMetadataValue{ + Address: "[fe80::1ff:fe23:4567:890a]:8888", + }, + }, + { + name: "valid IPv4-mapped IPv6 address", + addr: &v3corepb.Address{ + Address: &v3corepb.Address_SocketAddress{ + SocketAddress: &v3corepb.SocketAddress{ + Address: "::ffff:192.0.2.128", + PortSpecifier: &v3corepb.SocketAddress_PortValue{ + PortValue: 1234, + }, + }, + }, + }, + want: ProxyAddressMetadataValue{ + Address: "[::ffff:192.0.2.128]:1234", + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + anyProto := testutils.MarshalAny(t, tt.addr) + got, err := converter.convert(anyProto) + if err != nil { + t.Fatalf("convert() failed with error: %v", err) + } + if diff := cmp.Diff(tt.want, got, cmp.AllowUnexported(ProxyAddressMetadataValue{})); diff != "" { + t.Errorf("convert() returned unexpected value (-want +got):\n%s", diff) + } + }) + } +} + +func (s) TestProxyAddressConverterFailure(t *testing.T) { + converter := metadataConverterForType(proxyAddressTypeURL) + if converter == nil { + t.Fatalf("Converter for %q not found in registry", proxyAddressTypeURL) + } + tests := []struct { + name string + addr *v3corepb.Address + wantErr string + }{ + { + name: "invalid address", + addr: &v3corepb.Address{ + Address: &v3corepb.Address_SocketAddress{ + SocketAddress: &v3corepb.SocketAddress{ + Address: "invalid-ip", + }, + }, + }, + wantErr: "address field is not a valid IPv4 or IPv6 address: \"invalid-ip\"", + }, + { + name: "missing socket_address", + addr: &v3corepb.Address{ + // No SocketAddress field set. + }, + wantErr: "no socket_address field in metadata", + }, + { + name: "address is not a socket address", + addr: &v3corepb.Address{ + Address: &v3corepb.Address_EnvoyInternalAddress{ + EnvoyInternalAddress: &v3corepb.EnvoyInternalAddress{ + AddressNameSpecifier: &v3corepb.EnvoyInternalAddress_ServerListenerName{ + ServerListenerName: "some-internal-listener", + }, + }, + }, + }, + wantErr: "no socket_address field in metadata", + }, + { + name: "port value not set", + addr: &v3corepb.Address{ + Address: &v3corepb.Address_SocketAddress{ + SocketAddress: &v3corepb.SocketAddress{ + Address: "127.0.0.1", + PortSpecifier: nil, + }, + }, + }, + wantErr: "port value not set in socket_address", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + anyProto := testutils.MarshalAny(t, tt.addr) + _, err := converter.convert(anyProto) + if err == nil || err.Error() != tt.wantErr { + t.Errorf("convert() got error = %v, wantErr = %q", err, tt.wantErr) + } + }) + } +} diff --git a/xds/internal/xdsclient/xdsresource/name.go b/internal/xds/xdsclient/xdsresource/name.go similarity index 100% rename from xds/internal/xdsclient/xdsresource/name.go rename to internal/xds/xdsclient/xdsresource/name.go diff --git a/xds/internal/xdsclient/xdsresource/name_test.go b/internal/xds/xdsclient/xdsresource/name_test.go similarity index 100% rename from xds/internal/xdsclient/xdsresource/name_test.go rename to internal/xds/xdsclient/xdsresource/name_test.go diff --git a/xds/internal/xdsclient/xdsresource/resource_type.go b/internal/xds/xdsclient/xdsresource/resource_type.go similarity index 98% rename from xds/internal/xdsclient/xdsresource/resource_type.go rename to internal/xds/xdsclient/xdsresource/resource_type.go index 4ecf63a1c378..2c591312f1be 100644 --- a/xds/internal/xdsclient/xdsresource/resource_type.go +++ b/internal/xds/xdsclient/xdsresource/resource_type.go @@ -27,10 +27,10 @@ package xdsresource import ( "fmt" + xdsinternal "google.golang.org/grpc/internal/xds" "google.golang.org/grpc/internal/xds/bootstrap" - xdsinternal "google.golang.org/grpc/xds/internal" - "google.golang.org/grpc/xds/internal/clients/xdsclient" - "google.golang.org/grpc/xds/internal/xdsclient/xdsresource/version" + "google.golang.org/grpc/internal/xds/clients/xdsclient" + "google.golang.org/grpc/internal/xds/xdsclient/xdsresource/version" "google.golang.org/protobuf/types/known/anypb" ) diff --git a/xds/internal/xdsclient/xdsresource/route_config_resource_type.go b/internal/xds/xdsclient/xdsresource/route_config_resource_type.go similarity index 97% rename from xds/internal/xdsclient/xdsresource/route_config_resource_type.go rename to internal/xds/xdsclient/xdsresource/route_config_resource_type.go index 344932e93d94..912dc1b762b4 100644 --- a/xds/internal/xdsclient/xdsresource/route_config_resource_type.go +++ b/internal/xds/xdsclient/xdsresource/route_config_resource_type.go @@ -19,8 +19,8 @@ package xdsresource import ( "google.golang.org/grpc/internal/pretty" - xdsclient "google.golang.org/grpc/xds/internal/clients/xdsclient" - "google.golang.org/grpc/xds/internal/xdsclient/xdsresource/version" + xdsclient "google.golang.org/grpc/internal/xds/clients/xdsclient" + "google.golang.org/grpc/internal/xds/xdsclient/xdsresource/version" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/types/known/anypb" ) diff --git a/xds/internal/xdsclient/xdsresource/test_utils_test.go b/internal/xds/xdsclient/xdsresource/test_utils_test.go similarity index 100% rename from xds/internal/xdsclient/xdsresource/test_utils_test.go rename to internal/xds/xdsclient/xdsresource/test_utils_test.go diff --git a/xds/internal/xdsclient/xdsresource/tests/unmarshal_cds_test.go b/internal/xds/xdsclient/xdsresource/tests/unmarshal_cds_test.go similarity index 95% rename from xds/internal/xdsclient/xdsresource/tests/unmarshal_cds_test.go rename to internal/xds/xdsclient/xdsresource/tests/unmarshal_cds_test.go index c9eaef5ad717..c25ddf62a02a 100644 --- a/xds/internal/xdsclient/xdsresource/tests/unmarshal_cds_test.go +++ b/internal/xds/xdsclient/xdsresource/tests/unmarshal_cds_test.go @@ -32,11 +32,11 @@ import ( iserviceconfig "google.golang.org/grpc/internal/serviceconfig" "google.golang.org/grpc/internal/testutils" "google.golang.org/grpc/internal/testutils/xds/e2e" + xdsinternal "google.golang.org/grpc/internal/xds" + "google.golang.org/grpc/internal/xds/balancer/wrrlocality" "google.golang.org/grpc/internal/xds/bootstrap" + "google.golang.org/grpc/internal/xds/xdsclient/xdsresource" "google.golang.org/grpc/serviceconfig" - "google.golang.org/grpc/xds/internal" - "google.golang.org/grpc/xds/internal/balancer/wrrlocality" - "google.golang.org/grpc/xds/internal/xdsclient/xdsresource" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/types/known/anypb" "google.golang.org/protobuf/types/known/structpb" @@ -142,7 +142,7 @@ func (s) TestValidateCluster_Success(t *testing.T) { ClusterName: clusterName, ClusterType: xdsresource.ClusterTypeLogicalDNS, DNSHostName: "dns_host:8080", - TelemetryLabels: internal.UnknownCSMLabels, + TelemetryLabels: xdsinternal.UnknownCSMLabels, }, wantLBConfig: &iserviceconfig.BalancerConfig{ Name: wrrlocality.Name, @@ -171,7 +171,7 @@ func (s) TestValidateCluster_Success(t *testing.T) { ClusterName: clusterName, ClusterType: xdsresource.ClusterTypeAggregate, PrioritizedClusterNames: []string{"a", "b", "c"}, - TelemetryLabels: internal.UnknownCSMLabels, + TelemetryLabels: xdsinternal.UnknownCSMLabels, }, wantLBConfig: &iserviceconfig.BalancerConfig{ Name: wrrlocality.Name, @@ -187,7 +187,7 @@ func (s) TestValidateCluster_Success(t *testing.T) { cluster: e2e.DefaultCluster(clusterName, "", e2e.SecurityLevelNone), wantUpdate: xdsresource.ClusterUpdate{ ClusterName: clusterName, - TelemetryLabels: internal.UnknownCSMLabels, + TelemetryLabels: xdsinternal.UnknownCSMLabels, }, wantLBConfig: &iserviceconfig.BalancerConfig{ Name: wrrlocality.Name, @@ -204,7 +204,7 @@ func (s) TestValidateCluster_Success(t *testing.T) { wantUpdate: xdsresource.ClusterUpdate{ ClusterName: clusterName, EDSServiceName: serviceName, - TelemetryLabels: internal.UnknownCSMLabels, + TelemetryLabels: xdsinternal.UnknownCSMLabels, }, wantLBConfig: &iserviceconfig.BalancerConfig{ Name: wrrlocality.Name, @@ -227,7 +227,7 @@ func (s) TestValidateCluster_Success(t *testing.T) { ClusterName: clusterName, EDSServiceName: serviceName, LRSServerConfig: serverCfg, - TelemetryLabels: internal.UnknownCSMLabels, + TelemetryLabels: xdsinternal.UnknownCSMLabels, }, wantLBConfig: &iserviceconfig.BalancerConfig{ Name: wrrlocality.Name, @@ -266,7 +266,7 @@ func (s) TestValidateCluster_Success(t *testing.T) { EDSServiceName: serviceName, LRSServerConfig: serverCfg, MaxRequests: func() *uint32 { i := uint32(512); return &i }(), - TelemetryLabels: internal.UnknownCSMLabels, + TelemetryLabels: xdsinternal.UnknownCSMLabels, }, wantLBConfig: &iserviceconfig.BalancerConfig{ Name: wrrlocality.Name, @@ -287,7 +287,7 @@ func (s) TestValidateCluster_Success(t *testing.T) { wantUpdate: xdsresource.ClusterUpdate{ ClusterName: clusterName, EDSServiceName: serviceName, - TelemetryLabels: internal.UnknownCSMLabels, + TelemetryLabels: xdsinternal.UnknownCSMLabels, }, wantLBConfig: &iserviceconfig.BalancerConfig{ Name: "ring_hash_experimental", @@ -315,7 +315,7 @@ func (s) TestValidateCluster_Success(t *testing.T) { wantUpdate: xdsresource.ClusterUpdate{ ClusterName: clusterName, EDSServiceName: serviceName, - TelemetryLabels: internal.UnknownCSMLabels, + TelemetryLabels: xdsinternal.UnknownCSMLabels, }, wantLBConfig: &iserviceconfig.BalancerConfig{ Name: "least_request_experimental", @@ -340,7 +340,7 @@ func (s) TestValidateCluster_Success(t *testing.T) { wantUpdate: xdsresource.ClusterUpdate{ ClusterName: clusterName, EDSServiceName: serviceName, - TelemetryLabels: internal.UnknownCSMLabels, + TelemetryLabels: xdsinternal.UnknownCSMLabels, }, wantLBConfig: &iserviceconfig.BalancerConfig{ Name: "ring_hash_experimental", @@ -373,7 +373,7 @@ func (s) TestValidateCluster_Success(t *testing.T) { wantUpdate: xdsresource.ClusterUpdate{ ClusterName: clusterName, EDSServiceName: serviceName, - TelemetryLabels: internal.UnknownCSMLabels, + TelemetryLabels: xdsinternal.UnknownCSMLabels, }, wantLBConfig: &iserviceconfig.BalancerConfig{ Name: "least_request_experimental", @@ -412,7 +412,7 @@ func (s) TestValidateCluster_Success(t *testing.T) { wantUpdate: xdsresource.ClusterUpdate{ ClusterName: clusterName, EDSServiceName: serviceName, - TelemetryLabels: internal.UnknownCSMLabels, + TelemetryLabels: xdsinternal.UnknownCSMLabels, }, wantLBConfig: &iserviceconfig.BalancerConfig{ Name: "ring_hash_experimental", @@ -448,7 +448,7 @@ func (s) TestValidateCluster_Success(t *testing.T) { wantUpdate: xdsresource.ClusterUpdate{ ClusterName: clusterName, EDSServiceName: serviceName, - TelemetryLabels: internal.UnknownCSMLabels, + TelemetryLabels: xdsinternal.UnknownCSMLabels, }, wantLBConfig: &iserviceconfig.BalancerConfig{ Name: wrrlocality.Name, @@ -488,7 +488,7 @@ func (s) TestValidateCluster_Success(t *testing.T) { wantUpdate: xdsresource.ClusterUpdate{ ClusterName: clusterName, EDSServiceName: serviceName, - TelemetryLabels: internal.UnknownCSMLabels, + TelemetryLabels: xdsinternal.UnknownCSMLabels, }, wantLBConfig: &iserviceconfig.BalancerConfig{ Name: wrrlocality.Name, @@ -537,7 +537,7 @@ func (s) TestValidateCluster_Success(t *testing.T) { wantUpdate: xdsresource.ClusterUpdate{ ClusterName: clusterName, EDSServiceName: serviceName, - TelemetryLabels: internal.UnknownCSMLabels, + TelemetryLabels: xdsinternal.UnknownCSMLabels, }, wantLBConfig: &iserviceconfig.BalancerConfig{ Name: "ring_hash_experimental", diff --git a/xds/internal/xdsclient/xdsresource/type.go b/internal/xds/xdsclient/xdsresource/type.go similarity index 98% rename from xds/internal/xdsclient/xdsresource/type.go rename to internal/xds/xdsclient/xdsresource/type.go index 994204101835..7f85c1da2105 100644 --- a/xds/internal/xdsclient/xdsresource/type.go +++ b/internal/xds/xdsclient/xdsresource/type.go @@ -21,7 +21,7 @@ import ( "time" v3discoverypb "github.com/envoyproxy/go-control-plane/envoy/service/discovery/v3" - "google.golang.org/grpc/xds/internal/xdsclient/xdsresource/version" + "google.golang.org/grpc/internal/xds/xdsclient/xdsresource/version" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/types/known/anypb" ) diff --git a/xds/internal/xdsclient/xdsresource/type_cds.go b/internal/xds/xdsclient/xdsresource/type_cds.go similarity index 100% rename from xds/internal/xdsclient/xdsresource/type_cds.go rename to internal/xds/xdsclient/xdsresource/type_cds.go diff --git a/xds/internal/xdsclient/xdsresource/type_eds.go b/internal/xds/xdsclient/xdsresource/type_eds.go similarity index 95% rename from xds/internal/xdsclient/xdsresource/type_eds.go rename to internal/xds/xdsclient/xdsresource/type_eds.go index 12294626f392..a8d568e18263 100644 --- a/xds/internal/xdsclient/xdsresource/type_eds.go +++ b/internal/xds/xdsclient/xdsresource/type_eds.go @@ -18,7 +18,7 @@ package xdsresource import ( - "google.golang.org/grpc/xds/internal/clients" + "google.golang.org/grpc/internal/xds/clients" "google.golang.org/protobuf/types/known/anypb" ) @@ -53,6 +53,7 @@ type Endpoint struct { HealthStatus EndpointHealthStatus Weight uint32 HashKey string + Metadata map[string]any } // Locality contains information of a locality. @@ -61,6 +62,7 @@ type Locality struct { ID clients.Locality Priority uint32 Weight uint32 + Metadata map[string]any } // EndpointsUpdate contains an EDS update. diff --git a/xds/internal/xdsclient/xdsresource/type_lds.go b/internal/xds/xdsclient/xdsresource/type_lds.go similarity index 98% rename from xds/internal/xdsclient/xdsresource/type_lds.go rename to internal/xds/xdsclient/xdsresource/type_lds.go index a71e38ea9a52..a2e057b0e7a3 100644 --- a/xds/internal/xdsclient/xdsresource/type_lds.go +++ b/internal/xds/xdsclient/xdsresource/type_lds.go @@ -20,7 +20,7 @@ package xdsresource import ( "time" - "google.golang.org/grpc/xds/internal/httpfilter" + "google.golang.org/grpc/internal/xds/httpfilter" "google.golang.org/protobuf/types/known/anypb" ) diff --git a/xds/internal/xdsclient/xdsresource/type_rds.go b/internal/xds/xdsclient/xdsresource/type_rds.go similarity index 98% rename from xds/internal/xdsclient/xdsresource/type_rds.go rename to internal/xds/xdsclient/xdsresource/type_rds.go index 42da39126393..44bc27891f1b 100644 --- a/xds/internal/xdsclient/xdsresource/type_rds.go +++ b/internal/xds/xdsclient/xdsresource/type_rds.go @@ -22,9 +22,9 @@ import ( "time" "google.golang.org/grpc/codes" + "google.golang.org/grpc/internal/xds/clusterspecifier" + "google.golang.org/grpc/internal/xds/httpfilter" "google.golang.org/grpc/internal/xds/matcher" - "google.golang.org/grpc/xds/internal/clusterspecifier" - "google.golang.org/grpc/xds/internal/httpfilter" "google.golang.org/protobuf/types/known/anypb" ) diff --git a/xds/internal/xdsclient/xdsresource/unmarshal_cds.go b/internal/xds/xdsclient/xdsresource/unmarshal_cds.go similarity index 99% rename from xds/internal/xdsclient/xdsresource/unmarshal_cds.go rename to internal/xds/xdsclient/xdsresource/unmarshal_cds.go index 43247c5b8d9f..d7133c996cb3 100644 --- a/xds/internal/xdsclient/xdsresource/unmarshal_cds.go +++ b/internal/xds/xdsclient/xdsresource/unmarshal_cds.go @@ -36,8 +36,8 @@ import ( iserviceconfig "google.golang.org/grpc/internal/serviceconfig" "google.golang.org/grpc/internal/xds/bootstrap" "google.golang.org/grpc/internal/xds/matcher" - "google.golang.org/grpc/xds/internal/xdsclient/xdslbregistry" - "google.golang.org/grpc/xds/internal/xdsclient/xdsresource/version" + "google.golang.org/grpc/internal/xds/xdsclient/xdslbregistry" + "google.golang.org/grpc/internal/xds/xdsclient/xdsresource/version" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/types/known/anypb" "google.golang.org/protobuf/types/known/structpb" diff --git a/xds/internal/xdsclient/xdsresource/unmarshal_cds_test.go b/internal/xds/xdsclient/xdsresource/unmarshal_cds_test.go similarity index 98% rename from xds/internal/xdsclient/xdsresource/unmarshal_cds_test.go rename to internal/xds/xdsclient/xdsresource/unmarshal_cds_test.go index 513241e0a958..0fb70d635447 100644 --- a/xds/internal/xdsclient/xdsresource/unmarshal_cds_test.go +++ b/internal/xds/xdsclient/xdsresource/unmarshal_cds_test.go @@ -28,10 +28,10 @@ import ( "google.golang.org/grpc/internal/envconfig" "google.golang.org/grpc/internal/pretty" "google.golang.org/grpc/internal/testutils" + xdsinternal "google.golang.org/grpc/internal/xds" "google.golang.org/grpc/internal/xds/bootstrap" "google.golang.org/grpc/internal/xds/matcher" - "google.golang.org/grpc/xds/internal" - "google.golang.org/grpc/xds/internal/xdsclient/xdsresource/version" + "google.golang.org/grpc/internal/xds/xdsclient/xdsresource/version" v3clusterpb "github.com/envoyproxy/go-control-plane/envoy/config/cluster/v3" v3corepb "github.com/envoyproxy/go-control-plane/envoy/config/core/v3" @@ -935,7 +935,7 @@ func (s) TestValidateClusterWithSecurityConfig(t *testing.T) { RootInstanceName: rootPluginInstance, RootCertName: rootCertName, }, - TelemetryLabels: internal.UnknownCSMLabels, + TelemetryLabels: xdsinternal.UnknownCSMLabels, }, }, { @@ -977,7 +977,7 @@ func (s) TestValidateClusterWithSecurityConfig(t *testing.T) { RootInstanceName: rootPluginInstance, RootCertName: rootCertName, }, - TelemetryLabels: internal.UnknownCSMLabels, + TelemetryLabels: xdsinternal.UnknownCSMLabels, }, }, { @@ -1023,7 +1023,7 @@ func (s) TestValidateClusterWithSecurityConfig(t *testing.T) { IdentityInstanceName: identityPluginInstance, IdentityCertName: identityCertName, }, - TelemetryLabels: internal.UnknownCSMLabels, + TelemetryLabels: xdsinternal.UnknownCSMLabels, }, }, { @@ -1076,7 +1076,7 @@ func (s) TestValidateClusterWithSecurityConfig(t *testing.T) { IdentityInstanceName: identityPluginInstance, IdentityCertName: identityCertName, }, - TelemetryLabels: internal.UnknownCSMLabels, + TelemetryLabels: xdsinternal.UnknownCSMLabels, }, }, { @@ -1121,7 +1121,7 @@ func (s) TestValidateClusterWithSecurityConfig(t *testing.T) { IdentityInstanceName: identityPluginInstance, IdentityCertName: identityCertName, }, - TelemetryLabels: internal.UnknownCSMLabels, + TelemetryLabels: xdsinternal.UnknownCSMLabels, }, }, { @@ -1223,7 +1223,7 @@ func (s) TestValidateClusterWithSecurityConfig(t *testing.T) { matcher.StringMatcherForTesting(nil, nil, nil, newStringP(sanContains), nil, false), }, }, - TelemetryLabels: internal.UnknownCSMLabels, + TelemetryLabels: xdsinternal.UnknownCSMLabels, }, }, { @@ -1290,7 +1290,7 @@ func (s) TestValidateClusterWithSecurityConfig(t *testing.T) { matcher.StringMatcherForTesting(nil, nil, nil, newStringP(sanContains), nil, false), }, }, - TelemetryLabels: internal.UnknownCSMLabels, + TelemetryLabels: xdsinternal.UnknownCSMLabels, }, }, { @@ -1354,7 +1354,7 @@ func (s) TestValidateClusterWithSecurityConfig(t *testing.T) { matcher.StringMatcherForTesting(nil, nil, nil, newStringP(sanContains), nil, false), }, }, - TelemetryLabels: internal.UnknownCSMLabels, + TelemetryLabels: xdsinternal.UnknownCSMLabels, }, }, } @@ -1553,7 +1553,7 @@ func (s) TestUnmarshalCluster(t *testing.T) { EDSServiceName: v3Service, LRSServerConfig: serverCfg, Raw: v3ClusterAny, - TelemetryLabels: internal.UnknownCSMLabels, + TelemetryLabels: xdsinternal.UnknownCSMLabels, }, }, { @@ -1566,7 +1566,7 @@ func (s) TestUnmarshalCluster(t *testing.T) { EDSServiceName: v3Service, LRSServerConfig: serverCfg, Raw: v3ClusterAny, - TelemetryLabels: internal.UnknownCSMLabels, + TelemetryLabels: xdsinternal.UnknownCSMLabels, }, }, { @@ -1579,7 +1579,7 @@ func (s) TestUnmarshalCluster(t *testing.T) { EDSServiceName: v3Service, LRSServerConfig: serverCfg, Raw: v3ClusterAnyWithEDSConfigSourceSelf, - TelemetryLabels: internal.UnknownCSMLabels, + TelemetryLabels: xdsinternal.UnknownCSMLabels, }, }, { diff --git a/xds/internal/xdsclient/xdsresource/unmarshal_eds.go b/internal/xds/xdsclient/xdsresource/unmarshal_eds.go similarity index 72% rename from xds/internal/xdsclient/xdsresource/unmarshal_eds.go rename to internal/xds/xdsclient/xdsresource/unmarshal_eds.go index d56b42dd360e..c5b9723a79a3 100644 --- a/xds/internal/xdsclient/xdsresource/unmarshal_eds.go +++ b/internal/xds/xdsclient/xdsresource/unmarshal_eds.go @@ -28,8 +28,8 @@ import ( v3typepb "github.com/envoyproxy/go-control-plane/envoy/type/v3" "google.golang.org/grpc/internal/envconfig" "google.golang.org/grpc/internal/pretty" - "google.golang.org/grpc/xds/internal" - "google.golang.org/grpc/xds/internal/clients" + xdsinternal "google.golang.org/grpc/internal/xds" + "google.golang.org/grpc/internal/xds/clients" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/types/known/anypb" ) @@ -108,30 +108,42 @@ func parseEndpoints(lbEndpoints []*v3endpointpb.LbEndpoint, uniqueEndpointAddrs } uniqueEndpointAddrs[a] = true } + + var endpointMetadata map[string]any + var hashKey string + if envconfig.XDSHTTPConnectEnabled || !envconfig.XDSEndpointHashKeyBackwardCompat { + var err error + endpointMetadata, err = validateAndConstructMetadata(lbEndpoint.GetMetadata()) + if err != nil { + return nil, err + } + + // "The xDS resolver, described in A74, will be changed to set the hash_key + // endpoint attribute to the value of LbEndpoint.Metadata envoy.lb hash_key + // field, as described in Envoy's documentation for the ring hash load + // balancer." - A76 + if !envconfig.XDSEndpointHashKeyBackwardCompat { + hashKey = hashKeyFromMetadata(endpointMetadata) + } + } endpoints = append(endpoints, Endpoint{ HealthStatus: EndpointHealthStatus(lbEndpoint.GetHealthStatus()), Addresses: addrs, Weight: weight, - HashKey: hashKey(lbEndpoint), + HashKey: hashKey, + Metadata: endpointMetadata, }) } return endpoints, nil } -// hashKey extracts and returns the hash key from the given LbEndpoint. If no -// hash key is found, it returns an empty string. -func hashKey(lbEndpoint *v3endpointpb.LbEndpoint) string { - // "The xDS resolver, described in A74, will be changed to set the hash_key - // endpoint attribute to the value of LbEndpoint.Metadata envoy.lb hash_key - // field, as described in Envoy's documentation for the ring hash load - // balancer." - A76 - if envconfig.XDSEndpointHashKeyBackwardCompat { - return "" - } - envoyLB := lbEndpoint.GetMetadata().GetFilterMetadata()["envoy.lb"] - if envoyLB != nil { - if h := envoyLB.GetFields()["hash_key"]; h != nil { - return h.GetStringValue() +// hashKey extracts and returns the hash key from the given endpoint metadata. +// If no hash key is found, it returns an empty string. +func hashKeyFromMetadata(metadata map[string]any) string { + envoyLB, ok := metadata["envoy.lb"].(StructMetadataValue) + if ok { + if h, ok := envoyLB.Data["hash_key"].(string); ok { + return h } } return "" @@ -170,7 +182,7 @@ func parseEDSRespProto(m *v3endpointpb.ClusterLoadAssignment) (EndpointsUpdate, Zone: l.Zone, SubZone: l.SubZone, } - lidStr := internal.LocalityString(lid) + lidStr := xdsinternal.LocalityString(lid) // "Since an xDS configuration can place a given locality under multiple // priorities, it is possible to see locality weight attributes with @@ -190,11 +202,21 @@ func parseEDSRespProto(m *v3endpointpb.ClusterLoadAssignment) (EndpointsUpdate, if err != nil { return EndpointsUpdate{}, err } + var localityMetadata map[string]any + if envconfig.XDSHTTPConnectEnabled { + var err error + localityMetadata, err = validateAndConstructMetadata(locality.GetMetadata()) + if err != nil { + return EndpointsUpdate{}, err + } + } + ret.Localities = append(ret.Localities, Locality{ ID: lid, Endpoints: endpoints, Weight: weight, Priority: priority, + Metadata: localityMetadata, }) } for i := 0; i < len(priorities); i++ { @@ -204,3 +226,34 @@ func parseEDSRespProto(m *v3endpointpb.ClusterLoadAssignment) (EndpointsUpdate, } return ret, nil } + +func validateAndConstructMetadata(metadataProto *v3corepb.Metadata) (map[string]any, error) { + if metadataProto == nil { + return nil, nil + } + metadata := make(map[string]any) + // First go through TypedFilterMetadata. + for key, anyProto := range metadataProto.GetTypedFilterMetadata() { + converter := metadataConverterForType(anyProto.GetTypeUrl()) + // Ignore types we don't have a converter for. + if converter == nil { + continue + } + val, err := converter.convert(anyProto) + if err != nil { + // If the converter fails, nack the whole resource. + return nil, fmt.Errorf("metadata conversion for key %q and type %q failed: %v", key, anyProto.GetTypeUrl(), err) + } + metadata[key] = val + } + + // Process FilterMetadata for any keys not already handled. + for key, structProto := range metadataProto.GetFilterMetadata() { + // Skip keys already added from TyperFilterMetadata. + if metadata[key] != nil { + continue + } + metadata[key] = StructMetadataValue{Data: structProto.AsMap()} + } + return metadata, nil +} diff --git a/internal/xds/xdsclient/xdsresource/unmarshal_eds_test.go b/internal/xds/xdsclient/xdsresource/unmarshal_eds_test.go new file mode 100644 index 000000000000..3020b4953116 --- /dev/null +++ b/internal/xds/xdsclient/xdsresource/unmarshal_eds_test.go @@ -0,0 +1,1462 @@ +/* + * + * Copyright 2021 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package xdsresource + +import ( + "fmt" + "net" + "strconv" + "testing" + + v3corepb "github.com/envoyproxy/go-control-plane/envoy/config/core/v3" + v3endpointpb "github.com/envoyproxy/go-control-plane/envoy/config/endpoint/v3" + v3discoverypb "github.com/envoyproxy/go-control-plane/envoy/service/discovery/v3" + v3typepb "github.com/envoyproxy/go-control-plane/envoy/type/v3" + "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/cmpopts" + "google.golang.org/grpc/internal/envconfig" + "google.golang.org/grpc/internal/pretty" + "google.golang.org/grpc/internal/testutils" + "google.golang.org/grpc/internal/xds/clients" + "google.golang.org/grpc/internal/xds/xdsclient/xdsresource/version" + "google.golang.org/protobuf/proto" + "google.golang.org/protobuf/types/known/anypb" + "google.golang.org/protobuf/types/known/structpb" + "google.golang.org/protobuf/types/known/wrapperspb" +) + +func (s) TestEDSParseRespProto(t *testing.T) { + tests := []struct { + name string + m *v3endpointpb.ClusterLoadAssignment + want EndpointsUpdate + wantErr bool + }{ + { + name: "missing-priority", + m: func() *v3endpointpb.ClusterLoadAssignment { + clab0 := newClaBuilder("test", nil) + clab0.addLocality("locality-1", 1, 0, []endpointOpts{{addrWithPort: "addr1:314"}}, nil) + clab0.addLocality("locality-2", 1, 2, []endpointOpts{{addrWithPort: "addr2:159"}}, nil) + return clab0.Build() + }(), + want: EndpointsUpdate{}, + wantErr: true, + }, + { + name: "missing-locality-ID", + m: func() *v3endpointpb.ClusterLoadAssignment { + clab0 := newClaBuilder("test", nil) + clab0.addLocality("", 1, 0, []endpointOpts{{addrWithPort: "addr1:314"}}, nil) + return clab0.Build() + }(), + want: EndpointsUpdate{}, + wantErr: true, + }, + { + name: "zero-endpoint-weight", + m: func() *v3endpointpb.ClusterLoadAssignment { + clab0 := newClaBuilder("test", nil) + clab0.addLocality("locality-0", 1, 0, []endpointOpts{{addrWithPort: "addr1:314"}}, &addLocalityOptions{Weight: []uint32{0}}) + return clab0.Build() + }(), + want: EndpointsUpdate{}, + wantErr: true, + }, + { + name: "duplicate-locality-in-the-same-priority", + m: func() *v3endpointpb.ClusterLoadAssignment { + clab0 := newClaBuilder("test", nil) + clab0.addLocality("locality-0", 1, 0, []endpointOpts{{addrWithPort: "addr1:314"}}, nil) + clab0.addLocality("locality-0", 1, 0, []endpointOpts{{addrWithPort: "addr1:314"}}, nil) // Duplicate locality with the same priority. + return clab0.Build() + }(), + want: EndpointsUpdate{}, + wantErr: true, + }, + { + name: "missing locality weight", + m: func() *v3endpointpb.ClusterLoadAssignment { + clab0 := newClaBuilder("test", nil) + clab0.addLocality("locality-1", 0, 1, []endpointOpts{{addrWithPort: "addr1:314"}}, &addLocalityOptions{ + Health: []v3corepb.HealthStatus{v3corepb.HealthStatus_HEALTHY}, + }) + clab0.addLocality("locality-2", 0, 0, []endpointOpts{{addrWithPort: "addr2:159"}}, &addLocalityOptions{ + Health: []v3corepb.HealthStatus{v3corepb.HealthStatus_HEALTHY}, + }) + return clab0.Build() + }(), + want: EndpointsUpdate{}, + }, + { + name: "max sum of weights at the same priority exceeded", + m: func() *v3endpointpb.ClusterLoadAssignment { + clab0 := newClaBuilder("test", nil) + clab0.addLocality("locality-1", 1, 0, []endpointOpts{{addrWithPort: "addr1:314"}}, nil) + clab0.addLocality("locality-2", 4294967295, 1, []endpointOpts{{addrWithPort: "addr2:159"}}, nil) + clab0.addLocality("locality-3", 1, 1, []endpointOpts{{addrWithPort: "addr2:88"}}, nil) + return clab0.Build() + }(), + want: EndpointsUpdate{}, + wantErr: true, + }, + { + name: "duplicate endpoint address", + m: func() *v3endpointpb.ClusterLoadAssignment { + clab0 := newClaBuilder("test", nil) + clab0.addLocality("locality-1", 1, 1, []endpointOpts{{addrWithPort: "addr:997"}}, nil) + clab0.addLocality("locality-2", 1, 0, []endpointOpts{{addrWithPort: "addr:997"}}, nil) + return clab0.Build() + }(), + want: EndpointsUpdate{}, + wantErr: true, + }, + { + name: "good", + m: func() *v3endpointpb.ClusterLoadAssignment { + clab0 := newClaBuilder("test", nil) + clab0.addLocality("locality-1", 1, 1, []endpointOpts{{addrWithPort: "addr1:314"}}, &addLocalityOptions{ + Health: []v3corepb.HealthStatus{v3corepb.HealthStatus_UNHEALTHY}, + Weight: []uint32{271}, + }) + clab0.addLocality("locality-2", 1, 0, []endpointOpts{{addrWithPort: "addr2:159"}}, &addLocalityOptions{ + Health: []v3corepb.HealthStatus{v3corepb.HealthStatus_DRAINING}, + Weight: []uint32{828}, + }) + return clab0.Build() + }(), + want: EndpointsUpdate{ + Drops: nil, + Localities: []Locality{ + { + Endpoints: []Endpoint{{ + Addresses: []string{"addr1:314"}, + HealthStatus: EndpointHealthStatusUnhealthy, + Weight: 271, + }}, + ID: clients.Locality{SubZone: "locality-1"}, + Priority: 1, + Weight: 1, + }, + { + Endpoints: []Endpoint{{ + Addresses: []string{"addr2:159"}, + HealthStatus: EndpointHealthStatusDraining, + Weight: 828, + }}, + ID: clients.Locality{SubZone: "locality-2"}, + Priority: 0, + Weight: 1, + }, + }, + }, + wantErr: false, + }, + { + name: "good duplicate locality with different priority", + m: func() *v3endpointpb.ClusterLoadAssignment { + clab0 := newClaBuilder("test", nil) + clab0.addLocality("locality-1", 1, 1, []endpointOpts{{addrWithPort: "addr1:314"}}, &addLocalityOptions{ + Health: []v3corepb.HealthStatus{v3corepb.HealthStatus_UNHEALTHY}, + Weight: []uint32{271}, + }) + // Same locality name, but with different priority. + clab0.addLocality("locality-1", 1, 0, []endpointOpts{{addrWithPort: "addr2:159"}}, &addLocalityOptions{ + Health: []v3corepb.HealthStatus{v3corepb.HealthStatus_DRAINING}, + Weight: []uint32{828}, + }) + return clab0.Build() + }(), + want: EndpointsUpdate{ + Drops: nil, + Localities: []Locality{ + { + Endpoints: []Endpoint{{ + Addresses: []string{"addr1:314"}, + HealthStatus: EndpointHealthStatusUnhealthy, + Weight: 271, + }}, + ID: clients.Locality{SubZone: "locality-1"}, + Priority: 1, + Weight: 1, + }, + { + Endpoints: []Endpoint{{ + Addresses: []string{"addr2:159"}, + HealthStatus: EndpointHealthStatusDraining, + Weight: 828, + }}, + ID: clients.Locality{SubZone: "locality-1"}, + Priority: 0, + Weight: 1, + }, + }, + }, + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := parseEDSRespProto(tt.m) + if (err != nil) != tt.wantErr { + t.Fatalf("parseEDSRespProto() error = %v, wantErr %v", err, tt.wantErr) + } + if d := cmp.Diff(got, tt.want, cmpopts.EquateEmpty()); d != "" { + t.Errorf("parseEDSRespProto() got = %v, want %v, diff: %v", got, tt.want, d) + } + }) + } +} + +func (s) TestEDSParseRespProtoAdditionalAddrs(t *testing.T) { + origDualstackEndpointsEnabled := envconfig.XDSDualstackEndpointsEnabled + defer func() { + envconfig.XDSDualstackEndpointsEnabled = origDualstackEndpointsEnabled + }() + envconfig.XDSDualstackEndpointsEnabled = true + + tests := []struct { + name string + m *v3endpointpb.ClusterLoadAssignment + want EndpointsUpdate + wantErr bool + }{ + { + name: "duplicate primary address in self additional addresses", + m: func() *v3endpointpb.ClusterLoadAssignment { + clab0 := newClaBuilder("test", nil) + clab0.addLocality("locality-1", 1, 0, []endpointOpts{{addrWithPort: "addr:998", additionalAddrWithPorts: []string{"addr:998"}}}, nil) + return clab0.Build() + }(), + want: EndpointsUpdate{}, + wantErr: true, + }, + { + name: "duplicate primary address in other locality additional addresses", + m: func() *v3endpointpb.ClusterLoadAssignment { + clab0 := newClaBuilder("test", nil) + clab0.addLocality("locality-1", 1, 1, []endpointOpts{{addrWithPort: "addr:997"}}, nil) + clab0.addLocality("locality-2", 1, 0, []endpointOpts{{addrWithPort: "addr:998", additionalAddrWithPorts: []string{"addr:997"}}}, nil) + return clab0.Build() + }(), + want: EndpointsUpdate{}, + wantErr: true, + }, + { + name: "duplicate additional address in self additional addresses", + m: func() *v3endpointpb.ClusterLoadAssignment { + clab0 := newClaBuilder("test", nil) + clab0.addLocality("locality-1", 1, 0, []endpointOpts{{addrWithPort: "addr:998", additionalAddrWithPorts: []string{"addr:999", "addr:999"}}}, nil) + return clab0.Build() + }(), + want: EndpointsUpdate{}, + wantErr: true, + }, + { + name: "duplicate additional address in other locality additional addresses", + m: func() *v3endpointpb.ClusterLoadAssignment { + clab0 := newClaBuilder("test", nil) + clab0.addLocality("locality-1", 1, 1, []endpointOpts{{addrWithPort: "addr:997", additionalAddrWithPorts: []string{"addr:1000"}}}, nil) + clab0.addLocality("locality-2", 1, 0, []endpointOpts{{addrWithPort: "addr:998", additionalAddrWithPorts: []string{"addr:1000"}}}, nil) + return clab0.Build() + }(), + want: EndpointsUpdate{}, + wantErr: true, + }, + { + name: "multiple localities", + m: func() *v3endpointpb.ClusterLoadAssignment { + clab0 := newClaBuilder("test", nil) + clab0.addLocality("locality-1", 1, 1, []endpointOpts{{addrWithPort: "addr1:997", additionalAddrWithPorts: []string{"addr1:1000"}}}, &addLocalityOptions{ + Health: []v3corepb.HealthStatus{v3corepb.HealthStatus_UNHEALTHY}, + Weight: []uint32{271}, + }) + clab0.addLocality("locality-2", 1, 0, []endpointOpts{{addrWithPort: "addr2:998", additionalAddrWithPorts: []string{"addr2:1000"}}}, &addLocalityOptions{ + Health: []v3corepb.HealthStatus{v3corepb.HealthStatus_HEALTHY}, + Weight: []uint32{828}, + }) + return clab0.Build() + }(), + want: EndpointsUpdate{ + Drops: nil, + Localities: []Locality{ + { + Endpoints: []Endpoint{{ + Addresses: []string{"addr1:997", "addr1:1000"}, + HealthStatus: EndpointHealthStatusUnhealthy, + Weight: 271, + }}, + ID: clients.Locality{SubZone: "locality-1"}, + Priority: 1, + Weight: 1, + }, + { + Endpoints: []Endpoint{{ + Addresses: []string{"addr2:998", "addr2:1000"}, + HealthStatus: EndpointHealthStatusHealthy, + Weight: 828, + }}, + ID: clients.Locality{SubZone: "locality-2"}, + Priority: 0, + Weight: 1, + }, + }, + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := parseEDSRespProto(tt.m) + if (err != nil) != tt.wantErr { + t.Fatalf("parseEDSRespProto() error = %v, wantErr %v", err, tt.wantErr) + } + if d := cmp.Diff(got, tt.want, cmpopts.EquateEmpty()); d != "" { + t.Errorf("parseEDSRespProto() got = %v, want %v, diff: %v", got, tt.want, d) + } + }) + } +} + +func (s) TestUnmarshalEndpointHashKey(t *testing.T) { + baseCLA := &v3endpointpb.ClusterLoadAssignment{ + Endpoints: []*v3endpointpb.LocalityLbEndpoints{ + { + Locality: &v3corepb.Locality{Region: "r"}, + LbEndpoints: []*v3endpointpb.LbEndpoint{ + { + HostIdentifier: &v3endpointpb.LbEndpoint_Endpoint{ + Endpoint: &v3endpointpb.Endpoint{ + Address: &v3corepb.Address{ + Address: &v3corepb.Address_SocketAddress{ + SocketAddress: &v3corepb.SocketAddress{ + Address: "test-address", + PortSpecifier: &v3corepb.SocketAddress_PortValue{ + PortValue: 8080, + }, + }, + }, + }, + }, + }, + }, + }, + LoadBalancingWeight: &wrapperspb.UInt32Value{Value: 1}, + }, + }, + } + + tests := []struct { + name string + metadata *v3corepb.Metadata + wantHashKey string + compatEnvVar bool + }{ + { + name: "no metadata", + metadata: nil, + wantHashKey: "", + }, + { + name: "empty metadata", + metadata: &v3corepb.Metadata{}, + wantHashKey: "", + }, + { + name: "filter metadata without envoy.lb", + metadata: &v3corepb.Metadata{ + FilterMetadata: map[string]*structpb.Struct{ + "test-filter": {}, + }, + }, + wantHashKey: "", + }, + { + name: "nil envoy.lb", + metadata: &v3corepb.Metadata{ + FilterMetadata: map[string]*structpb.Struct{ + "envoy.lb": nil, + }, + }, + wantHashKey: "", + }, + { + name: "envoy.lb without hash key", + metadata: &v3corepb.Metadata{ + FilterMetadata: map[string]*structpb.Struct{ + "envoy.lb": { + Fields: map[string]*structpb.Value{ + "hash_key": { + Kind: &structpb.Value_NumberValue{NumberValue: 123.0}, + }, + }, + }, + }, + }, + wantHashKey: "", + }, + { + name: "envoy.lb with hash key, compat mode off", + metadata: &v3corepb.Metadata{ + FilterMetadata: map[string]*structpb.Struct{ + "envoy.lb": { + Fields: map[string]*structpb.Value{ + "hash_key": { + Kind: &structpb.Value_StringValue{StringValue: "test-hash-key"}, + }, + }, + }, + }, + }, + wantHashKey: "test-hash-key", + }, + { + name: "envoy.lb with hash key, compat mode on", + metadata: &v3corepb.Metadata{ + FilterMetadata: map[string]*structpb.Struct{ + "envoy.lb": { + Fields: map[string]*structpb.Value{ + "hash_key": { + Kind: &structpb.Value_StringValue{StringValue: "test-hash-key"}, + }, + }, + }, + }, + }, + wantHashKey: "", + compatEnvVar: true, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + testutils.SetEnvConfig(t, &envconfig.XDSEndpointHashKeyBackwardCompat, test.compatEnvVar) + + cla := proto.Clone(baseCLA).(*v3endpointpb.ClusterLoadAssignment) + cla.Endpoints[0].LbEndpoints[0].Metadata = test.metadata + marshalledCLA := testutils.MarshalAny(t, cla) + _, update, err := unmarshalEndpointsResource(marshalledCLA) + if err != nil { + t.Fatalf("unmarshalEndpointsResource() got error = %v, want success", err) + } + got := update.Localities[0].Endpoints[0].HashKey + if got != test.wantHashKey { + t.Errorf("unmarshalEndpointResource() endpoint hash key: got %s, want %s", got, test.wantHashKey) + } + }) + } +} + +func (s) TestUnmarshalEndpoints(t *testing.T) { + testutils.SetEnvConfig(t, &envconfig.XDSHTTPConnectEnabled, true) + var v3EndpointsAny = testutils.MarshalAny(t, func() *v3endpointpb.ClusterLoadAssignment { + clab0 := newClaBuilder("test", nil) + clab0.addLocality("locality-1", 1, 1, []endpointOpts{{addrWithPort: "addr1:314"}}, &addLocalityOptions{ + Health: []v3corepb.HealthStatus{v3corepb.HealthStatus_UNHEALTHY}, + Weight: []uint32{271}, + }) + clab0.addLocality("locality-2", 1, 0, []endpointOpts{{addrWithPort: "addr2:159"}}, &addLocalityOptions{ + Health: []v3corepb.HealthStatus{v3corepb.HealthStatus_DRAINING}, + Weight: []uint32{828}, + }) + return clab0.Build() + }()) + + tests := []struct { + name string + resource *anypb.Any + wantName string + wantUpdate EndpointsUpdate + wantErr bool + }{ + { + name: "non-clusterLoadAssignment resource type", + resource: &anypb.Any{TypeUrl: version.V3HTTPConnManagerURL}, + wantErr: true, + }, + { + name: "badly marshaled clusterLoadAssignment resource", + resource: &anypb.Any{ + TypeUrl: version.V3EndpointsURL, + Value: []byte{1, 2, 3, 4}, + }, + wantErr: true, + }, + { + name: "bad endpoints resource", + resource: testutils.MarshalAny(t, func() *v3endpointpb.ClusterLoadAssignment { + clab0 := newClaBuilder("test", nil) + clab0.addLocality("locality-1", 1, 0, []endpointOpts{{addrWithPort: "addr1:314"}}, nil) + clab0.addLocality("locality-2", 1, 2, []endpointOpts{{addrWithPort: "addr2:159"}}, nil) + return clab0.Build() + }()), + wantName: "test", + wantErr: true, + }, + { + name: "v3 endpoints", + resource: v3EndpointsAny, + wantName: "test", + wantUpdate: EndpointsUpdate{ + Drops: nil, + Localities: []Locality{ + { + Endpoints: []Endpoint{{ + Addresses: []string{"addr1:314"}, + HealthStatus: EndpointHealthStatusUnhealthy, + Weight: 271, + }}, + ID: clients.Locality{SubZone: "locality-1"}, + Priority: 1, + Weight: 1, + }, + { + Endpoints: []Endpoint{{ + Addresses: []string{"addr2:159"}, + HealthStatus: EndpointHealthStatusDraining, + Weight: 828, + }}, + ID: clients.Locality{SubZone: "locality-2"}, + Priority: 0, + Weight: 1, + }, + }, + Raw: v3EndpointsAny, + }, + }, + { + name: "v3 endpoints wrapped", + resource: testutils.MarshalAny(t, &v3discoverypb.Resource{Resource: v3EndpointsAny}), + wantName: "test", + wantUpdate: EndpointsUpdate{ + Drops: nil, + Localities: []Locality{ + { + Endpoints: []Endpoint{{ + Addresses: []string{"addr1:314"}, + HealthStatus: EndpointHealthStatusUnhealthy, + Weight: 271, + }}, + ID: clients.Locality{SubZone: "locality-1"}, + Priority: 1, + Weight: 1, + }, + { + Endpoints: []Endpoint{{ + Addresses: []string{"addr2:159"}, + HealthStatus: EndpointHealthStatusDraining, + Weight: 828, + }}, + ID: clients.Locality{SubZone: "locality-2"}, + Priority: 0, + Weight: 1, + }, + }, + Raw: v3EndpointsAny, + }, + }, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + name, update, err := unmarshalEndpointsResource(test.resource) + if (err != nil) != test.wantErr { + t.Fatalf("unmarshalEndpointsResource(%s), got err: %v, wantErr: %v", pretty.ToJSON(test.resource), err, test.wantErr) + } + if name != test.wantName { + t.Errorf("unmarshalEndpointsResource(%s), got name: %s, want: %s", pretty.ToJSON(test.resource), name, test.wantName) + } + if diff := cmp.Diff(update, test.wantUpdate, cmpOpts); diff != "" { + t.Errorf("unmarshalEndpointsResource(%s), got unexpected update, diff (-got +want): %v", pretty.ToJSON(test.resource), diff) + } + }) + } +} + +// Tests custom metadata parsing for success cases when the +// GRPC_EXPERIMENTAL_XDS_HTTP_CONNECT environment variable is set. +func (s) TestEDSParseRespProto_HTTP_Connect_CustomMetadata_EnvVarOn(t *testing.T) { + testutils.SetEnvConfig(t, &envconfig.XDSHTTPConnectEnabled, true) + tests := []struct { + name string + endpointProto *v3endpointpb.ClusterLoadAssignment + wantEndpoint EndpointsUpdate + }{ + { + name: "typed_filter_metadata_in_endpoint", + endpointProto: func() *v3endpointpb.ClusterLoadAssignment { + clab0 := newClaBuilder("test", nil) + clab0.addLocality("locality-1", 1, 0, []endpointOpts{{ + addrWithPort: "addr1:314", + metadata: &v3corepb.Metadata{ + TypedFilterMetadata: map[string]*anypb.Any{ + "test-key": testutils.MarshalAny(t, &v3corepb.Address{ + Address: &v3corepb.Address_SocketAddress{ + SocketAddress: &v3corepb.SocketAddress{ + Address: "1.2.3.4", + PortSpecifier: &v3corepb.SocketAddress_PortValue{ + PortValue: 1111, + }}, + }, + }), + }, + }, + }}, nil) + return clab0.Build() + }(), + wantEndpoint: EndpointsUpdate{ + Localities: []Locality{ + { + Endpoints: []Endpoint{{ + Addresses: []string{"addr1:314"}, + HealthStatus: EndpointHealthStatusUnknown, + Weight: 1, + Metadata: map[string]any{ + "test-key": ProxyAddressMetadataValue{ + Address: "1.2.3.4:1111", + }, + }, + }}, + ID: clients.Locality{SubZone: "locality-1"}, + Priority: 0, + Weight: 1, + }, + }, + }, + }, + { + name: "filter_metadata_in_endpoint", + endpointProto: func() *v3endpointpb.ClusterLoadAssignment { + clab0 := newClaBuilder("test", nil) + clab0.addLocality("locality-1", 1, 0, []endpointOpts{{ + addrWithPort: "addr1:314", + metadata: &v3corepb.Metadata{ + FilterMetadata: map[string]*structpb.Struct{ + "test-key": { + Fields: map[string]*structpb.Value{ + "key": { + Kind: &structpb.Value_NumberValue{NumberValue: 123.0}, + }, + }, + }, + }, + }, + }}, nil) + return clab0.Build() + }(), + wantEndpoint: EndpointsUpdate{ + Localities: []Locality{ + { + Endpoints: []Endpoint{{ + Addresses: []string{"addr1:314"}, + HealthStatus: EndpointHealthStatusUnknown, + Weight: 1, + Metadata: map[string]any{ + "test-key": StructMetadataValue{Data: map[string]any{ + "key": float64(123), + }}, + }, + }}, + ID: clients.Locality{SubZone: "locality-1"}, + Priority: 0, + Weight: 1, + }, + }, + }, + }, + { + name: "typed_filter_metadata_in_locality", + endpointProto: func() *v3endpointpb.ClusterLoadAssignment { + clab0 := newClaBuilder("test", nil) + clab0.addLocality("locality-1", 1, 0, []endpointOpts{{addrWithPort: "addr1:314"}}, &addLocalityOptions{ + Metadata: &v3corepb.Metadata{ + TypedFilterMetadata: map[string]*anypb.Any{ + "test-key": testutils.MarshalAny(t, &v3corepb.Address{ + Address: &v3corepb.Address_SocketAddress{ + SocketAddress: &v3corepb.SocketAddress{ + Address: "1.2.3.4", + PortSpecifier: &v3corepb.SocketAddress_PortValue{ + PortValue: 1111, + }}, + }, + }), + }, + }, + }) + return clab0.Build() + }(), + wantEndpoint: EndpointsUpdate{ + Localities: []Locality{ + { + Endpoints: []Endpoint{{ + Addresses: []string{"addr1:314"}, + HealthStatus: EndpointHealthStatusUnknown, + Weight: 1, + }}, + ID: clients.Locality{SubZone: "locality-1"}, + Priority: 0, + Weight: 1, + Metadata: map[string]any{ + "test-key": ProxyAddressMetadataValue{ + Address: "1.2.3.4:1111", + }, + }, + }, + }, + }, + }, + { + name: "filter_metadata_in_locality", + endpointProto: func() *v3endpointpb.ClusterLoadAssignment { + clab0 := newClaBuilder("test", nil) + clab0.addLocality("locality-1", 1, 0, []endpointOpts{{addrWithPort: "addr1:314"}}, &addLocalityOptions{ + Metadata: &v3corepb.Metadata{ + FilterMetadata: map[string]*structpb.Struct{ + "test-key": { + Fields: map[string]*structpb.Value{ + "key": { + Kind: &structpb.Value_NumberValue{NumberValue: 123.0}, + }, + }, + }, + }, + }, + }) + return clab0.Build() + }(), + wantEndpoint: EndpointsUpdate{ + Localities: []Locality{ + { + Endpoints: []Endpoint{{ + Addresses: []string{"addr1:314"}, + HealthStatus: EndpointHealthStatusUnknown, + Weight: 1, + }}, + ID: clients.Locality{SubZone: "locality-1"}, + Priority: 0, + Weight: 1, + Metadata: map[string]any{ + "test-key": StructMetadataValue{Data: map[string]any{ + "key": float64(123), + }}, + }, + }, + }, + }, + }, + { + name: "typed_filter_metadata_over_filter_metadata_in_endpoint", + endpointProto: func() *v3endpointpb.ClusterLoadAssignment { + clab0 := newClaBuilder("test", nil) + clab0.addLocality("locality-1", 1, 0, []endpointOpts{{ + addrWithPort: "addr1:314", + metadata: &v3corepb.Metadata{ + TypedFilterMetadata: map[string]*anypb.Any{ + "test-key": testutils.MarshalAny(t, &v3corepb.Address{ + Address: &v3corepb.Address_SocketAddress{ + SocketAddress: &v3corepb.SocketAddress{ + Address: "1.2.3.4", + PortSpecifier: &v3corepb.SocketAddress_PortValue{ + PortValue: 1111, + }}, + }, + }), + }, + FilterMetadata: map[string]*structpb.Struct{ + "test-key": { + Fields: map[string]*structpb.Value{ + "key": { + Kind: &structpb.Value_NumberValue{NumberValue: 123.0}, + }, + }, + }, + }, + }, + }}, nil) + return clab0.Build() + }(), + wantEndpoint: EndpointsUpdate{ + Localities: []Locality{ + { + Endpoints: []Endpoint{{ + Addresses: []string{"addr1:314"}, + HealthStatus: EndpointHealthStatusUnknown, + Weight: 1, + Metadata: map[string]any{ + "test-key": ProxyAddressMetadataValue{ + Address: "1.2.3.4:1111", + }, + }, + }}, + ID: clients.Locality{SubZone: "locality-1"}, + Priority: 0, + Weight: 1, + }, + }, + }, + }, + { + name: "typed_filter_metadata_over_filter_metadata_in_locality", + endpointProto: func() *v3endpointpb.ClusterLoadAssignment { + clab0 := newClaBuilder("test", nil) + clab0.addLocality("locality-1", 1, 0, []endpointOpts{{addrWithPort: "addr1:314"}}, &addLocalityOptions{ + Metadata: &v3corepb.Metadata{ + TypedFilterMetadata: map[string]*anypb.Any{ + "test-key": testutils.MarshalAny(t, &v3corepb.Address{ + Address: &v3corepb.Address_SocketAddress{ + SocketAddress: &v3corepb.SocketAddress{ + Address: "1.2.3.4", + PortSpecifier: &v3corepb.SocketAddress_PortValue{ + PortValue: 1111, + }}, + }, + }), + }, + FilterMetadata: map[string]*structpb.Struct{ + "test-key": { + Fields: map[string]*structpb.Value{ + "key": { + Kind: &structpb.Value_NumberValue{NumberValue: 123.0}, + }, + }, + }, + }, + }, + }) + return clab0.Build() + }(), + wantEndpoint: EndpointsUpdate{ + Localities: []Locality{ + { + Endpoints: []Endpoint{{ + Addresses: []string{"addr1:314"}, + HealthStatus: EndpointHealthStatusUnknown, + Weight: 1, + }}, + ID: clients.Locality{SubZone: "locality-1"}, + Priority: 0, + Weight: 1, + Metadata: map[string]any{ + "test-key": ProxyAddressMetadataValue{ + Address: "1.2.3.4:1111", + }, + }, + }, + }, + }, + }, + { + name: "both_filter_and_typed_filter_metadata_in_endpoint", + endpointProto: func() *v3endpointpb.ClusterLoadAssignment { + clab0 := newClaBuilder("test", nil) + clab0.addLocality("locality-1", 1, 0, []endpointOpts{{ + addrWithPort: "addr1:314", + metadata: &v3corepb.Metadata{ + TypedFilterMetadata: map[string]*anypb.Any{ + "test-key": testutils.MarshalAny(t, &v3corepb.Address{ + Address: &v3corepb.Address_SocketAddress{ + SocketAddress: &v3corepb.SocketAddress{ + Address: "1.2.3.4", + PortSpecifier: &v3corepb.SocketAddress_PortValue{ + PortValue: 1111, + }}, + }, + }), + }, + FilterMetadata: map[string]*structpb.Struct{ + "another-test-key": { + Fields: map[string]*structpb.Value{ + "key": { + Kind: &structpb.Value_NumberValue{NumberValue: 123.0}, + }, + }, + }, + }, + }, + }}, nil) + return clab0.Build() + }(), + wantEndpoint: EndpointsUpdate{ + Localities: []Locality{ + { + Endpoints: []Endpoint{{ + Addresses: []string{"addr1:314"}, + HealthStatus: EndpointHealthStatusUnknown, + Weight: 1, + Metadata: map[string]any{ + "test-key": ProxyAddressMetadataValue{ + Address: "1.2.3.4:1111", + }, + "another-test-key": StructMetadataValue{Data: map[string]any{ + "key": float64(123), + }}, + }, + }}, + ID: clients.Locality{SubZone: "locality-1"}, + Priority: 0, + Weight: 1, + }, + }, + }, + }, + { + name: "both_filter_and_typed_filter_metadata_in_locality", + endpointProto: func() *v3endpointpb.ClusterLoadAssignment { + clab0 := newClaBuilder("test", nil) + clab0.addLocality("locality-1", 1, 0, []endpointOpts{{addrWithPort: "addr1:314"}}, &addLocalityOptions{ + Metadata: &v3corepb.Metadata{ + TypedFilterMetadata: map[string]*anypb.Any{ + "test-key": testutils.MarshalAny(t, &v3corepb.Address{ + Address: &v3corepb.Address_SocketAddress{ + SocketAddress: &v3corepb.SocketAddress{ + Address: "1.2.3.4", + PortSpecifier: &v3corepb.SocketAddress_PortValue{ + PortValue: 1111, + }}, + }, + }), + }, + FilterMetadata: map[string]*structpb.Struct{ + "another-test-key": { + Fields: map[string]*structpb.Value{ + "key": { + Kind: &structpb.Value_NumberValue{NumberValue: 123.0}, + }, + }, + }, + }, + }, + }) + return clab0.Build() + }(), + wantEndpoint: EndpointsUpdate{ + Localities: []Locality{ + { + Endpoints: []Endpoint{{ + Addresses: []string{"addr1:314"}, + HealthStatus: EndpointHealthStatusUnknown, + Weight: 1, + }}, + ID: clients.Locality{SubZone: "locality-1"}, + Priority: 0, + Weight: 1, + Metadata: map[string]any{ + "test-key": ProxyAddressMetadataValue{ + Address: "1.2.3.4:1111", + }, + "another-test-key": StructMetadataValue{Data: map[string]any{ + "key": float64(123), + }}, + }, + }, + }, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := parseEDSRespProto(tt.endpointProto) + if err != nil { + t.Fatalf("parseEDSRespProto() failed: %v", err) + } + if diff := cmp.Diff(tt.wantEndpoint, got, cmpopts.EquateEmpty()); diff != "" { + t.Errorf("parseEDSRespProto() returned unexpected diff (-want +got):\n%s", diff) + } + }) + } +} + +// Tests custom metadata parsing for success cases when the +// GRPC_EXPERIMENTAL_XDS_HTTP_CONNECT environment variable is not set. +func (s) TestEDSParseRespProto_HTTP_Connect_CustomMetadata_EnvVarOff(t *testing.T) { + testutils.SetEnvConfig(t, &envconfig.XDSHTTPConnectEnabled, false) + tests := []struct { + name string + endpointProto *v3endpointpb.ClusterLoadAssignment + wantEndpoint EndpointsUpdate + }{ + { + name: "typed_filter_metadata_in_endpoint", + endpointProto: func() *v3endpointpb.ClusterLoadAssignment { + clab0 := newClaBuilder("test", nil) + clab0.addLocality("locality-1", 1, 0, []endpointOpts{{ + addrWithPort: "addr1:314", + metadata: &v3corepb.Metadata{ + TypedFilterMetadata: map[string]*anypb.Any{ + "test-key": testutils.MarshalAny(t, &v3corepb.Address{ + Address: &v3corepb.Address_SocketAddress{ + SocketAddress: &v3corepb.SocketAddress{ + Address: "1.2.3.4", + PortSpecifier: &v3corepb.SocketAddress_PortValue{ + PortValue: 1111, + }}, + }, + }), + }, + }, + }}, nil) + return clab0.Build() + }(), + wantEndpoint: EndpointsUpdate{ + Localities: []Locality{ + { + Endpoints: []Endpoint{{ + Addresses: []string{"addr1:314"}, + HealthStatus: EndpointHealthStatusUnknown, + Weight: 1, + }}, + ID: clients.Locality{SubZone: "locality-1"}, + Priority: 0, + Weight: 1, + }, + }, + }, + }, + { + name: "filter_metadata_in_endpoint", + endpointProto: func() *v3endpointpb.ClusterLoadAssignment { + clab0 := newClaBuilder("test", nil) + clab0.addLocality("locality-1", 1, 0, []endpointOpts{{ + addrWithPort: "addr1:314", + metadata: &v3corepb.Metadata{ + FilterMetadata: map[string]*structpb.Struct{ + "test-key": { + Fields: map[string]*structpb.Value{ + "key": { + Kind: &structpb.Value_NumberValue{NumberValue: 123.0}, + }, + }, + }, + }, + }, + }}, nil) + return clab0.Build() + }(), + wantEndpoint: EndpointsUpdate{ + Localities: []Locality{ + { + Endpoints: []Endpoint{{ + Addresses: []string{"addr1:314"}, + HealthStatus: EndpointHealthStatusUnknown, + Weight: 1, + }}, + ID: clients.Locality{SubZone: "locality-1"}, + Priority: 0, + Weight: 1, + }, + }, + }, + }, + { + name: "typed_filter_metadata_in_locality", + endpointProto: func() *v3endpointpb.ClusterLoadAssignment { + clab0 := newClaBuilder("test", nil) + clab0.addLocality("locality-1", 1, 0, []endpointOpts{{addrWithPort: "addr1:314"}}, &addLocalityOptions{ + Metadata: &v3corepb.Metadata{ + TypedFilterMetadata: map[string]*anypb.Any{ + "test-key": testutils.MarshalAny(t, &v3corepb.Address{ + Address: &v3corepb.Address_SocketAddress{ + SocketAddress: &v3corepb.SocketAddress{ + Address: "1.2.3.4", + PortSpecifier: &v3corepb.SocketAddress_PortValue{ + PortValue: 1111, + }}, + }, + }), + }, + }, + }) + return clab0.Build() + }(), + wantEndpoint: EndpointsUpdate{ + Localities: []Locality{ + { + Endpoints: []Endpoint{{ + Addresses: []string{"addr1:314"}, + HealthStatus: EndpointHealthStatusUnknown, + Weight: 1, + }}, + ID: clients.Locality{SubZone: "locality-1"}, + Priority: 0, + Weight: 1, + }, + }, + }, + }, + { + name: "filter_metadata_in_locality", + endpointProto: func() *v3endpointpb.ClusterLoadAssignment { + clab0 := newClaBuilder("test", nil) + clab0.addLocality("locality-1", 1, 0, []endpointOpts{{addrWithPort: "addr1:314"}}, &addLocalityOptions{ + Metadata: &v3corepb.Metadata{ + FilterMetadata: map[string]*structpb.Struct{ + "test-key": { + Fields: map[string]*structpb.Value{ + "key": { + Kind: &structpb.Value_NumberValue{NumberValue: 123.0}, + }, + }, + }, + }, + }, + }) + return clab0.Build() + }(), + wantEndpoint: EndpointsUpdate{ + Localities: []Locality{ + { + Endpoints: []Endpoint{{ + Addresses: []string{"addr1:314"}, + HealthStatus: EndpointHealthStatusUnknown, + Weight: 1, + }}, + ID: clients.Locality{SubZone: "locality-1"}, + Priority: 0, + Weight: 1, + }, + }, + }, + }, + { + name: "both_filter_and_typed_filter_metadata_in_endpoint", + endpointProto: func() *v3endpointpb.ClusterLoadAssignment { + clab0 := newClaBuilder("test", nil) + clab0.addLocality("locality-1", 1, 0, []endpointOpts{{ + addrWithPort: "addr1:314", + metadata: &v3corepb.Metadata{ + TypedFilterMetadata: map[string]*anypb.Any{ + "test-key": testutils.MarshalAny(t, &v3corepb.Address{ + Address: &v3corepb.Address_SocketAddress{ + SocketAddress: &v3corepb.SocketAddress{ + Address: "1.2.3.4", + PortSpecifier: &v3corepb.SocketAddress_PortValue{ + PortValue: 1111, + }}, + }, + }), + }, + FilterMetadata: map[string]*structpb.Struct{ + "another-test-key": { + Fields: map[string]*structpb.Value{ + "key": { + Kind: &structpb.Value_NumberValue{NumberValue: 123.0}, + }, + }, + }, + }, + }, + }}, nil) + return clab0.Build() + }(), + wantEndpoint: EndpointsUpdate{ + Localities: []Locality{ + { + Endpoints: []Endpoint{{ + Addresses: []string{"addr1:314"}, + HealthStatus: EndpointHealthStatusUnknown, + Weight: 1, + }}, + ID: clients.Locality{SubZone: "locality-1"}, + Priority: 0, + Weight: 1, + }, + }, + }, + }, + { + name: "both_filter_and_typed_filter_metadata_in_locality", + endpointProto: func() *v3endpointpb.ClusterLoadAssignment { + clab0 := newClaBuilder("test", nil) + clab0.addLocality("locality-1", 1, 0, []endpointOpts{{addrWithPort: "addr1:314"}}, &addLocalityOptions{ + Metadata: &v3corepb.Metadata{ + TypedFilterMetadata: map[string]*anypb.Any{ + "test-key": testutils.MarshalAny(t, &v3corepb.Address{ + Address: &v3corepb.Address_SocketAddress{ + SocketAddress: &v3corepb.SocketAddress{ + Address: "1.2.3.4", + PortSpecifier: &v3corepb.SocketAddress_PortValue{ + PortValue: 1111, + }}, + }, + }), + }, + FilterMetadata: map[string]*structpb.Struct{ + "another-test-key": { + Fields: map[string]*structpb.Value{ + "key": { + Kind: &structpb.Value_NumberValue{NumberValue: 123.0}, + }, + }, + }, + }, + }, + }) + return clab0.Build() + }(), + wantEndpoint: EndpointsUpdate{ + Localities: []Locality{ + { + Endpoints: []Endpoint{{ + Addresses: []string{"addr1:314"}, + HealthStatus: EndpointHealthStatusUnknown, + Weight: 1, + }}, + ID: clients.Locality{SubZone: "locality-1"}, + Priority: 0, + Weight: 1, + }, + }, + }, + }, + { + name: "converter_failure_is_not_triggerred", + endpointProto: func() *v3endpointpb.ClusterLoadAssignment { + clab0 := newClaBuilder("test", nil) + clab0.addLocality("locality-1", 1, 0, []endpointOpts{{ + addrWithPort: "addr1:314", + metadata: &v3corepb.Metadata{ + TypedFilterMetadata: map[string]*anypb.Any{ + "envoy.http11_proxy_transport_socket.proxy_address": testutils.MarshalAny(t, &v3corepb.Address{ + Address: &v3corepb.Address_SocketAddress{ + SocketAddress: &v3corepb.SocketAddress{ + Address: "invalid", + }, + }, + }), + }, + }, + }}, &addLocalityOptions{ + Metadata: &v3corepb.Metadata{ + TypedFilterMetadata: map[string]*anypb.Any{ + "envoy.http11_proxy_transport_socket.proxy_address": testutils.MarshalAny(t, &v3corepb.Address{ + Address: &v3corepb.Address_SocketAddress{ + SocketAddress: &v3corepb.SocketAddress{ + Address: "invalid", + }, + }, + }), + }, + }, + }) + return clab0.Build() + }(), + wantEndpoint: EndpointsUpdate{ + Localities: []Locality{ + { + Endpoints: []Endpoint{{ + Addresses: []string{"addr1:314"}, + HealthStatus: EndpointHealthStatusUnknown, + Weight: 1, + }}, + ID: clients.Locality{SubZone: "locality-1"}, + Priority: 0, + Weight: 1, + }, + }, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := parseEDSRespProto(tt.endpointProto) + if err != nil { + t.Fatalf("parseEDSRespProto() failed: %v", err) + } + if diff := cmp.Diff(tt.wantEndpoint, got, cmpopts.EquateEmpty()); diff != "" { + t.Errorf("parseEDSRespProto() returned unexpected diff (-want +got):\n%s", diff) + } + }) + } +} + +// Tests custom metadata parsing for converter failure cases when the +// GRPC_EXPERIMENTAL_XDS_HTTP_CONNECT environment variable is set. +func (s) TestEDSParseRespProto_HTTP_Connect_CustomMetadata_ConverterFailure(t *testing.T) { + testutils.SetEnvConfig(t, &envconfig.XDSHTTPConnectEnabled, true) + tests := []struct { + name string + endpointProto *v3endpointpb.ClusterLoadAssignment + }{ + { + name: "converter_failure_in_endpoint", + endpointProto: func() *v3endpointpb.ClusterLoadAssignment { + clab0 := newClaBuilder("test", nil) + clab0.addLocality("locality-1", 1, 0, []endpointOpts{{ + addrWithPort: "addr1:314", + metadata: &v3corepb.Metadata{ + TypedFilterMetadata: map[string]*anypb.Any{ + "envoy.http11_proxy_transport_socket.proxy_address": testutils.MarshalAny(t, &v3corepb.Address{ + Address: &v3corepb.Address_SocketAddress{ + SocketAddress: &v3corepb.SocketAddress{ + Address: "invalid", + }, + }, + }), + }, + }, + }}, nil) + return clab0.Build() + }(), + }, + { + name: "converter_failure_in_locality", + endpointProto: func() *v3endpointpb.ClusterLoadAssignment { + clab0 := newClaBuilder("test", nil) + clab0.addLocality("locality-1", 1, 0, []endpointOpts{{addrWithPort: "addr1:314"}}, &addLocalityOptions{ + Metadata: &v3corepb.Metadata{ + TypedFilterMetadata: map[string]*anypb.Any{ + "envoy.http11_proxy_transport_socket.proxy_address": testutils.MarshalAny(t, &v3corepb.Address{ + Address: &v3corepb.Address_SocketAddress{ + SocketAddress: &v3corepb.SocketAddress{ + Address: "invalid", + }, + }, + }), + }, + }, + }) + return clab0.Build() + }(), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if _, err := parseEDSRespProto(tt.endpointProto); err == nil { + t.Fatalf("parseEDSRespProto() did not return error when expected") + } + }) + } +} + +// claBuilder builds a ClusterLoadAssignment, aka EDS +// response. +type claBuilder struct { + v *v3endpointpb.ClusterLoadAssignment +} + +// newClaBuilder creates a claBuilder. +func newClaBuilder(clusterName string, dropPercents []uint32) *claBuilder { + var drops []*v3endpointpb.ClusterLoadAssignment_Policy_DropOverload + for i, d := range dropPercents { + drops = append(drops, &v3endpointpb.ClusterLoadAssignment_Policy_DropOverload{ + Category: fmt.Sprintf("test-drop-%d", i), + DropPercentage: &v3typepb.FractionalPercent{ + Numerator: d, + Denominator: v3typepb.FractionalPercent_HUNDRED, + }, + }) + } + + return &claBuilder{ + v: &v3endpointpb.ClusterLoadAssignment{ + ClusterName: clusterName, + Policy: &v3endpointpb.ClusterLoadAssignment_Policy{ + DropOverloads: drops, + }, + }, + } +} + +// addLocalityOptions contains options when adding locality to the builder. +type addLocalityOptions struct { + Health []v3corepb.HealthStatus + Weight []uint32 + Metadata *v3corepb.Metadata +} + +type endpointOpts struct { + addrWithPort string + additionalAddrWithPorts []string + metadata *v3corepb.Metadata +} + +func addressFromStr(addrWithPort string) *v3corepb.Address { + host, portStr, err := net.SplitHostPort(addrWithPort) + if err != nil { + panic("failed to split " + addrWithPort) + } + port, err := strconv.Atoi(portStr) + if err != nil { + panic("failed to atoi " + portStr) + } + + return &v3corepb.Address{ + Address: &v3corepb.Address_SocketAddress{ + SocketAddress: &v3corepb.SocketAddress{ + Protocol: v3corepb.SocketAddress_TCP, + Address: host, + PortSpecifier: &v3corepb.SocketAddress_PortValue{PortValue: uint32(port)}, + }, + }, + } +} + +// addLocality adds a locality to the builder. +func (clab *claBuilder) addLocality(subzone string, weight uint32, priority uint32, endpoints []endpointOpts, opts *addLocalityOptions) { + var lbEndPoints []*v3endpointpb.LbEndpoint + for i, e := range endpoints { + var additionalAddrs []*v3endpointpb.Endpoint_AdditionalAddress + for _, a := range e.additionalAddrWithPorts { + additionalAddrs = append(additionalAddrs, &v3endpointpb.Endpoint_AdditionalAddress{ + Address: addressFromStr(a), + }) + } + lbe := &v3endpointpb.LbEndpoint{ + HostIdentifier: &v3endpointpb.LbEndpoint_Endpoint{ + Endpoint: &v3endpointpb.Endpoint{ + Address: addressFromStr(e.addrWithPort), + AdditionalAddresses: additionalAddrs, + }, + }, + Metadata: e.metadata, + } + if opts != nil { + if i < len(opts.Health) { + lbe.HealthStatus = opts.Health[i] + } + if i < len(opts.Weight) { + lbe.LoadBalancingWeight = &wrapperspb.UInt32Value{Value: opts.Weight[i]} + } + } + lbEndPoints = append(lbEndPoints, lbe) + } + + var localityID *v3corepb.Locality + if subzone != "" { + localityID = &v3corepb.Locality{ + Region: "", + Zone: "", + SubZone: subzone, + } + } + + locality := &v3endpointpb.LocalityLbEndpoints{ + Locality: localityID, + LbEndpoints: lbEndPoints, + LoadBalancingWeight: &wrapperspb.UInt32Value{Value: weight}, + Priority: priority, + } + if opts != nil { + locality.Metadata = opts.Metadata + } + clab.v.Endpoints = append(clab.v.Endpoints, locality) +} + +// Build builds ClusterLoadAssignment. +func (clab *claBuilder) Build() *v3endpointpb.ClusterLoadAssignment { + return clab.v +} diff --git a/xds/internal/xdsclient/xdsresource/unmarshal_lds.go b/internal/xds/xdsclient/xdsresource/unmarshal_lds.go similarity index 99% rename from xds/internal/xdsclient/xdsresource/unmarshal_lds.go rename to internal/xds/xdsclient/xdsresource/unmarshal_lds.go index 475300cefcc0..25c607b48a4d 100644 --- a/xds/internal/xdsclient/xdsresource/unmarshal_lds.go +++ b/internal/xds/xdsclient/xdsresource/unmarshal_lds.go @@ -27,7 +27,7 @@ import ( v3listenerpb "github.com/envoyproxy/go-control-plane/envoy/config/listener/v3" v3routepb "github.com/envoyproxy/go-control-plane/envoy/config/route/v3" v3httppb "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/network/http_connection_manager/v3" - "google.golang.org/grpc/xds/internal/httpfilter" + "google.golang.org/grpc/internal/xds/httpfilter" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/types/known/anypb" ) diff --git a/xds/internal/xdsclient/xdsresource/unmarshal_lds_test.go b/internal/xds/xdsclient/xdsresource/unmarshal_lds_test.go similarity index 99% rename from xds/internal/xdsclient/xdsresource/unmarshal_lds_test.go rename to internal/xds/xdsclient/xdsresource/unmarshal_lds_test.go index 900afdd311b0..b652c722781f 100644 --- a/xds/internal/xdsclient/xdsresource/unmarshal_lds_test.go +++ b/internal/xds/xdsclient/xdsresource/unmarshal_lds_test.go @@ -28,8 +28,8 @@ import ( "google.golang.org/grpc/internal/pretty" "google.golang.org/grpc/internal/testutils" "google.golang.org/grpc/internal/testutils/xds/e2e" - "google.golang.org/grpc/xds/internal/httpfilter" - "google.golang.org/grpc/xds/internal/xdsclient/xdsresource/version" + "google.golang.org/grpc/internal/xds/httpfilter" + "google.golang.org/grpc/internal/xds/xdsclient/xdsresource/version" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/types/known/anypb" "google.golang.org/protobuf/types/known/durationpb" @@ -48,8 +48,8 @@ import ( v3discoverypb "github.com/envoyproxy/go-control-plane/envoy/service/discovery/v3" v3matcherpb "github.com/envoyproxy/go-control-plane/envoy/type/matcher/v3" - _ "google.golang.org/grpc/xds/internal/httpfilter/rbac" // Register the RBAC HTTP filter. - _ "google.golang.org/grpc/xds/internal/httpfilter/router" // Register the router filter. + _ "google.golang.org/grpc/internal/xds/httpfilter/rbac" // Register the RBAC HTTP filter. + _ "google.golang.org/grpc/internal/xds/httpfilter/router" // Register the router filter. ) func (s) TestUnmarshalListener_ClientSide(t *testing.T) { diff --git a/xds/internal/xdsclient/xdsresource/unmarshal_rds.go b/internal/xds/xdsclient/xdsresource/unmarshal_rds.go similarity index 99% rename from xds/internal/xdsclient/xdsresource/unmarshal_rds.go rename to internal/xds/xdsclient/xdsresource/unmarshal_rds.go index db862514eb58..beab03ebb327 100644 --- a/xds/internal/xdsclient/xdsresource/unmarshal_rds.go +++ b/internal/xds/xdsclient/xdsresource/unmarshal_rds.go @@ -25,8 +25,8 @@ import ( "time" "google.golang.org/grpc/codes" + "google.golang.org/grpc/internal/xds/clusterspecifier" "google.golang.org/grpc/internal/xds/matcher" - "google.golang.org/grpc/xds/internal/clusterspecifier" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/types/known/anypb" diff --git a/xds/internal/xdsclient/xdsresource/unmarshal_rds_test.go b/internal/xds/xdsclient/xdsresource/unmarshal_rds_test.go similarity index 99% rename from xds/internal/xdsclient/xdsresource/unmarshal_rds_test.go rename to internal/xds/xdsclient/xdsresource/unmarshal_rds_test.go index c545ba45e996..622ef7df0881 100644 --- a/xds/internal/xdsclient/xdsresource/unmarshal_rds_test.go +++ b/internal/xds/xdsclient/xdsresource/unmarshal_rds_test.go @@ -31,10 +31,10 @@ import ( "google.golang.org/grpc/codes" "google.golang.org/grpc/internal/pretty" "google.golang.org/grpc/internal/testutils" + "google.golang.org/grpc/internal/xds/clusterspecifier" + "google.golang.org/grpc/internal/xds/httpfilter" "google.golang.org/grpc/internal/xds/matcher" - "google.golang.org/grpc/xds/internal/clusterspecifier" - "google.golang.org/grpc/xds/internal/httpfilter" - "google.golang.org/grpc/xds/internal/xdsclient/xdsresource/version" + "google.golang.org/grpc/internal/xds/xdsclient/xdsresource/version" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/types/known/anypb" "google.golang.org/protobuf/types/known/durationpb" diff --git a/xds/internal/xdsclient/xdsresource/version/version.go b/internal/xds/xdsclient/xdsresource/version/version.go similarity index 100% rename from xds/internal/xdsclient/xdsresource/version/version.go rename to internal/xds/xdsclient/xdsresource/version/version.go diff --git a/interop/observability/Dockerfile b/interop/observability/Dockerfile index e4e3a3c7b200..32cfb8109866 100644 --- a/interop/observability/Dockerfile +++ b/interop/observability/Dockerfile @@ -17,7 +17,7 @@ # Stage 1: Build the interop test client and server # -FROM golang:1.23-bullseye as build +FROM golang:1.24-bullseye as build WORKDIR /grpc-go COPY . . @@ -36,7 +36,7 @@ RUN go build -o server/ server/server.go && \ # with the given parameters. # -FROM golang:1.23-bullseye +FROM golang:1.24-bullseye ENV GRPC_GO_LOG_SEVERITY_LEVEL info ENV GRPC_GO_LOG_VERBOSITY_LEVEL 2 diff --git a/interop/observability/go.mod b/interop/observability/go.mod index 48f04f389e0b..8bb16a206b59 100644 --- a/interop/observability/go.mod +++ b/interop/observability/go.mod @@ -1,15 +1,15 @@ module google.golang.org/grpc/interop/observability -go 1.23.0 +go 1.24.0 require ( - google.golang.org/grpc v1.73.0 + google.golang.org/grpc v1.74.2 google.golang.org/grpc/gcp/observability v1.0.1 ) require ( - cloud.google.com/go v0.121.3 // indirect - cloud.google.com/go/auth v0.16.2 // indirect + cloud.google.com/go v0.121.4 // indirect + cloud.google.com/go/auth v0.16.3 // indirect cloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect cloud.google.com/go/compute/metadata v0.7.0 // indirect cloud.google.com/go/logging v1.13.0 // indirect @@ -17,19 +17,19 @@ require ( cloud.google.com/go/monitoring v1.24.2 // indirect cloud.google.com/go/trace v1.11.6 // indirect contrib.go.opencensus.io/exporter/stackdriver v0.13.15-0.20230702191903-2de6d2748484 // indirect - github.com/aws/aws-sdk-go-v2 v1.36.5 // indirect - github.com/aws/aws-sdk-go-v2/config v1.29.17 // indirect - github.com/aws/aws-sdk-go-v2/credentials v1.17.70 // indirect - github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.32 // indirect - github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.36 // indirect - github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.36 // indirect + github.com/aws/aws-sdk-go-v2 v1.37.2 // indirect + github.com/aws/aws-sdk-go-v2/config v1.30.3 // indirect + github.com/aws/aws-sdk-go-v2/credentials v1.18.3 // indirect + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.2 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.2 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.2 // indirect github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.4 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.17 // indirect - github.com/aws/aws-sdk-go-v2/service/sso v1.25.5 // indirect - github.com/aws/aws-sdk-go-v2/service/ssooidc v1.30.3 // indirect - github.com/aws/aws-sdk-go-v2/service/sts v1.34.0 // indirect - github.com/aws/smithy-go v1.22.4 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.0 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.2 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.27.0 // indirect + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.32.0 // indirect + github.com/aws/aws-sdk-go-v2/service/sts v1.36.0 // indirect + github.com/aws/smithy-go v1.22.5 // indirect github.com/census-instrumentation/opencensus-proto v0.4.1 // indirect github.com/cncf/xds/go v0.0.0-20250501225837-2ac532fd4443 // indirect github.com/envoyproxy/protoc-gen-validate v1.2.1 // indirect @@ -41,7 +41,7 @@ require ( github.com/google/s2a-go v0.1.9 // indirect github.com/google/uuid v1.6.0 // indirect github.com/googleapis/enterprise-certificate-proxy v0.3.6 // indirect - github.com/googleapis/gax-go/v2 v2.14.2 // indirect + github.com/googleapis/gax-go/v2 v2.15.0 // indirect go.opencensus.io v0.24.0 // indirect go.opentelemetry.io/auto/sdk v1.1.0 // indirect go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.62.0 // indirect @@ -49,17 +49,17 @@ require ( go.opentelemetry.io/otel v1.37.0 // indirect go.opentelemetry.io/otel/metric v1.37.0 // indirect go.opentelemetry.io/otel/trace v1.37.0 // indirect - golang.org/x/crypto v0.39.0 // indirect - golang.org/x/net v0.41.0 // indirect + golang.org/x/crypto v0.40.0 // indirect + golang.org/x/net v0.42.0 // indirect golang.org/x/oauth2 v0.30.0 // indirect - golang.org/x/sync v0.15.0 // indirect - golang.org/x/sys v0.33.0 // indirect - golang.org/x/text v0.26.0 // indirect + golang.org/x/sync v0.16.0 // indirect + golang.org/x/sys v0.34.0 // indirect + golang.org/x/text v0.27.0 // indirect golang.org/x/time v0.12.0 // indirect - google.golang.org/api v0.240.0 // indirect - google.golang.org/genproto v0.0.0-20250707201910-8d1bb00bc6a7 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20250707201910-8d1bb00bc6a7 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20250707201910-8d1bb00bc6a7 // indirect + google.golang.org/api v0.245.0 // indirect + google.golang.org/genproto v0.0.0-20250804133106-a7a43d27e69b // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20250804133106-a7a43d27e69b // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20250804133106-a7a43d27e69b // indirect google.golang.org/grpc/stats/opencensus v1.0.0 // indirect google.golang.org/protobuf v1.36.6 // indirect ) diff --git a/interop/observability/go.sum b/interop/observability/go.sum index f4164b31c8ef..4c0560786875 100644 --- a/interop/observability/go.sum +++ b/interop/observability/go.sum @@ -42,8 +42,8 @@ cloud.google.com/go v0.110.0/go.mod h1:SJnCLqQ0FCFGSZMUNUf84MV3Aia54kn7pi8st7tMz cloud.google.com/go v0.110.2/go.mod h1:k04UEeEtb6ZBRTv3dZz4CeJC3jKGxyhl0sAiVVquxiw= cloud.google.com/go v0.110.4/go.mod h1:+EYjdK8e5RME/VY/qLCAtuyALQ9q67dvuum8i+H5xsI= cloud.google.com/go v0.110.6/go.mod h1:+EYjdK8e5RME/VY/qLCAtuyALQ9q67dvuum8i+H5xsI= -cloud.google.com/go v0.121.3 h1:84RD+hQXNdY5Sw/MWVAx5O9Aui/rd5VQ9HEcdN19afo= -cloud.google.com/go v0.121.3/go.mod h1:6vWF3nJWRrEUv26mMB3FEIU/o1MQNVPG1iHdisa2SJc= +cloud.google.com/go v0.121.4 h1:cVvUiY0sX0xwyxPwdSU2KsF9knOVmtRyAMt8xou0iTs= +cloud.google.com/go v0.121.4/go.mod h1:XEBchUiHFJbz4lKBZwYBDHV/rSyfFktk737TLDU089s= cloud.google.com/go/accessapproval v1.4.0/go.mod h1:zybIuC3KpDOvotz59lFe5qxRZx6C75OtwbisN56xYB4= cloud.google.com/go/accessapproval v1.5.0/go.mod h1:HFy3tuiGvMdcd/u+Cu5b9NkO1pEICJ46IR82PoUdplw= cloud.google.com/go/accessapproval v1.6.0/go.mod h1:R0EiYnwV5fsRFiKZkPHr6mwyk2wxUJ30nL4j2pcFY2E= @@ -120,8 +120,8 @@ cloud.google.com/go/assuredworkloads v1.8.0/go.mod h1:AsX2cqyNCOvEQC8RMPnoc0yEar cloud.google.com/go/assuredworkloads v1.9.0/go.mod h1:kFuI1P78bplYtT77Tb1hi0FMxM0vVpRC7VVoJC3ZoT0= cloud.google.com/go/assuredworkloads v1.10.0/go.mod h1:kwdUQuXcedVdsIaKgKTp9t0UJkE5+PAVNhdQm4ZVq2E= cloud.google.com/go/assuredworkloads v1.11.1/go.mod h1:+F04I52Pgn5nmPG36CWFtxmav6+7Q+c5QyJoL18Lry0= -cloud.google.com/go/auth v0.16.2 h1:QvBAGFPLrDeoiNjyfVunhQ10HKNYuOwZ5noee0M5df4= -cloud.google.com/go/auth v0.16.2/go.mod h1:sRBas2Y1fB1vZTdurouM0AzuYQBMZinrUYL8EufhtEA= +cloud.google.com/go/auth v0.16.3 h1:kabzoQ9/bobUmnseYnBO6qQG7q4a/CffFRlJSxv2wCc= +cloud.google.com/go/auth v0.16.3/go.mod h1:NucRGjaXfzP1ltpcQ7On/VTZ0H4kWB5Jy+Y9Dnm76fA= cloud.google.com/go/auth/oauth2adapt v0.2.8 h1:keo8NaayQZ6wimpNSmW5OPc283g65QNIiLpZnkHRbnc= cloud.google.com/go/auth/oauth2adapt v0.2.8/go.mod h1:XQ9y31RkqZCcwJWNSx2Xvric3RrU88hAYYbjDWYDL+c= cloud.google.com/go/automl v1.5.0/go.mod h1:34EjfoFGMZ5sgJ9EoLsRtdPSNZLcfflJR39VbVNS2M0= @@ -836,32 +836,32 @@ github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6l github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU= github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g= -github.com/aws/aws-sdk-go-v2 v1.36.5 h1:0OF9RiEMEdDdZEMqF9MRjevyxAQcf6gY+E7vwBILFj0= -github.com/aws/aws-sdk-go-v2 v1.36.5/go.mod h1:EYrzvCCN9CMUTa5+6lf6MM4tq3Zjp8UhSGR/cBsjai0= -github.com/aws/aws-sdk-go-v2/config v1.29.17 h1:jSuiQ5jEe4SAMH6lLRMY9OVC+TqJLP5655pBGjmnjr0= -github.com/aws/aws-sdk-go-v2/config v1.29.17/go.mod h1:9P4wwACpbeXs9Pm9w1QTh6BwWwJjwYvJ1iCt5QbCXh8= -github.com/aws/aws-sdk-go-v2/credentials v1.17.70 h1:ONnH5CM16RTXRkS8Z1qg7/s2eDOhHhaXVd72mmyv4/0= -github.com/aws/aws-sdk-go-v2/credentials v1.17.70/go.mod h1:M+lWhhmomVGgtuPOhO85u4pEa3SmssPTdcYpP/5J/xc= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.32 h1:KAXP9JSHO1vKGCr5f4O6WmlVKLFFXgWYAGoJosorxzU= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.32/go.mod h1:h4Sg6FQdexC1yYG9RDnOvLbW1a/P986++/Y/a+GyEM8= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.36 h1:SsytQyTMHMDPspp+spo7XwXTP44aJZZAC7fBV2C5+5s= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.36/go.mod h1:Q1lnJArKRXkenyog6+Y+zr7WDpk4e6XlR6gs20bbeNo= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.36 h1:i2vNHQiXUvKhs3quBR6aqlgJaiaexz/aNvdCktW/kAM= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.36/go.mod h1:UdyGa7Q91id/sdyHPwth+043HhmP6yP9MBHgbZM0xo8= +github.com/aws/aws-sdk-go-v2 v1.37.2 h1:xkW1iMYawzcmYFYEV0UCMxc8gSsjCGEhBXQkdQywVbo= +github.com/aws/aws-sdk-go-v2 v1.37.2/go.mod h1:9Q0OoGQoboYIAJyslFyF1f5K1Ryddop8gqMhWx/n4Wg= +github.com/aws/aws-sdk-go-v2/config v1.30.3 h1:utupeVnE3bmB221W08P0Moz1lDI3OwYa2fBtUhl7TCc= +github.com/aws/aws-sdk-go-v2/config v1.30.3/go.mod h1:NDGwOEBdpyZwLPlQkpKIO7frf18BW8PaCmAM9iUxQmI= +github.com/aws/aws-sdk-go-v2/credentials v1.18.3 h1:ptfyXmv+ooxzFwyuBth0yqABcjVIkjDL0iTYZBSbum8= +github.com/aws/aws-sdk-go-v2/credentials v1.18.3/go.mod h1:Q43Nci++Wohb0qUh4m54sNln0dbxJw8PvQWkrwOkGOI= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.2 h1:nRniHAvjFJGUCl04F3WaAj7qp/rcz5Gi1OVoj5ErBkc= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.2/go.mod h1:eJDFKAMHHUvv4a0Zfa7bQb//wFNUXGrbFpYRCHe2kD0= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.2 h1:sPiRHLVUIIQcoVZTNwqQcdtjkqkPopyYmIX0M5ElRf4= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.2/go.mod h1:ik86P3sgV+Bk7c1tBFCwI3VxMoSEwl4YkRB9xn1s340= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.2 h1:ZdzDAg075H6stMZtbD2o+PyB933M/f20e9WmCBC17wA= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.2/go.mod h1:eE1IIzXG9sdZCB0pNNpMpsYTLl4YdOQD3njiVN1e/E4= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3 h1:bIqFDwgGXXN1Kpp99pDOdKMTTb5d2KyU5X/BZxjOkRo= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3/go.mod h1:H5O/EsxDWyU+LP/V8i5sm8cxoZgc2fdNR9bxlOFrQTo= -github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.4 h1:CXV68E2dNqhuynZJPB80bhPQwAKqBWVer887figW6Jc= -github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.4/go.mod h1:/xFi9KtvBXP97ppCz1TAEvU1Uf66qvid89rbem3wCzQ= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.17 h1:t0E6FzREdtCsiLIoLCWsYliNsRBgyGD/MCK571qk4MI= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.17/go.mod h1:ygpklyoaypuyDvOM5ujWGrYWpAK3h7ugnmKCU/76Ys4= -github.com/aws/aws-sdk-go-v2/service/sso v1.25.5 h1:AIRJ3lfb2w/1/8wOOSqYb9fUKGwQbtysJ2H1MofRUPg= -github.com/aws/aws-sdk-go-v2/service/sso v1.25.5/go.mod h1:b7SiVprpU+iGazDUqvRSLf5XmCdn+JtT1on7uNL6Ipc= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.30.3 h1:BpOxT3yhLwSJ77qIY3DoHAQjZsc4HEGfMCE4NGy3uFg= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.30.3/go.mod h1:vq/GQR1gOFLquZMSrxUK/cpvKCNVYibNyJ1m7JrU88E= -github.com/aws/aws-sdk-go-v2/service/sts v1.34.0 h1:NFOJ/NXEGV4Rq//71Hs1jC/NvPs1ezajK+yQmkwnPV0= -github.com/aws/aws-sdk-go-v2/service/sts v1.34.0/go.mod h1:7ph2tGpfQvwzgistp2+zga9f+bCjlQJPkPUmMgDSD7w= -github.com/aws/smithy-go v1.22.4 h1:uqXzVZNuNexwc/xrh6Tb56u89WDlJY6HS+KC0S4QSjw= -github.com/aws/smithy-go v1.22.4/go.mod h1:t1ufH5HMublsJYulve2RKmHDC15xu1f26kHCp/HgceI= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.0 h1:6+lZi2JeGKtCraAj1rpoZfKqnQ9SptseRZioejfUOLM= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.0/go.mod h1:eb3gfbVIxIoGgJsi9pGne19dhCBpK6opTYpQqAmdy44= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.2 h1:oxmDEO14NBZJbK/M8y3brhMFEIGN4j8a6Aq8eY0sqlo= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.2/go.mod h1:4hH+8QCrk1uRWDPsVfsNDUup3taAjO8Dnx63au7smAU= +github.com/aws/aws-sdk-go-v2/service/sso v1.27.0 h1:j7/jTOjWeJDolPwZ/J4yZ7dUsxsWZEsxNwH5O7F8eEA= +github.com/aws/aws-sdk-go-v2/service/sso v1.27.0/go.mod h1:M0xdEPQtgpNT7kdAX4/vOAPkFj60hSQRb7TvW9B0iug= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.32.0 h1:ywQF2N4VjqX+Psw+jLjMmUL2g1RDHlvri3NxHA08MGI= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.32.0/go.mod h1:Z+qv5Q6b7sWiclvbJyPSOT1BRVU9wfSUPaqQzZ1Xg3E= +github.com/aws/aws-sdk-go-v2/service/sts v1.36.0 h1:bRP/a9llXSSgDPk7Rqn5GD/DQCGo6uk95plBFKoXt2M= +github.com/aws/aws-sdk-go-v2/service/sts v1.36.0/go.mod h1:tgBsFzxwl65BWkuJ/x2EUs59bD4SfYKgikvFDJi1S58= +github.com/aws/smithy-go v1.22.5 h1:P9ATCXPMb2mPjYBgueqJNCA5S9UfktsW0tTxi+a7eqw= +github.com/aws/smithy-go v1.22.5/go.mod h1:t1ufH5HMublsJYulve2RKmHDC15xu1f26kHCp/HgceI= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= @@ -919,9 +919,11 @@ github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaB github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE= github.com/envoyproxy/go-control-plane v0.10.3/go.mod h1:fJJn/j26vwOu972OllsvAgJJM//w9BV6Fxbg2LuVd34= github.com/envoyproxy/go-control-plane v0.11.0/go.mod h1:VnHyVMpzcLvCFt9yUz1UnCwHLhwx1WguiVDV7pTG/tI= +github.com/envoyproxy/go-control-plane v0.13.4 h1:zEqyPVyku6IvWCFwux4x9RxkLOMUL+1vC9xUFv5l2/M= github.com/envoyproxy/go-control-plane v0.13.4/go.mod h1:kDfuBlDVsSj2MjrLEtRWtHlsWIFcGyB2RMO44Dc5GZA= github.com/envoyproxy/go-control-plane/envoy v1.32.2/go.mod h1:eR2SOX2IedqlPvmiKjUH7Wu//S602JKI7HPC/L3SRq8= github.com/envoyproxy/go-control-plane/envoy v1.32.3/go.mod h1:F6hWupPfh75TBXGKA++MCT/CZHFq5r9/uwt/kQYkZfE= +github.com/envoyproxy/go-control-plane/envoy v1.32.4 h1:jb83lalDRZSpPWW2Z7Mck/8kXZ5CQAFYVjQcdVIr83A= github.com/envoyproxy/go-control-plane/envoy v1.32.4/go.mod h1:Gzjc5k8JcJswLjAx1Zm+wSYE20UrLtt7JZMWiWQXQEw= github.com/envoyproxy/go-control-plane/ratelimit v0.1.0/go.mod h1:Wk+tMFAFbCXaJPzVVHnPgRKdUdwW/KdbRt94AzgRee4= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= @@ -960,7 +962,7 @@ github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2 github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20231223183121-56fa3ac82ce7/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-jose/go-jose/v4 v4.0.4/go.mod h1:NKb5HO1EZccyMpiZNbdUw/14tiXNyUJh188dfnMCAfc= -github.com/go-jose/go-jose/v4 v4.1.1/go.mod h1:BdsZGqgdO3b6tTc6LSE56wcDbMMLuPsw5d4ZD5f94kA= +github.com/go-jose/go-jose/v4 v4.1.2/go.mod h1:22cg9HWM1pOlnRiY+9cQYJ9XHmya1bYW8OeDM6Ku6Oo= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o= @@ -1111,8 +1113,8 @@ github.com/googleapis/gax-go/v2 v2.7.1/go.mod h1:4orTrqY6hXxxaUL4LHIPl6lGo8vAE38 github.com/googleapis/gax-go/v2 v2.8.0/go.mod h1:4orTrqY6hXxxaUL4LHIPl6lGo8vAE38/qKbhSAKP6QI= github.com/googleapis/gax-go/v2 v2.10.0/go.mod h1:4UOEnMCrxsSqQ940WnTiD6qJ63le2ev3xfyagutxiPw= github.com/googleapis/gax-go/v2 v2.11.0/go.mod h1:DxmR61SGKkGLa2xigwuZIQpkCI2S5iydzRfb3peWZJI= -github.com/googleapis/gax-go/v2 v2.14.2 h1:eBLnkZ9635krYIPD+ag1USrOAI0Nr0QYF3+/3GqO0k0= -github.com/googleapis/gax-go/v2 v2.14.2/go.mod h1:ON64QhlJkhVtSqp4v1uaK92VyZ2gmvDQsweuyLV+8+w= +github.com/googleapis/gax-go/v2 v2.15.0 h1:SyjDc1mGgZU5LncH8gimWo9lW1DtIfPibOG81vgd/bo= +github.com/googleapis/gax-go/v2 v2.15.0/go.mod h1:zVVkkxAQHa1RQpg9z2AUCMnKhi0Qld9rcmyfL1OZhoc= github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4= github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= @@ -1255,6 +1257,7 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA= github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= +github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 h1:GFCKgmp0tecUJ0sJuv4pzYCqS9+RGSn52M3FUwPs+uo= github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10/go.mod h1:t/avpk3KcrXxUnYOhZhMXJlSEyie6gQbtLq5NM3loB8= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= @@ -1442,8 +1445,9 @@ golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ss golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc= golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc= golang.org/x/crypto v0.38.0/go.mod h1:MvrbAqul58NNYPKnOra203SB9vpuZW0e+RRZV+Ggqjw= -golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM= golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U= +golang.org/x/crypto v0.40.0 h1:r4x+VvoG5Fm+eJcxMaY8CQM7Lb0l1lsmjGBQ6s8BfKM= +golang.org/x/crypto v0.40.0/go.mod h1:Qr1vMER5WyS2dfPHAlsOj01wgLbsyWtFn/aY+5+ZdxY= golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -1620,8 +1624,9 @@ golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k= golang.org/x/net v0.37.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8= golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds= -golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw= golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA= +golang.org/x/net v0.42.0 h1:jzkYrhi3YQWD6MLBJcsklgQsoAcw89EcZbJw8Z614hs= +golang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -1679,8 +1684,9 @@ golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sync v0.14.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= -golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8= golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw= +golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -1790,8 +1796,9 @@ golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= -golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA= +golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE= golang.org/x/telemetry v0.0.0-20240521205824-bda55230c457/go.mod h1:pRgIJT+bRLFKnoM1ldnzKoxTIn14Yxz928LQRYYgIN0= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= @@ -1820,6 +1827,7 @@ golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM= golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek= golang.org/x/term v0.30.0/go.mod h1:NYYFdzHoI5wRh/h5tDMdMqCqPJZEuNqVR5xJLd/n67g= golang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ= +golang.org/x/term v0.33.0/go.mod h1:s18+ql9tYWp1IfpV9DmCtQDDSRBUjKaw9M1eAv5UeF0= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1848,8 +1856,9 @@ golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY= golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4= golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA= -golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M= golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA= +golang.org/x/text v0.27.0 h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4= +golang.org/x/text v0.27.0/go.mod h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -1935,6 +1944,7 @@ golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxb golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c= golang.org/x/tools v0.26.0/go.mod h1:TPVVj70c7JJ3WCazhD8OdXcZg/og+b9+tH/KxylGwH0= golang.org/x/tools v0.33.0/go.mod h1:CIJMaWEY88juyUfo7UbgPqbC8rU2OqfAV1h2Qp0oMYI= +golang.org/x/tools v0.34.0/go.mod h1:pAP9OwEaY1CAW3HOmg3hLZC5Z0CCmzjAF2UQMSqNARg= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -2020,8 +2030,8 @@ google.golang.org/api v0.122.0/go.mod h1:gcitW0lvnyWjSp9nKxAbdHKIZ6vF4aajGueeslZ google.golang.org/api v0.124.0/go.mod h1:xu2HQurE5gi/3t1aFCvhPD781p0a3p11sdunTJ2BlP4= google.golang.org/api v0.125.0/go.mod h1:mBwVAtz+87bEN6CbA1GtZPDOqY2R5ONPqJeIlvyo4Aw= google.golang.org/api v0.126.0/go.mod h1:mBwVAtz+87bEN6CbA1GtZPDOqY2R5ONPqJeIlvyo4Aw= -google.golang.org/api v0.240.0 h1:PxG3AA2UIqT1ofIzWV2COM3j3JagKTKSwy7L6RHNXNU= -google.golang.org/api v0.240.0/go.mod h1:cOVEm2TpdAGHL2z+UwyS+kmlGr3bVWQQ6sYEqkKje50= +google.golang.org/api v0.245.0 h1:YliGvz1rjXB+sTLNIST6Ffeji9WlRdLQ+LPl9ruSa5Y= +google.golang.org/api v0.245.0/go.mod h1:dMVhVcylamkirHdzEBAIQWUCgqY885ivNeZYd7VAVr8= google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -2170,8 +2180,8 @@ google.golang.org/genproto v0.0.0-20230629202037-9506855d4529/go.mod h1:xZnkP7mR google.golang.org/genproto v0.0.0-20230706204954-ccb25ca9f130/go.mod h1:O9kGHb51iE/nOGvQaDUuadVYqovW56s5emA88lQnj6Y= google.golang.org/genproto v0.0.0-20230726155614-23370e0ffb3e/go.mod h1:0ggbjUrZYpy1q+ANUS30SEoGZ53cdfwtbuG7Ptgy108= google.golang.org/genproto v0.0.0-20230803162519-f966b187b2e5/go.mod h1:oH/ZOT02u4kWEp7oYBGYFFkCdKS/uYR9Z7+0/xuuFp8= -google.golang.org/genproto v0.0.0-20250707201910-8d1bb00bc6a7 h1:FGOcxvKlJgRBVbXeugjljCfCgfKWhC42FBoYmTCWVBs= -google.golang.org/genproto v0.0.0-20250707201910-8d1bb00bc6a7/go.mod h1:249YoW4b1INqFTEop2T4aJgiO7UBYJrpejsaLvjWfI8= +google.golang.org/genproto v0.0.0-20250804133106-a7a43d27e69b h1:eZTgydvqZO44zyTZAvMaSyAxccZZdraiSAGvqOczVvk= +google.golang.org/genproto v0.0.0-20250804133106-a7a43d27e69b/go.mod h1:suyz2QBHQKlGIF92HEEsCfO1SwxXdk7PFLz+Zd9Uah4= google.golang.org/genproto/googleapis/api v0.0.0-20230525234020-1aefcd67740a/go.mod h1:ts19tUU+Z0ZShN1y3aPyq2+O3d5FUNNgT6FtOzmrNn8= google.golang.org/genproto/googleapis/api v0.0.0-20230525234035-dd9d682886f9/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig= google.golang.org/genproto/googleapis/api v0.0.0-20230526203410-71b5a4ffd15e/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig= @@ -2182,8 +2192,8 @@ google.golang.org/genproto/googleapis/api v0.0.0-20230726155614-23370e0ffb3e/go. google.golang.org/genproto/googleapis/api v0.0.0-20230822172742-b8732ec3820d/go.mod h1:KjSP20unUpOx5kyQUFa7k4OJg0qeJ7DEZflGDu2p6Bk= google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142/go.mod h1:d6be+8HhtEtucleCbxpPW9PA9XwISACu8nvpPqF0BVo= google.golang.org/genproto/googleapis/api v0.0.0-20241202173237-19429a94021a/go.mod h1:jehYqy3+AhJU9ve55aNOaSml7wUXjF9x6z2LcCfpAhY= -google.golang.org/genproto/googleapis/api v0.0.0-20250707201910-8d1bb00bc6a7 h1:FiusG7LWj+4byqhbvmB+Q93B/mOxJLN2DTozDuZm4EU= -google.golang.org/genproto/googleapis/api v0.0.0-20250707201910-8d1bb00bc6a7/go.mod h1:kXqgZtrWaf6qS3jZOCnCH7WYfrvFjkC51bM8fz3RsCA= +google.golang.org/genproto/googleapis/api v0.0.0-20250804133106-a7a43d27e69b h1:ULiyYQ0FdsJhwwZUwbaXpZF5yUE3h+RA+gxvBu37ucc= +google.golang.org/genproto/googleapis/api v0.0.0-20250804133106-a7a43d27e69b/go.mod h1:oDOGiMSXHL4sDTJvFvIB9nRQCGdLP1o/iVaqQK8zB+M= google.golang.org/genproto/googleapis/bytestream v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:ylj+BE99M198VPbBh6A8d9n3w8fChvyLK3wwBOjXBFA= google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234015-3fc162c6f38a/go.mod h1:xURIpW9ES5+/GZhnV6beoEtxQrnkRGIfP5VQG2tCBLc= google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA= @@ -2200,9 +2210,9 @@ google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142/go. google.golang.org/genproto/googleapis/rpc v0.0.0-20240826202546-f6391c0de4c7/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= google.golang.org/genproto/googleapis/rpc v0.0.0-20241118233622-e639e219e697/go.mod h1:5uTbfoYQed2U9p3KIj2/Zzm02PYhndfdmML0qC3q3FU= google.golang.org/genproto/googleapis/rpc v0.0.0-20241202173237-19429a94021a/go.mod h1:5uTbfoYQed2U9p3KIj2/Zzm02PYhndfdmML0qC3q3FU= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250707201910-8d1bb00bc6a7 h1:pFyd6EwwL2TqFf8emdthzeX+gZE1ElRq3iM8pui4KBY= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250707201910-8d1bb00bc6a7/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250728155136-f173205681a0/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250804133106-a7a43d27e69b h1:zPKJod4w6F1+nRGDI9ubnXYhU9NSWoFAijkHkUXeTK8= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250804133106-a7a43d27e69b/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/grpc/examples v0.0.0-20230224211313-3775f633ce20/go.mod h1:Nr5H8+MlGWr5+xX/STzdoEqJrO+YteqFbMyCsrb6mH0= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= diff --git a/interop/xds/client/Dockerfile b/interop/xds/client/Dockerfile index 47c4bccdfeb4..f170ab3c2361 100644 --- a/interop/xds/client/Dockerfile +++ b/interop/xds/client/Dockerfile @@ -16,7 +16,7 @@ # following command from grpc-go directory: # docker build -t -f interop/xds/client/Dockerfile . -FROM golang:1.23-alpine as build +FROM golang:1.25-alpine as build # Make a grpc-go directory and copy the repo into it. WORKDIR /go/src/grpc-go diff --git a/interop/xds/go.mod b/interop/xds/go.mod index f30eb5b82060..239c00bc85be 100644 --- a/interop/xds/go.mod +++ b/interop/xds/go.mod @@ -1,14 +1,14 @@ module google.golang.org/grpc/interop/xds -go 1.23.0 +go 1.24.0 replace google.golang.org/grpc => ../.. require ( - github.com/prometheus/client_golang v1.22.0 + github.com/prometheus/client_golang v1.23.0 go.opentelemetry.io/otel/exporters/prometheus v0.59.1 go.opentelemetry.io/otel/sdk/metric v1.37.0 - google.golang.org/grpc v1.73.0 + google.golang.org/grpc v1.74.2 ) require ( @@ -20,7 +20,7 @@ require ( github.com/cncf/xds/go v0.0.0-20250501225837-2ac532fd4443 // indirect github.com/envoyproxy/go-control-plane/envoy v1.32.4 // indirect github.com/envoyproxy/protoc-gen-validate v1.2.1 // indirect - github.com/go-jose/go-jose/v4 v4.1.1 // indirect + github.com/go-jose/go-jose/v4 v4.1.2 // indirect github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/google/uuid v1.6.0 // indirect @@ -29,7 +29,7 @@ require ( github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 // indirect github.com/prometheus/client_model v0.6.2 // indirect github.com/prometheus/common v0.65.0 // indirect - github.com/prometheus/otlptranslator v0.0.0-20250717125610-8549f4ab4f8f // indirect + github.com/prometheus/otlptranslator v0.0.0-20250725141939-ab8d56d297e3 // indirect github.com/prometheus/procfs v0.17.0 // indirect github.com/spiffe/go-spiffe/v2 v2.5.0 // indirect github.com/zeebo/errs v1.4.0 // indirect @@ -39,13 +39,13 @@ require ( go.opentelemetry.io/otel/metric v1.37.0 // indirect go.opentelemetry.io/otel/sdk v1.37.0 // indirect go.opentelemetry.io/otel/trace v1.37.0 // indirect - golang.org/x/crypto v0.39.0 // indirect - golang.org/x/net v0.41.0 // indirect + golang.org/x/crypto v0.40.0 // indirect + golang.org/x/net v0.42.0 // indirect golang.org/x/oauth2 v0.30.0 // indirect - golang.org/x/sync v0.15.0 // indirect + golang.org/x/sync v0.16.0 // indirect golang.org/x/sys v0.34.0 // indirect - golang.org/x/text v0.26.0 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20250707201910-8d1bb00bc6a7 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20250707201910-8d1bb00bc6a7 // indirect + golang.org/x/text v0.27.0 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20250804133106-a7a43d27e69b // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20250804133106-a7a43d27e69b // indirect google.golang.org/protobuf v1.36.6 // indirect ) diff --git a/interop/xds/go.sum b/interop/xds/go.sum index be2cc2d87303..4cbe4aa00969 100644 --- a/interop/xds/go.sum +++ b/interop/xds/go.sum @@ -20,8 +20,8 @@ github.com/envoyproxy/go-control-plane/ratelimit v0.1.0 h1:/G9QYbddjL25KvtKTv3an github.com/envoyproxy/go-control-plane/ratelimit v0.1.0/go.mod h1:Wk+tMFAFbCXaJPzVVHnPgRKdUdwW/KdbRt94AzgRee4= github.com/envoyproxy/protoc-gen-validate v1.2.1 h1:DEo3O99U8j4hBFwbJfrz9VtgcDfUKS7KJ7spH3d86P8= github.com/envoyproxy/protoc-gen-validate v1.2.1/go.mod h1:d/C80l/jxXLdfEIhX1W2TmLfsJ31lvEjwamM4DxlWXU= -github.com/go-jose/go-jose/v4 v4.1.1 h1:JYhSgy4mXXzAdF3nUx3ygx347LRXJRrpgyU3adRmkAI= -github.com/go-jose/go-jose/v4 v4.1.1/go.mod h1:BdsZGqgdO3b6tTc6LSE56wcDbMMLuPsw5d4ZD5f94kA= +github.com/go-jose/go-jose/v4 v4.1.2 h1:TK/7NqRQZfgAh+Td8AlsrvtPoUyiHh0LqVvokh+1vHI= +github.com/go-jose/go-jose/v4 v4.1.2/go.mod h1:22cg9HWM1pOlnRiY+9cQYJ9XHmya1bYW8OeDM6Ku6Oo= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= @@ -45,14 +45,14 @@ github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 h1:GFCKgm github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10/go.mod h1:t/avpk3KcrXxUnYOhZhMXJlSEyie6gQbtLq5NM3loB8= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/prometheus/client_golang v1.22.0 h1:rb93p9lokFEsctTys46VnV1kLCDpVZ0a/Y92Vm0Zc6Q= -github.com/prometheus/client_golang v1.22.0/go.mod h1:R7ljNsLXhuQXYZYtw6GAE9AZg8Y7vEW5scdCXrWRXC0= +github.com/prometheus/client_golang v1.23.0 h1:ust4zpdl9r4trLY/gSjlm07PuiBq2ynaXXlptpfy8Uc= +github.com/prometheus/client_golang v1.23.0/go.mod h1:i/o0R9ByOnHX0McrTMTyhYvKE4haaf2mW08I+jGAjEE= github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk= github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE= github.com/prometheus/common v0.65.0 h1:QDwzd+G1twt//Kwj/Ww6E9FQq1iVMmODnILtW1t2VzE= github.com/prometheus/common v0.65.0/go.mod h1:0gZns+BLRQ3V6NdaerOhMbwwRbNh9hkGINtQAsP5GS8= -github.com/prometheus/otlptranslator v0.0.0-20250717125610-8549f4ab4f8f h1:QQB6SuvGZjK8kdc2YaLJpYhV8fxauOsjE6jgcL6YJ8Q= -github.com/prometheus/otlptranslator v0.0.0-20250717125610-8549f4ab4f8f/go.mod h1:P8AwMgdD7XEr6QRUJ2QWLpiAZTgTE2UYgjlu3svompI= +github.com/prometheus/otlptranslator v0.0.0-20250725141939-ab8d56d297e3 h1:b/yrfZp3Ee3SrHXqbRT2L2zLODkY27IjZVvtEcEPES0= +github.com/prometheus/otlptranslator v0.0.0-20250725141939-ab8d56d297e3/go.mod h1:P8AwMgdD7XEr6QRUJ2QWLpiAZTgTE2UYgjlu3svompI= github.com/prometheus/procfs v0.17.0 h1:FuLQ+05u4ZI+SS/w9+BWEM2TXiHKsUQ9TADiRH7DuK0= github.com/prometheus/procfs v0.17.0/go.mod h1:oPQLaDAMRbA+u8H5Pbfq+dl3VDAvHxMUOVhe0wYB2zw= github.com/spiffe/go-spiffe/v2 v2.5.0 h1:N2I01KCUkv1FAjZXJMwh95KK1ZIQLYbPfhaxw8WS0hE= @@ -77,24 +77,26 @@ go.opentelemetry.io/otel/sdk/metric v1.37.0 h1:90lI228XrB9jCMuSdA0673aubgRobVZFh go.opentelemetry.io/otel/sdk/metric v1.37.0/go.mod h1:cNen4ZWfiD37l5NhS+Keb5RXVWZWpRE+9WyVCpbo5ps= go.opentelemetry.io/otel/trace v1.37.0 h1:HLdcFNbRQBE2imdSEgm/kwqmQj1Or1l/7bW6mxVK7z4= go.opentelemetry.io/otel/trace v1.37.0/go.mod h1:TlgrlQ+PtQO5XFerSPUYG0JSgGyryXewPGyayAWSBS0= -golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM= -golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U= -golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw= -golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA= +go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= +golang.org/x/crypto v0.40.0 h1:r4x+VvoG5Fm+eJcxMaY8CQM7Lb0l1lsmjGBQ6s8BfKM= +golang.org/x/crypto v0.40.0/go.mod h1:Qr1vMER5WyS2dfPHAlsOj01wgLbsyWtFn/aY+5+ZdxY= +golang.org/x/net v0.42.0 h1:jzkYrhi3YQWD6MLBJcsklgQsoAcw89EcZbJw8Z614hs= +golang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8= golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI= golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU= -golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8= -golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw= +golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA= golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= -golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M= -golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA= +golang.org/x/text v0.27.0 h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4= +golang.org/x/text v0.27.0/go.mod h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU= gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk= gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E= -google.golang.org/genproto/googleapis/api v0.0.0-20250707201910-8d1bb00bc6a7 h1:FiusG7LWj+4byqhbvmB+Q93B/mOxJLN2DTozDuZm4EU= -google.golang.org/genproto/googleapis/api v0.0.0-20250707201910-8d1bb00bc6a7/go.mod h1:kXqgZtrWaf6qS3jZOCnCH7WYfrvFjkC51bM8fz3RsCA= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250707201910-8d1bb00bc6a7 h1:pFyd6EwwL2TqFf8emdthzeX+gZE1ElRq3iM8pui4KBY= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250707201910-8d1bb00bc6a7/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= +google.golang.org/genproto/googleapis/api v0.0.0-20250804133106-a7a43d27e69b h1:ULiyYQ0FdsJhwwZUwbaXpZF5yUE3h+RA+gxvBu37ucc= +google.golang.org/genproto/googleapis/api v0.0.0-20250804133106-a7a43d27e69b/go.mod h1:oDOGiMSXHL4sDTJvFvIB9nRQCGdLP1o/iVaqQK8zB+M= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250804133106-a7a43d27e69b h1:zPKJod4w6F1+nRGDI9ubnXYhU9NSWoFAijkHkUXeTK8= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250804133106-a7a43d27e69b/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= diff --git a/interop/xds/server/Dockerfile b/interop/xds/server/Dockerfile index a43bbe496b77..08fc49764c89 100644 --- a/interop/xds/server/Dockerfile +++ b/interop/xds/server/Dockerfile @@ -16,7 +16,7 @@ # following command from grpc-go directory: # docker build -t -f interop/xds/server/Dockerfile . -FROM golang:1.23-alpine as build +FROM golang:1.25-alpine as build # Make a grpc-go directory and copy the repo into it. WORKDIR /go/src/grpc-go diff --git a/scripts/vet.sh b/scripts/vet.sh index 38b6650d2174..28c96962b976 100755 --- a/scripts/vet.sh +++ b/scripts/vet.sh @@ -97,7 +97,7 @@ for MOD_FILE in $(find . -name 'go.mod'); do gofmt -s -d -l . 2>&1 | fail_on_output goimports -l . 2>&1 | not grep -vE "\.pb\.go" - go mod tidy -compat=1.23 + go mod tidy -compat=1.24 git status --porcelain 2>&1 | fail_on_output || \ (git status; git --no-pager diff; exit 1) diff --git a/security/advancedtls/examples/go.mod b/security/advancedtls/examples/go.mod index 6caa4aa06312..5566db7309c1 100644 --- a/security/advancedtls/examples/go.mod +++ b/security/advancedtls/examples/go.mod @@ -1,22 +1,22 @@ module google.golang.org/grpc/security/advancedtls/examples -go 1.23.0 +go 1.24.0 require ( - google.golang.org/grpc v1.73.0 - google.golang.org/grpc/examples v0.0.0-20250708024235-a21e37488e05 + google.golang.org/grpc v1.74.2 + google.golang.org/grpc/examples v0.0.0-20250806063742-8729c7d017f4 google.golang.org/grpc/security/advancedtls v1.0.0 ) require ( - github.com/go-jose/go-jose/v4 v4.1.1 // indirect + github.com/go-jose/go-jose/v4 v4.1.2 // indirect github.com/spiffe/go-spiffe/v2 v2.5.0 // indirect github.com/zeebo/errs v1.4.0 // indirect - golang.org/x/crypto v0.39.0 // indirect - golang.org/x/net v0.41.0 // indirect + golang.org/x/crypto v0.40.0 // indirect + golang.org/x/net v0.42.0 // indirect golang.org/x/sys v0.34.0 // indirect - golang.org/x/text v0.26.0 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20250707201910-8d1bb00bc6a7 // indirect + golang.org/x/text v0.27.0 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20250804133106-a7a43d27e69b // indirect google.golang.org/protobuf v1.36.6 // indirect ) diff --git a/security/advancedtls/examples/go.sum b/security/advancedtls/examples/go.sum index e769aadd3796..e4fa3e3ffb05 100644 --- a/security/advancedtls/examples/go.sum +++ b/security/advancedtls/examples/go.sum @@ -1,7 +1,7 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/go-jose/go-jose/v4 v4.1.1 h1:JYhSgy4mXXzAdF3nUx3ygx347LRXJRrpgyU3adRmkAI= -github.com/go-jose/go-jose/v4 v4.1.1/go.mod h1:BdsZGqgdO3b6tTc6LSE56wcDbMMLuPsw5d4ZD5f94kA= +github.com/go-jose/go-jose/v4 v4.1.2 h1:TK/7NqRQZfgAh+Td8AlsrvtPoUyiHh0LqVvokh+1vHI= +github.com/go-jose/go-jose/v4 v4.1.2/go.mod h1:22cg9HWM1pOlnRiY+9cQYJ9XHmya1bYW8OeDM6Ku6Oo= github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= @@ -32,18 +32,18 @@ go.opentelemetry.io/otel/sdk/metric v1.37.0 h1:90lI228XrB9jCMuSdA0673aubgRobVZFh go.opentelemetry.io/otel/sdk/metric v1.37.0/go.mod h1:cNen4ZWfiD37l5NhS+Keb5RXVWZWpRE+9WyVCpbo5ps= go.opentelemetry.io/otel/trace v1.37.0 h1:HLdcFNbRQBE2imdSEgm/kwqmQj1Or1l/7bW6mxVK7z4= go.opentelemetry.io/otel/trace v1.37.0/go.mod h1:TlgrlQ+PtQO5XFerSPUYG0JSgGyryXewPGyayAWSBS0= -golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM= -golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U= -golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw= -golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA= +golang.org/x/crypto v0.40.0 h1:r4x+VvoG5Fm+eJcxMaY8CQM7Lb0l1lsmjGBQ6s8BfKM= +golang.org/x/crypto v0.40.0/go.mod h1:Qr1vMER5WyS2dfPHAlsOj01wgLbsyWtFn/aY+5+ZdxY= +golang.org/x/net v0.42.0 h1:jzkYrhi3YQWD6MLBJcsklgQsoAcw89EcZbJw8Z614hs= +golang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8= golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA= golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= -golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M= -golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA= +golang.org/x/text v0.27.0 h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4= +golang.org/x/text v0.27.0/go.mod h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU= gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk= gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250707201910-8d1bb00bc6a7 h1:pFyd6EwwL2TqFf8emdthzeX+gZE1ElRq3iM8pui4KBY= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250707201910-8d1bb00bc6a7/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250804133106-a7a43d27e69b h1:zPKJod4w6F1+nRGDI9ubnXYhU9NSWoFAijkHkUXeTK8= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250804133106-a7a43d27e69b/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= diff --git a/security/advancedtls/go.mod b/security/advancedtls/go.mod index b09d96b454a9..cd2b48719e8a 100644 --- a/security/advancedtls/go.mod +++ b/security/advancedtls/go.mod @@ -1,22 +1,22 @@ module google.golang.org/grpc/security/advancedtls -go 1.23.0 +go 1.24.0 require ( github.com/google/go-cmp v0.7.0 - golang.org/x/crypto v0.39.0 - google.golang.org/grpc v1.73.0 + golang.org/x/crypto v0.40.0 + google.golang.org/grpc v1.74.2 google.golang.org/grpc/examples v0.0.0-20250403095317-51d6a43ec597 ) require ( - github.com/go-jose/go-jose/v4 v4.1.1 // indirect + github.com/go-jose/go-jose/v4 v4.1.2 // indirect github.com/spiffe/go-spiffe/v2 v2.5.0 // indirect github.com/zeebo/errs v1.4.0 // indirect - golang.org/x/net v0.41.0 // indirect + golang.org/x/net v0.42.0 // indirect golang.org/x/sys v0.34.0 // indirect - golang.org/x/text v0.26.0 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20250707201910-8d1bb00bc6a7 // indirect + golang.org/x/text v0.27.0 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20250804133106-a7a43d27e69b // indirect google.golang.org/protobuf v1.36.6 // indirect ) diff --git a/security/advancedtls/go.sum b/security/advancedtls/go.sum index e769aadd3796..e4fa3e3ffb05 100644 --- a/security/advancedtls/go.sum +++ b/security/advancedtls/go.sum @@ -1,7 +1,7 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/go-jose/go-jose/v4 v4.1.1 h1:JYhSgy4mXXzAdF3nUx3ygx347LRXJRrpgyU3adRmkAI= -github.com/go-jose/go-jose/v4 v4.1.1/go.mod h1:BdsZGqgdO3b6tTc6LSE56wcDbMMLuPsw5d4ZD5f94kA= +github.com/go-jose/go-jose/v4 v4.1.2 h1:TK/7NqRQZfgAh+Td8AlsrvtPoUyiHh0LqVvokh+1vHI= +github.com/go-jose/go-jose/v4 v4.1.2/go.mod h1:22cg9HWM1pOlnRiY+9cQYJ9XHmya1bYW8OeDM6Ku6Oo= github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= @@ -32,18 +32,18 @@ go.opentelemetry.io/otel/sdk/metric v1.37.0 h1:90lI228XrB9jCMuSdA0673aubgRobVZFh go.opentelemetry.io/otel/sdk/metric v1.37.0/go.mod h1:cNen4ZWfiD37l5NhS+Keb5RXVWZWpRE+9WyVCpbo5ps= go.opentelemetry.io/otel/trace v1.37.0 h1:HLdcFNbRQBE2imdSEgm/kwqmQj1Or1l/7bW6mxVK7z4= go.opentelemetry.io/otel/trace v1.37.0/go.mod h1:TlgrlQ+PtQO5XFerSPUYG0JSgGyryXewPGyayAWSBS0= -golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM= -golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U= -golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw= -golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA= +golang.org/x/crypto v0.40.0 h1:r4x+VvoG5Fm+eJcxMaY8CQM7Lb0l1lsmjGBQ6s8BfKM= +golang.org/x/crypto v0.40.0/go.mod h1:Qr1vMER5WyS2dfPHAlsOj01wgLbsyWtFn/aY+5+ZdxY= +golang.org/x/net v0.42.0 h1:jzkYrhi3YQWD6MLBJcsklgQsoAcw89EcZbJw8Z614hs= +golang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8= golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA= golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= -golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M= -golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA= +golang.org/x/text v0.27.0 h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4= +golang.org/x/text v0.27.0/go.mod h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU= gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk= gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250707201910-8d1bb00bc6a7 h1:pFyd6EwwL2TqFf8emdthzeX+gZE1ElRq3iM8pui4KBY= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250707201910-8d1bb00bc6a7/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250804133106-a7a43d27e69b h1:zPKJod4w6F1+nRGDI9ubnXYhU9NSWoFAijkHkUXeTK8= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250804133106-a7a43d27e69b/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= diff --git a/stats/opencensus/go.mod b/stats/opencensus/go.mod index 8b258ddc4c13..a158af587378 100644 --- a/stats/opencensus/go.mod +++ b/stats/opencensus/go.mod @@ -1,19 +1,19 @@ module google.golang.org/grpc/stats/opencensus -go 1.23.0 +go 1.24.0 require ( github.com/google/go-cmp v0.7.0 go.opencensus.io v0.24.0 - google.golang.org/grpc v1.73.0 + google.golang.org/grpc v1.74.2 ) require ( github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect - golang.org/x/net v0.41.0 // indirect - golang.org/x/sys v0.33.0 // indirect - golang.org/x/text v0.26.0 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20250707201910-8d1bb00bc6a7 // indirect + golang.org/x/net v0.42.0 // indirect + golang.org/x/sys v0.34.0 // indirect + golang.org/x/text v0.27.0 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20250804133106-a7a43d27e69b // indirect google.golang.org/protobuf v1.36.6 // indirect ) diff --git a/stats/opencensus/go.sum b/stats/opencensus/go.sum index 0bc75d143eef..36f64a323bb4 100644 --- a/stats/opencensus/go.sum +++ b/stats/opencensus/go.sum @@ -909,7 +909,7 @@ github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2 github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20231223183121-56fa3ac82ce7/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-jose/go-jose/v4 v4.0.4/go.mod h1:NKb5HO1EZccyMpiZNbdUw/14tiXNyUJh188dfnMCAfc= -github.com/go-jose/go-jose/v4 v4.1.1/go.mod h1:BdsZGqgdO3b6tTc6LSE56wcDbMMLuPsw5d4ZD5f94kA= +github.com/go-jose/go-jose/v4 v4.1.2/go.mod h1:22cg9HWM1pOlnRiY+9cQYJ9XHmya1bYW8OeDM6Ku6Oo= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o= @@ -1379,6 +1379,7 @@ golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ug golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc= golang.org/x/crypto v0.38.0/go.mod h1:MvrbAqul58NNYPKnOra203SB9vpuZW0e+RRZV+Ggqjw= golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U= +golang.org/x/crypto v0.40.0/go.mod h1:Qr1vMER5WyS2dfPHAlsOj01wgLbsyWtFn/aY+5+ZdxY= golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -1555,8 +1556,9 @@ golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k= golang.org/x/net v0.37.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8= golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds= -golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw= golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA= +golang.org/x/net v0.42.0 h1:jzkYrhi3YQWD6MLBJcsklgQsoAcw89EcZbJw8Z614hs= +golang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -1614,6 +1616,7 @@ golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sync v0.14.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -1723,8 +1726,9 @@ golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= -golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA= +golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE= golang.org/x/telemetry v0.0.0-20240521205824-bda55230c457/go.mod h1:pRgIJT+bRLFKnoM1ldnzKoxTIn14Yxz928LQRYYgIN0= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= @@ -1753,6 +1757,7 @@ golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM= golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek= golang.org/x/term v0.30.0/go.mod h1:NYYFdzHoI5wRh/h5tDMdMqCqPJZEuNqVR5xJLd/n67g= golang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ= +golang.org/x/term v0.33.0/go.mod h1:s18+ql9tYWp1IfpV9DmCtQDDSRBUjKaw9M1eAv5UeF0= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1781,8 +1786,9 @@ golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY= golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4= golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA= -golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M= golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA= +golang.org/x/text v0.27.0 h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4= +golang.org/x/text v0.27.0/go.mod h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -1866,6 +1872,7 @@ golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxb golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c= golang.org/x/tools v0.26.0/go.mod h1:TPVVj70c7JJ3WCazhD8OdXcZg/og+b9+tH/KxylGwH0= golang.org/x/tools v0.33.0/go.mod h1:CIJMaWEY88juyUfo7UbgPqbC8rU2OqfAV1h2Qp0oMYI= +golang.org/x/tools v0.34.0/go.mod h1:pAP9OwEaY1CAW3HOmg3hLZC5Z0CCmzjAF2UQMSqNARg= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -2109,7 +2116,7 @@ google.golang.org/genproto/googleapis/api v0.0.0-20230726155614-23370e0ffb3e/go. google.golang.org/genproto/googleapis/api v0.0.0-20230822172742-b8732ec3820d/go.mod h1:KjSP20unUpOx5kyQUFa7k4OJg0qeJ7DEZflGDu2p6Bk= google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142/go.mod h1:d6be+8HhtEtucleCbxpPW9PA9XwISACu8nvpPqF0BVo= google.golang.org/genproto/googleapis/api v0.0.0-20241202173237-19429a94021a/go.mod h1:jehYqy3+AhJU9ve55aNOaSml7wUXjF9x6z2LcCfpAhY= -google.golang.org/genproto/googleapis/api v0.0.0-20250707201910-8d1bb00bc6a7/go.mod h1:kXqgZtrWaf6qS3jZOCnCH7WYfrvFjkC51bM8fz3RsCA= +google.golang.org/genproto/googleapis/api v0.0.0-20250804133106-a7a43d27e69b/go.mod h1:oDOGiMSXHL4sDTJvFvIB9nRQCGdLP1o/iVaqQK8zB+M= google.golang.org/genproto/googleapis/bytestream v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:ylj+BE99M198VPbBh6A8d9n3w8fChvyLK3wwBOjXBFA= google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234015-3fc162c6f38a/go.mod h1:xURIpW9ES5+/GZhnV6beoEtxQrnkRGIfP5VQG2tCBLc= google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA= @@ -2126,9 +2133,9 @@ google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142/go. google.golang.org/genproto/googleapis/rpc v0.0.0-20240826202546-f6391c0de4c7/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= google.golang.org/genproto/googleapis/rpc v0.0.0-20241118233622-e639e219e697/go.mod h1:5uTbfoYQed2U9p3KIj2/Zzm02PYhndfdmML0qC3q3FU= google.golang.org/genproto/googleapis/rpc v0.0.0-20241202173237-19429a94021a/go.mod h1:5uTbfoYQed2U9p3KIj2/Zzm02PYhndfdmML0qC3q3FU= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250707201910-8d1bb00bc6a7 h1:pFyd6EwwL2TqFf8emdthzeX+gZE1ElRq3iM8pui4KBY= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250707201910-8d1bb00bc6a7/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250728155136-f173205681a0/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250804133106-a7a43d27e69b h1:zPKJod4w6F1+nRGDI9ubnXYhU9NSWoFAijkHkUXeTK8= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250804133106-a7a43d27e69b/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/grpc/examples v0.0.0-20230224211313-3775f633ce20/go.mod h1:Nr5H8+MlGWr5+xX/STzdoEqJrO+YteqFbMyCsrb6mH0= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= diff --git a/stream.go b/stream.go index d9bbd4c57cf6..0a0af8961f05 100644 --- a/stream.go +++ b/stream.go @@ -549,6 +549,8 @@ type clientStream struct { sentLast bool // sent an end stream + receivedFirstMsg bool // set after the first message is received + methodConfig *MethodConfig ctx context.Context // the application's context, wrapped by stats/tracing @@ -1144,11 +1146,16 @@ func (a *csAttempt) recvMsg(m any, payInfo *payloadInfo) (err error) { if statusErr := a.transportStream.Status().Err(); statusErr != nil { return statusErr } + // Received no msg and status OK for non-server streaming rpcs. + if !cs.desc.ServerStreams && !cs.receivedFirstMsg { + return status.Error(codes.Internal, "cardinality violation: received no response message from non-server-streaming RPC") + } return io.EOF // indicates successful end of stream. } return toRPCErr(err) } + cs.receivedFirstMsg = true if a.trInfo != nil { a.mu.Lock() if a.trInfo.tr != nil { @@ -1177,7 +1184,7 @@ func (a *csAttempt) recvMsg(m any, payInfo *payloadInfo) (err error) { } else if err != nil { return toRPCErr(err) } - return status.Errorf(codes.Internal, "cardinality violation: expected for non server-streaming RPCs, but received another message") + return status.Error(codes.Internal, "cardinality violation: expected for non server-streaming RPCs, but received another message") } func (a *csAttempt) finish(err error) { @@ -1359,6 +1366,7 @@ type addrConnStream struct { transport transport.ClientTransport ctx context.Context sentLast bool + receivedFirstMsg bool desc *StreamDesc codec baseCodec sendCompressorV0 Compressor @@ -1484,10 +1492,15 @@ func (as *addrConnStream) RecvMsg(m any) (err error) { if statusErr := as.transportStream.Status().Err(); statusErr != nil { return statusErr } + // Received no msg and status OK for non-server streaming rpcs. + if !as.desc.ServerStreams && !as.receivedFirstMsg { + return status.Error(codes.Internal, "cardinality violation: received no response message from non-server-streaming RPC") + } return io.EOF // indicates successful end of stream. } return toRPCErr(err) } + as.receivedFirstMsg = true if as.desc.ServerStreams { // Subsequent messages should be received by subsequent RecvMsg calls. @@ -1501,7 +1514,7 @@ func (as *addrConnStream) RecvMsg(m any) (err error) { } else if err != nil { return toRPCErr(err) } - return status.Errorf(codes.Internal, "cardinality violation: expected for non server-streaming RPCs, but received another message") + return status.Error(codes.Internal, "cardinality violation: expected for non server-streaming RPCs, but received another message") } func (as *addrConnStream) finish(err error) { diff --git a/test/end2end_test.go b/test/end2end_test.go index b2f503990bc1..9157c525c094 100644 --- a/test/end2end_test.go +++ b/test/end2end_test.go @@ -3590,9 +3590,6 @@ func testClientStreamingError(t *testing.T, e env) { // Tests that a client receives a cardinality violation error for client-streaming // RPCs if the server doesn't send a message before returning status OK. func (s) TestClientStreamingCardinalityViolation_ServerHandlerMissingSendAndClose(t *testing.T) { - // TODO : https://github.com/grpc/grpc-go/issues/8119 - remove `t.Skip()` - // after this is fixed. - t.Skip() ss := &stubserver.StubServer{ StreamingInputCallF: func(_ testgrpc.TestService_StreamingInputCallServer) error { // Returning status OK without sending a response message.This is a @@ -3741,6 +3738,165 @@ func (s) TestClientStreaming_ReturnErrorAfterSendAndClose(t *testing.T) { } } +// Tests that client receives a cardinality violation error for unary +// RPCs if the server doesn't send a message before returning status OK. +func (s) TestUnaryRPC_ServerSendsOnlyTrailersWithOK(t *testing.T) { + lis, err := testutils.LocalTCPListener() + if err != nil { + t.Fatal(err) + } + defer lis.Close() + + ss := grpc.UnknownServiceHandler(func(any, grpc.ServerStream) error { + return nil + }) + + s := grpc.NewServer(ss) + go s.Serve(lis) + defer s.Stop() + + ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) + defer cancel() + cc, err := grpc.NewClient(lis.Addr().String(), grpc.WithTransportCredentials(insecure.NewCredentials())) + if err != nil { + t.Fatalf("grpc.NewClient(%q) failed unexpectedly: %v", lis.Addr(), err) + } + defer cc.Close() + + client := testgrpc.NewTestServiceClient(cc) + if _, err = client.EmptyCall(ctx, &testpb.Empty{}); status.Code(err) != codes.Internal { + t.Errorf("stream.RecvMsg() = %v, want error %v", status.Code(err), codes.Internal) + } +} + +// Tests the behavior for unary RPC when client calls RecvMsg() twice. +// Second call to RecvMsg should fail with io.EOF. +func (s) TestUnaryRPC_ClientCallRecvMsgTwice(t *testing.T) { + e := tcpTLSEnv + te := newTest(t, e) + defer te.tearDown() + + te.startServer(&testServer{security: e.security}) + + cc := te.clientConn() + ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) + defer cancel() + + desc := &grpc.StreamDesc{ + StreamName: "UnaryCall", + ServerStreams: false, + ClientStreams: false, + } + stream, err := cc.NewStream(ctx, desc, "/grpc.testing.TestService/UnaryCall") + if err != nil { + t.Fatalf("cc.NewStream() failed unexpectedly: %v", err) + } + + if err := stream.SendMsg(&testpb.SimpleRequest{}); err != nil { + t.Fatalf("stream.SendMsg(_) = %v, want ", err) + } + + resp := &testpb.SimpleResponse{} + if err := stream.RecvMsg(resp); err != nil { + t.Fatalf("stream.RecvMsg() = %v , want ", err) + } + + if err = stream.RecvMsg(resp); err != io.EOF { + t.Errorf("stream.RecvMsg() = %v, want error %v", err, io.EOF) + } +} + +// Tests the behavior for unary RPC when server calls SendMsg() twice. +// Client should fail with cardinality violation error. +func (s) TestUnaryRPC_ServerCallSendMsgTwice(t *testing.T) { + lis, err := testutils.LocalTCPListener() + if err != nil { + t.Fatal(err) + } + defer lis.Close() + + s := grpc.NewServer() + serviceDesc := grpc.ServiceDesc{ + ServiceName: "grpc.testing.TestService", + HandlerType: (*any)(nil), + Methods: []grpc.MethodDesc{}, + Streams: []grpc.StreamDesc{ + { + StreamName: "UnaryCall", + Handler: func(_ any, stream grpc.ServerStream) error { + if err := stream.RecvMsg(&testpb.Empty{}); err != nil { + t.Errorf("stream.RecvMsg() = %v, want ", err) + } + + if err = stream.SendMsg(&testpb.Empty{}); err != nil { + t.Errorf("stream.SendMsg() = %v, want ", err) + } + + if err = stream.SendMsg(&testpb.Empty{}); err != nil { + t.Errorf("stream.SendMsg() = %v, want ", err) + } + return nil + }, + ClientStreams: false, + ServerStreams: false, + }, + }, + } + s.RegisterService(&serviceDesc, &testServer{}) + go s.Serve(lis) + defer s.Stop() + + ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) + defer cancel() + cc, err := grpc.NewClient(lis.Addr().String(), grpc.WithTransportCredentials(insecure.NewCredentials())) + if err != nil { + t.Fatalf("grpc.NewClient(%q) failed unexpectedly: %v", lis.Addr(), err) + } + defer cc.Close() + + client := testgrpc.NewTestServiceClient(cc) + if _, err = client.UnaryCall(ctx, &testpb.SimpleRequest{}); status.Code(err) != codes.Internal { + t.Errorf("stream.RecvMsg() = %v, want error %v", status.Code(err), codes.Internal) + } +} + +// Tests the behavior for client-streaming RPC when client calls RecvMsg() twice. +// Second call to RecvMsg should fail with io.EOF. +func (s) TestClientStreaming_ClientCallRecvMsgTwice(t *testing.T) { + ss := stubserver.StubServer{ + StreamingInputCallF: func(stream testgrpc.TestService_StreamingInputCallServer) error { + if err := stream.SendAndClose(&testpb.StreamingInputCallResponse{}); err != nil { + t.Errorf("stream.SendAndClose(_) = %v, want ", err) + } + return nil + }, + } + if err := ss.Start(nil); err != nil { + t.Fatal("Error starting server:", err) + } + defer ss.Stop() + + ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) + defer cancel() + stream, err := ss.Client.StreamingInputCall(ctx) + if err != nil { + t.Fatalf(".StreamingInputCall(_) = _, %v, want ", err) + } + if err := stream.Send(&testpb.StreamingInputCallRequest{}); err != nil { + t.Fatalf("stream.Send(_) = %v, want ", err) + } + if err := stream.CloseSend(); err != nil { + t.Fatalf("stream.CloseSend() = %v, want ", err) + } + resp := new(testpb.StreamingInputCallResponse) + if err := stream.RecvMsg(resp); err != nil { + t.Fatalf("stream.RecvMsg() = %v , want ", err) + } + if err = stream.RecvMsg(resp); err != io.EOF { + t.Errorf("stream.RecvMsg() = %v, want error %v", err, io.EOF) + } +} + // Tests the behavior for server-side streaming when client calls SendMsg twice. // Second call to SendMsg should fail with Internal error and result in closing // the connection with a RST_STREAM. @@ -3802,7 +3958,6 @@ func (s) TestServerStreaming_ClientCallSendMsgTwice(t *testing.T) { <-handlerDone } -// TODO(i/7286) : Add tests to check server-side behavior for Unary RPC. // Tests the behavior for unary RPC when client calls SendMsg twice. Second call // to SendMsg should fail with Internal error. func (s) TestUnaryRPC_ClientCallSendMsgTwice(t *testing.T) { @@ -3981,7 +4136,7 @@ func (s) TestServerStreaming_ClientSendsZeroRequests(t *testing.T) { } // Tests that a client receives a cardinality violation error for client-streaming -// RPCs if the server call SendMsg multiple times. +// RPCs if the server calls SendMsg() multiple times. func (s) TestClientStreaming_ServerHandlerSendMsgAfterSendMsg(t *testing.T) { ss := stubserver.StubServer{ StreamingInputCallF: func(stream testgrpc.TestService_StreamingInputCallServer) error { diff --git a/test/kokoro/xds.sh b/test/kokoro/xds.sh index daac0d68e068..886146c0f27a 100755 --- a/test/kokoro/xds.sh +++ b/test/kokoro/xds.sh @@ -9,7 +9,7 @@ export GOPATH="${HOME}/gopath" pushd grpc-go/interop/xds/client # Install a version of Go supported by gRPC for the new features, e.g. # errors.Is() -gofilename=go1.23.0.linux-amd64.tar.gz +gofilename=go1.25.0.linux-amd64.tar.gz curl --retry 3 -O -L "https://go.dev/dl/${gofilename}" sudo tar -C /usr/local -xf "${gofilename}" sudo ln -s /usr/local/go/bin/go /usr/bin/go diff --git a/test/tools/go.mod b/test/tools/go.mod index 4c8f58edac60..8efb0fa275eb 100644 --- a/test/tools/go.mod +++ b/test/tools/go.mod @@ -1,11 +1,11 @@ module google.golang.org/grpc/test/tools -go 1.23.0 +go 1.24.0 require ( github.com/client9/misspell v0.3.4 - github.com/mgechev/revive v1.10.0 - golang.org/x/tools v0.34.0 + github.com/mgechev/revive v1.11.0 + golang.org/x/tools v0.35.0 google.golang.org/protobuf v1.36.6 honnef.co/go/tools v0.6.1 ) @@ -21,9 +21,10 @@ require ( github.com/mattn/go-isatty v0.0.20 // indirect github.com/mgechev/dots v1.0.0 // indirect github.com/spf13/afero v1.14.0 // indirect - golang.org/x/exp/typeparams v0.0.0-20250620022241-b7579e27df2b // indirect - golang.org/x/mod v0.25.0 // indirect - golang.org/x/sync v0.15.0 // indirect - golang.org/x/sys v0.33.0 // indirect - golang.org/x/text v0.26.0 // indirect + golang.org/x/exp/typeparams v0.0.0-20250718183923-645b1fa84792 // indirect + golang.org/x/mod v0.26.0 // indirect + golang.org/x/sync v0.16.0 // indirect + golang.org/x/sys v0.34.0 // indirect + golang.org/x/text v0.27.0 // indirect + golang.org/x/tools/go/expect v0.1.1-deprecated // indirect ) diff --git a/test/tools/go.sum b/test/tools/go.sum index 8e567a377303..b2de7841cfe3 100644 --- a/test/tools/go.sum +++ b/test/tools/go.sum @@ -20,27 +20,29 @@ github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWE github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mgechev/dots v1.0.0 h1:o+4OJ3OjWzgQHGJXKfJ8rbH4dqDugu5BiEy84nxg0k4= github.com/mgechev/dots v1.0.0/go.mod h1:rykuMydC9t3wfkM+ccYH3U3ss03vZGg6h3hmOznXLH0= -github.com/mgechev/revive v1.10.0 h1:x2oJsd7yrDp0mC6IgZqSKBTjSUC9Zk5Ob2WfBwZic2I= -github.com/mgechev/revive v1.10.0/go.mod h1:1MRO9zUV7Yukhqh/nGRKSaw6xC5XDzPWPja5GMPWoSE= +github.com/mgechev/revive v1.11.0 h1:b/gLLpBE427o+Xmd8G58gSA+KtBwxWinH/A565Awh0w= +github.com/mgechev/revive v1.11.0/go.mod h1:tI0oLF/2uj+InHCBLrrqfTKfjtFTBCFFfG05auyzgdw= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/spf13/afero v1.14.0 h1:9tH6MapGnn/j0eb0yIXiLjERO8RB6xIVZRDCX7PtqWA= github.com/spf13/afero v1.14.0/go.mod h1:acJQ8t0ohCGuMN3O+Pv0V0hgMxNYDlvdk+VTfyZmbYo= github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -golang.org/x/exp/typeparams v0.0.0-20250620022241-b7579e27df2b h1:KdrhdYPDUvJTvrDK9gdjfFd6JTk8vA1WJoldYSi0kHo= -golang.org/x/exp/typeparams v0.0.0-20250620022241-b7579e27df2b/go.mod h1:LKZHyeOpPuZcMgxeHjJp4p5yvxrCX1xDvH10zYHhjjQ= -golang.org/x/mod v0.25.0 h1:n7a+ZbQKQA/Ysbyb0/6IbB1H/X41mKgbhfv7AfG/44w= -golang.org/x/mod v0.25.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww= -golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8= -golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/exp/typeparams v0.0.0-20250718183923-645b1fa84792 h1:54/e+WfmhvjR2Zuz8Q7dzLGxIBM+s5WZpvo1QfVDGB8= +golang.org/x/exp/typeparams v0.0.0-20250718183923-645b1fa84792/go.mod h1:LKZHyeOpPuZcMgxeHjJp4p5yvxrCX1xDvH10zYHhjjQ= +golang.org/x/mod v0.26.0 h1:EGMPT//Ezu+ylkCijjPc+f4Aih7sZvaAr+O3EHBxvZg= +golang.org/x/mod v0.26.0/go.mod h1:/j6NAhSk8iQ723BGAUyoAcn7SlD7s15Dp9Nd/SfeaFQ= +golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw= +golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= -golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= -golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M= -golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA= -golang.org/x/tools v0.34.0 h1:qIpSLOxeCYGg9TrcJokLBG4KFA6d795g0xkBkiESGlo= -golang.org/x/tools v0.34.0/go.mod h1:pAP9OwEaY1CAW3HOmg3hLZC5Z0CCmzjAF2UQMSqNARg= +golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA= +golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/text v0.27.0 h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4= +golang.org/x/text v0.27.0/go.mod h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU= +golang.org/x/tools v0.35.0 h1:mBffYraMEf7aa0sB+NuKnuCy8qI/9Bughn8dC2Gu5r0= +golang.org/x/tools v0.35.0/go.mod h1:NKdj5HkL/73byiZSJjqJgKn3ep7KjFkBOkR/Hps3VPw= +golang.org/x/tools/go/expect v0.1.1-deprecated h1:jpBZDwmgPhXsKZC6WhL20P4b/wmnpsEAGHaNy0n/rJM= +golang.org/x/tools/go/expect v0.1.1-deprecated/go.mod h1:eihoPOH+FgIqa3FpoTwguz/bVUSGBlGQU67vpBeOrBY= google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= diff --git a/test/transport_test.go b/test/transport_test.go index 10e9ab57de30..3f0a8260086e 100644 --- a/test/transport_test.go +++ b/test/transport_test.go @@ -229,3 +229,76 @@ func (s) TestRSTDuringMessageRead(t *testing.T) { t.Fatalf("client.EmptyCall() returned %v; want status with code %v", err, codes.Canceled) } } + +// Test verifies that a client-side cancellation correctly frees up resources on +// the server. The test setup is designed to simulate a scenario where a server +// is blocked from sending a large message due to a full client-side flow +// control window. The client-side cancellation of this blocked RPC then frees +// up the max concurrent streams quota on the server, allowing a new RPC to be +// created successfully. +func (s) TestCancelWhileServerWaitingForFlowControl(t *testing.T) { + serverDoneCh := make(chan struct{}, 2) + const flowControlWindowSize = 65535 + ss := &stubserver.StubServer{ + StreamingOutputCallF: func(_ *testpb.StreamingOutputCallRequest, stream testgrpc.TestService_StreamingOutputCallServer) error { + // Send a large message to exhaust the client's flow control window. + stream.Send(&testpb.StreamingOutputCallResponse{ + Payload: &testpb.Payload{ + Body: make([]byte, flowControlWindowSize+1), + }, + }) + serverDoneCh <- struct{}{} + return nil + }, + } + + // Create a server that allows only 1 stream at a time. + ss = stubserver.StartTestService(t, ss, grpc.MaxConcurrentStreams(1)) + defer ss.Stop() + // Use a static flow control window. + if err := ss.StartClient(grpc.WithStaticStreamWindowSize(flowControlWindowSize)); err != nil { + t.Fatalf("Error while start test service client: %v", err) + } + client := ss.Client + ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) + defer cancel() + + streamCtx, streamCancel := context.WithCancel(ctx) + defer streamCancel() + + if _, err := client.StreamingOutputCall(streamCtx, &testpb.StreamingOutputCallRequest{}); err != nil { + t.Fatalf("Failed to create server streaming RPC: %v", err) + } + + // Wait for the server handler to return. This should cause the trailers to + // be buffered on the server, waiting for flow control quota to first send + // the data frame. + select { + case <-ctx.Done(): + t.Fatal("Context timed out waiting for server handler to return.") + case <-serverDoneCh: + } + + // Attempt to create a stream. It should fail since the previous stream is + // still blocked. + shortCtx, shortCancel := context.WithTimeout(ctx, defaultTestShortTimeout) + defer shortCancel() + _, err := client.StreamingOutputCall(shortCtx, &testpb.StreamingOutputCallRequest{}) + if status.Code(err) != codes.DeadlineExceeded { + t.Fatalf("Server stream creation returned error with unexpected status code: %v, want code: %v", err, codes.DeadlineExceeded) + } + + // Cancel the RPC, this should free up concurrent stream quota on the + // server. + streamCancel() + + // Attempt to create another stream. + stream, err := client.StreamingOutputCall(ctx, &testpb.StreamingOutputCallRequest{}) + if err != nil { + t.Fatalf("Failed to create server streaming RPC: %v", err) + } + _, err = stream.Recv() + if err != nil { + t.Fatalf("Failed to read from the stream: %v", err) + } +} diff --git a/version.go b/version.go index ed3786623dfb..76f2e0d060ff 100644 --- a/version.go +++ b/version.go @@ -19,4 +19,4 @@ package grpc // Version is the current grpc version. -const Version = "1.75.0-dev" +const Version = "1.76.0" diff --git a/xds/csds/csds.go b/xds/csds/csds.go index 3d8398a72ff0..603819d6c773 100644 --- a/xds/csds/csds.go +++ b/xds/csds/csds.go @@ -31,8 +31,8 @@ import ( "google.golang.org/grpc/codes" "google.golang.org/grpc/grpclog" internalgrpclog "google.golang.org/grpc/internal/grpclog" + "google.golang.org/grpc/internal/xds/xdsclient" "google.golang.org/grpc/status" - "google.golang.org/grpc/xds/internal/xdsclient" v3statusgrpc "github.com/envoyproxy/go-control-plane/envoy/service/status/v3" v3statuspb "github.com/envoyproxy/go-control-plane/envoy/service/status/v3" diff --git a/xds/csds/csds_e2e_test.go b/xds/csds/csds_e2e_test.go index a9654b20b8c2..d09deeb2682d 100644 --- a/xds/csds/csds_e2e_test.go +++ b/xds/csds/csds_e2e_test.go @@ -36,9 +36,9 @@ import ( "google.golang.org/grpc/internal/testutils" "google.golang.org/grpc/internal/testutils/xds/e2e" "google.golang.org/grpc/internal/xds/bootstrap" + "google.golang.org/grpc/internal/xds/xdsclient" + "google.golang.org/grpc/internal/xds/xdsclient/xdsresource" "google.golang.org/grpc/xds/csds" - "google.golang.org/grpc/xds/internal/xdsclient" - "google.golang.org/grpc/xds/internal/xdsclient/xdsresource" "google.golang.org/protobuf/encoding/prototext" "google.golang.org/protobuf/testing/protocmp" "google.golang.org/protobuf/types/known/anypb" @@ -52,7 +52,7 @@ import ( v3statuspb "github.com/envoyproxy/go-control-plane/envoy/service/status/v3" v3statuspbgrpc "github.com/envoyproxy/go-control-plane/envoy/service/status/v3" - _ "google.golang.org/grpc/xds/internal/httpfilter/router" // Register the router filter + _ "google.golang.org/grpc/internal/xds/httpfilter/router" // Register the router filter ) const defaultTestTimeout = 5 * time.Second diff --git a/xds/googledirectpath/googlec2p.go b/xds/googledirectpath/googlec2p.go index f75c022d9555..9ef59f1a92a7 100644 --- a/xds/googledirectpath/googlec2p.go +++ b/xds/googledirectpath/googlec2p.go @@ -38,8 +38,8 @@ import ( "google.golang.org/grpc/internal/googlecloud" internalgrpclog "google.golang.org/grpc/internal/grpclog" "google.golang.org/grpc/internal/xds/bootstrap" + "google.golang.org/grpc/internal/xds/xdsclient" "google.golang.org/grpc/resolver" - "google.golang.org/grpc/xds/internal/xdsclient" _ "google.golang.org/grpc/xds" // To register xds resolvers and balancers. ) @@ -182,6 +182,13 @@ func newNodeConfig(zone string, ipv6Capable bool) map[string]any { "id": fmt.Sprintf("C2P-%d", randInt()), "locality": map[string]any{"zone": zone}, } + if envconfig.NewPickFirstEnabled { + // Enable dualstack endpoints in TD. + // TODO(https://github.com/grpc/grpc-go/issues/8561): remove IPv6 metadata server queries entirely after old pick first is removed. + ipv6Capable = true + } else { + logger.Infof("GRPC_EXPERIMENTAL_ENABLE_NEW_PICK_FIRST is disabled, setting ipv6Capable node metadata based on metadata server query") + } if ipv6Capable { node["metadata"] = map[string]any{ipv6CapableMetadataName: true} } diff --git a/xds/googledirectpath/googlec2p_test.go b/xds/googledirectpath/googlec2p_test.go index 51f3fa4a79ca..74ee65db4987 100644 --- a/xds/googledirectpath/googlec2p_test.go +++ b/xds/googledirectpath/googlec2p_test.go @@ -32,10 +32,10 @@ import ( "google.golang.org/grpc/internal/envconfig" "google.golang.org/grpc/internal/grpctest" "google.golang.org/grpc/internal/xds/bootstrap" + "google.golang.org/grpc/internal/xds/xdsclient" testgrpc "google.golang.org/grpc/interop/grpc_testing" testpb "google.golang.org/grpc/interop/grpc_testing" "google.golang.org/grpc/resolver" - "google.golang.org/grpc/xds/internal/xdsclient" ) const defaultTestTimeout = 5 * time.Second @@ -103,6 +103,29 @@ func useCleanUniverseDomain(t *testing.T) { }) } +// TODO(https://github.com/grpc/grpc-go/issues/8561): this content can be hardcoded directly +// in wanted bootstraps again after old pick first is removed. +func expectedNodeJSON(ipv6Capable bool) []byte { + if !envconfig.NewPickFirstEnabled && !ipv6Capable { + return []byte(`{ + "id": "C2P-666", + "locality": { + "zone": "test-zone" + } + }`) + } + // Otherwise, return the node metadata including the IPv6 capability flag. + return []byte(`{ + "id": "C2P-666", + "locality": { + "zone": "test-zone" + }, + "metadata": { + "TRAFFICDIRECTOR_DIRECTPATH_C2P_IPV6_CAPABLE": true + } + }`) +} + // Tests the scenario where the bootstrap env vars are set and we're running on // GCE. The test builds a google-c2p resolver and verifies that an xDS resolver // is built and that we don't fallback to DNS (because federation is enabled by @@ -218,10 +241,7 @@ func (s) TestBuildXDS(t *testing.T) { ] }`), }, - Node: []byte(`{ - "id": "C2P-666", - "locality": {"zone": "test-zone"} - }`), + Node: expectedNodeJSON(false), }), }, { @@ -244,13 +264,7 @@ func (s) TestBuildXDS(t *testing.T) { ] }`), }, - Node: []byte(`{ - "id": "C2P-666", - "locality": {"zone": "test-zone"}, - "metadata": { - "TRAFFICDIRECTOR_DIRECTPATH_C2P_IPV6_CAPABLE": true - } - }`), + Node: expectedNodeJSON(true), }), }, { @@ -274,13 +288,7 @@ func (s) TestBuildXDS(t *testing.T) { ] }`), }, - Node: []byte(`{ - "id": "C2P-666", - "locality": {"zone": "test-zone"}, - "metadata": { - "TRAFFICDIRECTOR_DIRECTPATH_C2P_IPV6_CAPABLE": true - } - }`), + Node: expectedNodeJSON(true), }), }, } { @@ -442,10 +450,7 @@ func (s) TestSetUniverseDomainNonDefault(t *testing.T) { ] }`), }, - Node: []byte(`{ - "id": "C2P-666", - "locality": {"zone": "test-zone"} - }`), + Node: expectedNodeJSON(false), }) if diff := cmp.Diff(wantBootstrapConfig, gotConfig); diff != "" { t.Fatalf("Unexpected diff in bootstrap config (-want +got):\n%s", diff) @@ -513,10 +518,7 @@ func (s) TestDefaultUniverseDomain(t *testing.T) { ] }`), }, - Node: []byte(`{ - "id": "C2P-666", - "locality": {"zone": "test-zone"} - }`), + Node: expectedNodeJSON(false), }) if diff := cmp.Diff(wantBootstrapConfig, gotConfig); diff != "" { t.Fatalf("Unexpected diff in bootstrap config (-want +got):\n%s", diff) diff --git a/xds/internal/internal.go b/xds/internal/internal.go deleted file mode 100644 index 9e0b7931b5f7..000000000000 --- a/xds/internal/internal.go +++ /dev/null @@ -1,84 +0,0 @@ -/* - * - * Copyright 2019 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -// Package internal contains functions/structs shared by xds -// balancers/resolvers. -package internal - -import ( - "fmt" - - "google.golang.org/grpc/resolver" - "google.golang.org/grpc/xds/internal/clients" -) - -// LocalityString generates a string representation of clients.Locality in the -// format specified in gRFC A76. -func LocalityString(l clients.Locality) string { - return fmt.Sprintf("{region=%q, zone=%q, sub_zone=%q}", l.Region, l.Zone, l.SubZone) -} - -// IsLocalityEqual allows the values to be compared by Attributes.Equal. -func IsLocalityEqual(l clients.Locality, o any) bool { - ol, ok := o.(clients.Locality) - if !ok { - return false - } - return l.Region == ol.Region && l.Zone == ol.Zone && l.SubZone == ol.SubZone -} - -// LocalityFromString converts a string representation of clients.locality as -// specified in gRFC A76, into a LocalityID struct. -func LocalityFromString(s string) (ret clients.Locality, _ error) { - _, err := fmt.Sscanf(s, "{region=%q, zone=%q, sub_zone=%q}", &ret.Region, &ret.Zone, &ret.SubZone) - if err != nil { - return clients.Locality{}, fmt.Errorf("%s is not a well formatted locality ID, error: %v", s, err) - } - return ret, nil -} - -type localityKeyType string - -const localityKey = localityKeyType("grpc.xds.internal.address.locality") - -// GetLocalityID returns the locality ID of addr. -func GetLocalityID(addr resolver.Address) clients.Locality { - path, _ := addr.BalancerAttributes.Value(localityKey).(clients.Locality) - return path -} - -// SetLocalityID sets locality ID in addr to l. -func SetLocalityID(addr resolver.Address, l clients.Locality) resolver.Address { - addr.BalancerAttributes = addr.BalancerAttributes.WithValue(localityKey, l) - return addr -} - -// SetLocalityIDInEndpoint sets locality ID in endpoint to l. -func SetLocalityIDInEndpoint(endpoint resolver.Endpoint, l clients.Locality) resolver.Endpoint { - endpoint.Attributes = endpoint.Attributes.WithValue(localityKey, l) - return endpoint -} - -// ResourceTypeMapForTesting maps TypeUrl to corresponding ResourceType. -var ResourceTypeMapForTesting map[string]any - -// UnknownCSMLabels are TelemetryLabels emitted from CDS if CSM Telemetry Label -// data is not present in the CDS Resource. -var UnknownCSMLabels = map[string]string{ - "csm.service_name": "unknown", - "csm.service_namespace_name": "unknown", -} diff --git a/xds/internal/xdsclient/xdsresource/unmarshal_eds_test.go b/xds/internal/xdsclient/xdsresource/unmarshal_eds_test.go deleted file mode 100644 index f38f696178e5..000000000000 --- a/xds/internal/xdsclient/xdsresource/unmarshal_eds_test.go +++ /dev/null @@ -1,701 +0,0 @@ -/* - * - * Copyright 2021 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package xdsresource - -import ( - "fmt" - "net" - "strconv" - "testing" - - v3corepb "github.com/envoyproxy/go-control-plane/envoy/config/core/v3" - v3endpointpb "github.com/envoyproxy/go-control-plane/envoy/config/endpoint/v3" - v3discoverypb "github.com/envoyproxy/go-control-plane/envoy/service/discovery/v3" - v3typepb "github.com/envoyproxy/go-control-plane/envoy/type/v3" - "github.com/google/go-cmp/cmp" - "github.com/google/go-cmp/cmp/cmpopts" - "google.golang.org/grpc/internal/envconfig" - "google.golang.org/grpc/internal/pretty" - "google.golang.org/grpc/internal/testutils" - "google.golang.org/grpc/xds/internal/clients" - "google.golang.org/grpc/xds/internal/xdsclient/xdsresource/version" - "google.golang.org/protobuf/proto" - "google.golang.org/protobuf/types/known/anypb" - "google.golang.org/protobuf/types/known/structpb" - "google.golang.org/protobuf/types/known/wrapperspb" -) - -func (s) TestEDSParseRespProto(t *testing.T) { - tests := []struct { - name string - m *v3endpointpb.ClusterLoadAssignment - want EndpointsUpdate - wantErr bool - }{ - { - name: "missing-priority", - m: func() *v3endpointpb.ClusterLoadAssignment { - clab0 := newClaBuilder("test", nil) - clab0.addLocality("locality-1", 1, 0, []endpointOpts{{addrWithPort: "addr1:314"}}, nil) - clab0.addLocality("locality-2", 1, 2, []endpointOpts{{addrWithPort: "addr2:159"}}, nil) - return clab0.Build() - }(), - want: EndpointsUpdate{}, - wantErr: true, - }, - { - name: "missing-locality-ID", - m: func() *v3endpointpb.ClusterLoadAssignment { - clab0 := newClaBuilder("test", nil) - clab0.addLocality("", 1, 0, []endpointOpts{{addrWithPort: "addr1:314"}}, nil) - return clab0.Build() - }(), - want: EndpointsUpdate{}, - wantErr: true, - }, - { - name: "zero-endpoint-weight", - m: func() *v3endpointpb.ClusterLoadAssignment { - clab0 := newClaBuilder("test", nil) - clab0.addLocality("locality-0", 1, 0, []endpointOpts{{addrWithPort: "addr1:314"}}, &addLocalityOptions{Weight: []uint32{0}}) - return clab0.Build() - }(), - want: EndpointsUpdate{}, - wantErr: true, - }, - { - name: "duplicate-locality-in-the-same-priority", - m: func() *v3endpointpb.ClusterLoadAssignment { - clab0 := newClaBuilder("test", nil) - clab0.addLocality("locality-0", 1, 0, []endpointOpts{{addrWithPort: "addr1:314"}}, nil) - clab0.addLocality("locality-0", 1, 0, []endpointOpts{{addrWithPort: "addr1:314"}}, nil) // Duplicate locality with the same priority. - return clab0.Build() - }(), - want: EndpointsUpdate{}, - wantErr: true, - }, - { - name: "missing locality weight", - m: func() *v3endpointpb.ClusterLoadAssignment { - clab0 := newClaBuilder("test", nil) - clab0.addLocality("locality-1", 0, 1, []endpointOpts{{addrWithPort: "addr1:314"}}, &addLocalityOptions{ - Health: []v3corepb.HealthStatus{v3corepb.HealthStatus_HEALTHY}, - }) - clab0.addLocality("locality-2", 0, 0, []endpointOpts{{addrWithPort: "addr2:159"}}, &addLocalityOptions{ - Health: []v3corepb.HealthStatus{v3corepb.HealthStatus_HEALTHY}, - }) - return clab0.Build() - }(), - want: EndpointsUpdate{}, - }, - { - name: "max sum of weights at the same priority exceeded", - m: func() *v3endpointpb.ClusterLoadAssignment { - clab0 := newClaBuilder("test", nil) - clab0.addLocality("locality-1", 1, 0, []endpointOpts{{addrWithPort: "addr1:314"}}, nil) - clab0.addLocality("locality-2", 4294967295, 1, []endpointOpts{{addrWithPort: "addr2:159"}}, nil) - clab0.addLocality("locality-3", 1, 1, []endpointOpts{{addrWithPort: "addr2:88"}}, nil) - return clab0.Build() - }(), - want: EndpointsUpdate{}, - wantErr: true, - }, - { - name: "duplicate endpoint address", - m: func() *v3endpointpb.ClusterLoadAssignment { - clab0 := newClaBuilder("test", nil) - clab0.addLocality("locality-1", 1, 1, []endpointOpts{{addrWithPort: "addr:997"}}, nil) - clab0.addLocality("locality-2", 1, 0, []endpointOpts{{addrWithPort: "addr:997"}}, nil) - return clab0.Build() - }(), - want: EndpointsUpdate{}, - wantErr: true, - }, - { - name: "good", - m: func() *v3endpointpb.ClusterLoadAssignment { - clab0 := newClaBuilder("test", nil) - clab0.addLocality("locality-1", 1, 1, []endpointOpts{{addrWithPort: "addr1:314"}}, &addLocalityOptions{ - Health: []v3corepb.HealthStatus{v3corepb.HealthStatus_UNHEALTHY}, - Weight: []uint32{271}, - }) - clab0.addLocality("locality-2", 1, 0, []endpointOpts{{addrWithPort: "addr2:159"}}, &addLocalityOptions{ - Health: []v3corepb.HealthStatus{v3corepb.HealthStatus_DRAINING}, - Weight: []uint32{828}, - }) - return clab0.Build() - }(), - want: EndpointsUpdate{ - Drops: nil, - Localities: []Locality{ - { - Endpoints: []Endpoint{{ - Addresses: []string{"addr1:314"}, - HealthStatus: EndpointHealthStatusUnhealthy, - Weight: 271, - }}, - ID: clients.Locality{SubZone: "locality-1"}, - Priority: 1, - Weight: 1, - }, - { - Endpoints: []Endpoint{{ - Addresses: []string{"addr2:159"}, - HealthStatus: EndpointHealthStatusDraining, - Weight: 828, - }}, - ID: clients.Locality{SubZone: "locality-2"}, - Priority: 0, - Weight: 1, - }, - }, - }, - wantErr: false, - }, - { - name: "good duplicate locality with different priority", - m: func() *v3endpointpb.ClusterLoadAssignment { - clab0 := newClaBuilder("test", nil) - clab0.addLocality("locality-1", 1, 1, []endpointOpts{{addrWithPort: "addr1:314"}}, &addLocalityOptions{ - Health: []v3corepb.HealthStatus{v3corepb.HealthStatus_UNHEALTHY}, - Weight: []uint32{271}, - }) - // Same locality name, but with different priority. - clab0.addLocality("locality-1", 1, 0, []endpointOpts{{addrWithPort: "addr2:159"}}, &addLocalityOptions{ - Health: []v3corepb.HealthStatus{v3corepb.HealthStatus_DRAINING}, - Weight: []uint32{828}, - }) - return clab0.Build() - }(), - want: EndpointsUpdate{ - Drops: nil, - Localities: []Locality{ - { - Endpoints: []Endpoint{{ - Addresses: []string{"addr1:314"}, - HealthStatus: EndpointHealthStatusUnhealthy, - Weight: 271, - }}, - ID: clients.Locality{SubZone: "locality-1"}, - Priority: 1, - Weight: 1, - }, - { - Endpoints: []Endpoint{{ - Addresses: []string{"addr2:159"}, - HealthStatus: EndpointHealthStatusDraining, - Weight: 828, - }}, - ID: clients.Locality{SubZone: "locality-1"}, - Priority: 0, - Weight: 1, - }, - }, - }, - wantErr: false, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - got, err := parseEDSRespProto(tt.m) - if (err != nil) != tt.wantErr { - t.Errorf("parseEDSRespProto() error = %v, wantErr %v", err, tt.wantErr) - return - } - if d := cmp.Diff(got, tt.want, cmpopts.EquateEmpty()); d != "" { - t.Errorf("parseEDSRespProto() got = %v, want %v, diff: %v", got, tt.want, d) - } - }) - } -} - -func (s) TestEDSParseRespProtoAdditionalAddrs(t *testing.T) { - origDualstackEndpointsEnabled := envconfig.XDSDualstackEndpointsEnabled - defer func() { - envconfig.XDSDualstackEndpointsEnabled = origDualstackEndpointsEnabled - }() - envconfig.XDSDualstackEndpointsEnabled = true - - tests := []struct { - name string - m *v3endpointpb.ClusterLoadAssignment - want EndpointsUpdate - wantErr bool - }{ - { - name: "duplicate primary address in self additional addresses", - m: func() *v3endpointpb.ClusterLoadAssignment { - clab0 := newClaBuilder("test", nil) - clab0.addLocality("locality-1", 1, 0, []endpointOpts{{addrWithPort: "addr:998", additionalAddrWithPorts: []string{"addr:998"}}}, nil) - return clab0.Build() - }(), - want: EndpointsUpdate{}, - wantErr: true, - }, - { - name: "duplicate primary address in other locality additional addresses", - m: func() *v3endpointpb.ClusterLoadAssignment { - clab0 := newClaBuilder("test", nil) - clab0.addLocality("locality-1", 1, 1, []endpointOpts{{addrWithPort: "addr:997"}}, nil) - clab0.addLocality("locality-2", 1, 0, []endpointOpts{{addrWithPort: "addr:998", additionalAddrWithPorts: []string{"addr:997"}}}, nil) - return clab0.Build() - }(), - want: EndpointsUpdate{}, - wantErr: true, - }, - { - name: "duplicate additional address in self additional addresses", - m: func() *v3endpointpb.ClusterLoadAssignment { - clab0 := newClaBuilder("test", nil) - clab0.addLocality("locality-1", 1, 0, []endpointOpts{{addrWithPort: "addr:998", additionalAddrWithPorts: []string{"addr:999", "addr:999"}}}, nil) - return clab0.Build() - }(), - want: EndpointsUpdate{}, - wantErr: true, - }, - { - name: "duplicate additional address in other locality additional addresses", - m: func() *v3endpointpb.ClusterLoadAssignment { - clab0 := newClaBuilder("test", nil) - clab0.addLocality("locality-1", 1, 1, []endpointOpts{{addrWithPort: "addr:997", additionalAddrWithPorts: []string{"addr:1000"}}}, nil) - clab0.addLocality("locality-2", 1, 0, []endpointOpts{{addrWithPort: "addr:998", additionalAddrWithPorts: []string{"addr:1000"}}}, nil) - return clab0.Build() - }(), - want: EndpointsUpdate{}, - wantErr: true, - }, - { - name: "multiple localities", - m: func() *v3endpointpb.ClusterLoadAssignment { - clab0 := newClaBuilder("test", nil) - clab0.addLocality("locality-1", 1, 1, []endpointOpts{{addrWithPort: "addr1:997", additionalAddrWithPorts: []string{"addr1:1000"}}}, &addLocalityOptions{ - Health: []v3corepb.HealthStatus{v3corepb.HealthStatus_UNHEALTHY}, - Weight: []uint32{271}, - }) - clab0.addLocality("locality-2", 1, 0, []endpointOpts{{addrWithPort: "addr2:998", additionalAddrWithPorts: []string{"addr2:1000"}}}, &addLocalityOptions{ - Health: []v3corepb.HealthStatus{v3corepb.HealthStatus_HEALTHY}, - Weight: []uint32{828}, - }) - return clab0.Build() - }(), - want: EndpointsUpdate{ - Drops: nil, - Localities: []Locality{ - { - Endpoints: []Endpoint{{ - Addresses: []string{"addr1:997", "addr1:1000"}, - HealthStatus: EndpointHealthStatusUnhealthy, - Weight: 271, - }}, - ID: clients.Locality{SubZone: "locality-1"}, - Priority: 1, - Weight: 1, - }, - { - Endpoints: []Endpoint{{ - Addresses: []string{"addr2:998", "addr2:1000"}, - HealthStatus: EndpointHealthStatusHealthy, - Weight: 828, - }}, - ID: clients.Locality{SubZone: "locality-2"}, - Priority: 0, - Weight: 1, - }, - }, - }, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - got, err := parseEDSRespProto(tt.m) - if (err != nil) != tt.wantErr { - t.Errorf("parseEDSRespProto() error = %v, wantErr %v", err, tt.wantErr) - return - } - if d := cmp.Diff(got, tt.want, cmpopts.EquateEmpty()); d != "" { - t.Errorf("parseEDSRespProto() got = %v, want %v, diff: %v", got, tt.want, d) - } - }) - } -} - -func (s) TestUnmarshalEndpointHashKey(t *testing.T) { - baseCLA := &v3endpointpb.ClusterLoadAssignment{ - Endpoints: []*v3endpointpb.LocalityLbEndpoints{ - { - Locality: &v3corepb.Locality{Region: "r"}, - LbEndpoints: []*v3endpointpb.LbEndpoint{ - { - HostIdentifier: &v3endpointpb.LbEndpoint_Endpoint{ - Endpoint: &v3endpointpb.Endpoint{ - Address: &v3corepb.Address{ - Address: &v3corepb.Address_SocketAddress{ - SocketAddress: &v3corepb.SocketAddress{ - Address: "test-address", - PortSpecifier: &v3corepb.SocketAddress_PortValue{ - PortValue: 8080, - }, - }, - }, - }, - }, - }, - }, - }, - LoadBalancingWeight: &wrapperspb.UInt32Value{Value: 1}, - }, - }, - } - - tests := []struct { - name string - metadata *v3corepb.Metadata - wantHashKey string - compatEnvVar bool - }{ - { - name: "no metadata", - metadata: nil, - wantHashKey: "", - }, - { - name: "empty metadata", - metadata: &v3corepb.Metadata{}, - wantHashKey: "", - }, - { - name: "filter metadata without envoy.lb", - metadata: &v3corepb.Metadata{ - FilterMetadata: map[string]*structpb.Struct{ - "test-filter": {}, - }, - }, - wantHashKey: "", - }, - { - name: "nil envoy.lb", - metadata: &v3corepb.Metadata{ - FilterMetadata: map[string]*structpb.Struct{ - "envoy.lb": nil, - }, - }, - wantHashKey: "", - }, - { - name: "envoy.lb without hash key", - metadata: &v3corepb.Metadata{ - FilterMetadata: map[string]*structpb.Struct{ - "envoy.lb": { - Fields: map[string]*structpb.Value{ - "hash_key": { - Kind: &structpb.Value_NumberValue{NumberValue: 123.0}, - }, - }, - }, - }, - }, - wantHashKey: "", - }, - { - name: "envoy.lb with hash key, compat mode off", - metadata: &v3corepb.Metadata{ - FilterMetadata: map[string]*structpb.Struct{ - "envoy.lb": { - Fields: map[string]*structpb.Value{ - "hash_key": { - Kind: &structpb.Value_StringValue{StringValue: "test-hash-key"}, - }, - }, - }, - }, - }, - wantHashKey: "test-hash-key", - }, - { - name: "envoy.lb with hash key, compat mode on", - metadata: &v3corepb.Metadata{ - FilterMetadata: map[string]*structpb.Struct{ - "envoy.lb": { - Fields: map[string]*structpb.Value{ - "hash_key": { - Kind: &structpb.Value_StringValue{StringValue: "test-hash-key"}, - }, - }, - }, - }, - }, - wantHashKey: "", - compatEnvVar: true, - }, - } - - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - testutils.SetEnvConfig(t, &envconfig.XDSEndpointHashKeyBackwardCompat, test.compatEnvVar) - - cla := proto.Clone(baseCLA).(*v3endpointpb.ClusterLoadAssignment) - cla.Endpoints[0].LbEndpoints[0].Metadata = test.metadata - marshalledCLA := testutils.MarshalAny(t, cla) - _, update, err := unmarshalEndpointsResource(marshalledCLA) - if err != nil { - t.Fatalf("unmarshalEndpointsResource() got error = %v, want success", err) - } - got := update.Localities[0].Endpoints[0].HashKey - if got != test.wantHashKey { - t.Errorf("unmarshalEndpointResource() endpoint hash key: got %s, want %s", got, test.wantHashKey) - } - }) - } -} - -func (s) TestUnmarshalEndpoints(t *testing.T) { - var v3EndpointsAny = testutils.MarshalAny(t, func() *v3endpointpb.ClusterLoadAssignment { - clab0 := newClaBuilder("test", nil) - clab0.addLocality("locality-1", 1, 1, []endpointOpts{{addrWithPort: "addr1:314"}}, &addLocalityOptions{ - Health: []v3corepb.HealthStatus{v3corepb.HealthStatus_UNHEALTHY}, - Weight: []uint32{271}, - }) - clab0.addLocality("locality-2", 1, 0, []endpointOpts{{addrWithPort: "addr2:159"}}, &addLocalityOptions{ - Health: []v3corepb.HealthStatus{v3corepb.HealthStatus_DRAINING}, - Weight: []uint32{828}, - }) - return clab0.Build() - }()) - - tests := []struct { - name string - resource *anypb.Any - wantName string - wantUpdate EndpointsUpdate - wantErr bool - }{ - { - name: "non-clusterLoadAssignment resource type", - resource: &anypb.Any{TypeUrl: version.V3HTTPConnManagerURL}, - wantErr: true, - }, - { - name: "badly marshaled clusterLoadAssignment resource", - resource: &anypb.Any{ - TypeUrl: version.V3EndpointsURL, - Value: []byte{1, 2, 3, 4}, - }, - wantErr: true, - }, - { - name: "bad endpoints resource", - resource: testutils.MarshalAny(t, func() *v3endpointpb.ClusterLoadAssignment { - clab0 := newClaBuilder("test", nil) - clab0.addLocality("locality-1", 1, 0, []endpointOpts{{addrWithPort: "addr1:314"}}, nil) - clab0.addLocality("locality-2", 1, 2, []endpointOpts{{addrWithPort: "addr2:159"}}, nil) - return clab0.Build() - }()), - wantName: "test", - wantErr: true, - }, - { - name: "v3 endpoints", - resource: v3EndpointsAny, - wantName: "test", - wantUpdate: EndpointsUpdate{ - Drops: nil, - Localities: []Locality{ - { - Endpoints: []Endpoint{{ - Addresses: []string{"addr1:314"}, - HealthStatus: EndpointHealthStatusUnhealthy, - Weight: 271, - }}, - ID: clients.Locality{SubZone: "locality-1"}, - Priority: 1, - Weight: 1, - }, - { - Endpoints: []Endpoint{{ - Addresses: []string{"addr2:159"}, - HealthStatus: EndpointHealthStatusDraining, - Weight: 828, - }}, - ID: clients.Locality{SubZone: "locality-2"}, - Priority: 0, - Weight: 1, - }, - }, - Raw: v3EndpointsAny, - }, - }, - { - name: "v3 endpoints wrapped", - resource: testutils.MarshalAny(t, &v3discoverypb.Resource{Resource: v3EndpointsAny}), - wantName: "test", - wantUpdate: EndpointsUpdate{ - Drops: nil, - Localities: []Locality{ - { - Endpoints: []Endpoint{{ - Addresses: []string{"addr1:314"}, - HealthStatus: EndpointHealthStatusUnhealthy, - Weight: 271, - }}, - ID: clients.Locality{SubZone: "locality-1"}, - Priority: 1, - Weight: 1, - }, - { - Endpoints: []Endpoint{{ - Addresses: []string{"addr2:159"}, - HealthStatus: EndpointHealthStatusDraining, - Weight: 828, - }}, - ID: clients.Locality{SubZone: "locality-2"}, - Priority: 0, - Weight: 1, - }, - }, - Raw: v3EndpointsAny, - }, - }, - } - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - name, update, err := unmarshalEndpointsResource(test.resource) - if (err != nil) != test.wantErr { - t.Fatalf("unmarshalEndpointsResource(%s), got err: %v, wantErr: %v", pretty.ToJSON(test.resource), err, test.wantErr) - } - if name != test.wantName { - t.Errorf("unmarshalEndpointsResource(%s), got name: %s, want: %s", pretty.ToJSON(test.resource), name, test.wantName) - } - if diff := cmp.Diff(update, test.wantUpdate, cmpOpts); diff != "" { - t.Errorf("unmarshalEndpointsResource(%s), got unexpected update, diff (-got +want): %v", pretty.ToJSON(test.resource), diff) - } - }) - } -} - -// claBuilder builds a ClusterLoadAssignment, aka EDS -// response. -type claBuilder struct { - v *v3endpointpb.ClusterLoadAssignment -} - -// newClaBuilder creates a claBuilder. -func newClaBuilder(clusterName string, dropPercents []uint32) *claBuilder { - var drops []*v3endpointpb.ClusterLoadAssignment_Policy_DropOverload - for i, d := range dropPercents { - drops = append(drops, &v3endpointpb.ClusterLoadAssignment_Policy_DropOverload{ - Category: fmt.Sprintf("test-drop-%d", i), - DropPercentage: &v3typepb.FractionalPercent{ - Numerator: d, - Denominator: v3typepb.FractionalPercent_HUNDRED, - }, - }) - } - - return &claBuilder{ - v: &v3endpointpb.ClusterLoadAssignment{ - ClusterName: clusterName, - Policy: &v3endpointpb.ClusterLoadAssignment_Policy{ - DropOverloads: drops, - }, - }, - } -} - -// addLocalityOptions contains options when adding locality to the builder. -type addLocalityOptions struct { - Health []v3corepb.HealthStatus - Weight []uint32 -} - -type endpointOpts struct { - addrWithPort string - additionalAddrWithPorts []string -} - -func addressFromStr(addrWithPort string) *v3corepb.Address { - host, portStr, err := net.SplitHostPort(addrWithPort) - if err != nil { - panic("failed to split " + addrWithPort) - } - port, err := strconv.Atoi(portStr) - if err != nil { - panic("failed to atoi " + portStr) - } - - return &v3corepb.Address{ - Address: &v3corepb.Address_SocketAddress{ - SocketAddress: &v3corepb.SocketAddress{ - Protocol: v3corepb.SocketAddress_TCP, - Address: host, - PortSpecifier: &v3corepb.SocketAddress_PortValue{PortValue: uint32(port)}, - }, - }, - } -} - -// addLocality adds a locality to the builder. -func (clab *claBuilder) addLocality(subzone string, weight uint32, priority uint32, endpoints []endpointOpts, opts *addLocalityOptions) { - var lbEndPoints []*v3endpointpb.LbEndpoint - for i, e := range endpoints { - var additionalAddrs []*v3endpointpb.Endpoint_AdditionalAddress - for _, a := range e.additionalAddrWithPorts { - additionalAddrs = append(additionalAddrs, &v3endpointpb.Endpoint_AdditionalAddress{ - Address: addressFromStr(a), - }) - } - lbe := &v3endpointpb.LbEndpoint{ - HostIdentifier: &v3endpointpb.LbEndpoint_Endpoint{ - Endpoint: &v3endpointpb.Endpoint{ - Address: addressFromStr(e.addrWithPort), - AdditionalAddresses: additionalAddrs, - }, - }, - } - if opts != nil { - if i < len(opts.Health) { - lbe.HealthStatus = opts.Health[i] - } - if i < len(opts.Weight) { - lbe.LoadBalancingWeight = &wrapperspb.UInt32Value{Value: opts.Weight[i]} - } - } - lbEndPoints = append(lbEndPoints, lbe) - } - - var localityID *v3corepb.Locality - if subzone != "" { - localityID = &v3corepb.Locality{ - Region: "", - Zone: "", - SubZone: subzone, - } - } - - clab.v.Endpoints = append(clab.v.Endpoints, &v3endpointpb.LocalityLbEndpoints{ - Locality: localityID, - LbEndpoints: lbEndPoints, - LoadBalancingWeight: &wrapperspb.UInt32Value{Value: weight}, - Priority: priority, - }) -} - -// Build builds ClusterLoadAssignment. -func (clab *claBuilder) Build() *v3endpointpb.ClusterLoadAssignment { - return clab.v -} diff --git a/xds/server.go b/xds/server.go index 5baf91def228..d49396cec1d0 100644 --- a/xds/server.go +++ b/xds/server.go @@ -35,11 +35,11 @@ import ( istats "google.golang.org/grpc/internal/stats" "google.golang.org/grpc/internal/transport" "google.golang.org/grpc/internal/xds/bootstrap" + "google.golang.org/grpc/internal/xds/server" + "google.golang.org/grpc/internal/xds/xdsclient" + "google.golang.org/grpc/internal/xds/xdsclient/xdsresource" "google.golang.org/grpc/metadata" "google.golang.org/grpc/status" - "google.golang.org/grpc/xds/internal/server" - "google.golang.org/grpc/xds/internal/xdsclient" - "google.golang.org/grpc/xds/internal/xdsclient/xdsresource" ) const serverPrefix = "[xds-server %p] " diff --git a/xds/server_ext_test.go b/xds/server_ext_test.go index 381b93ebd53a..7e97a901fb8f 100644 --- a/xds/server_ext_test.go +++ b/xds/server_ext_test.go @@ -40,10 +40,10 @@ import ( "google.golang.org/grpc/internal/testutils" "google.golang.org/grpc/internal/testutils/xds/e2e" "google.golang.org/grpc/internal/xds/bootstrap" + "google.golang.org/grpc/internal/xds/xdsclient" "google.golang.org/grpc/peer" "google.golang.org/grpc/status" "google.golang.org/grpc/xds" - "google.golang.org/grpc/xds/internal/xdsclient" v3listenerpb "github.com/envoyproxy/go-control-plane/envoy/config/listener/v3" v3routepb "github.com/envoyproxy/go-control-plane/envoy/config/route/v3" diff --git a/xds/server_options.go b/xds/server_options.go index 4e3e3e9e27af..c72d93ec3f61 100644 --- a/xds/server_options.go +++ b/xds/server_options.go @@ -24,7 +24,7 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/connectivity" "google.golang.org/grpc/internal/xds/bootstrap" - "google.golang.org/grpc/xds/internal/xdsclient" + "google.golang.org/grpc/internal/xds/xdsclient" ) type serverOptions struct { diff --git a/xds/server_resource_ext_test.go b/xds/server_resource_ext_test.go index b396eb9ffc6c..29e68fb2066d 100644 --- a/xds/server_resource_ext_test.go +++ b/xds/server_resource_ext_test.go @@ -36,9 +36,9 @@ import ( "google.golang.org/grpc/internal/testutils" "google.golang.org/grpc/internal/testutils/xds/e2e" "google.golang.org/grpc/internal/xds/bootstrap" + "google.golang.org/grpc/internal/xds/xdsclient" + "google.golang.org/grpc/internal/xds/xdsclient/xdsresource/version" "google.golang.org/grpc/xds" - "google.golang.org/grpc/xds/internal/xdsclient" - "google.golang.org/grpc/xds/internal/xdsclient/xdsresource/version" "google.golang.org/protobuf/types/known/wrapperspb" v3corepb "github.com/envoyproxy/go-control-plane/envoy/config/core/v3" diff --git a/xds/server_security_ext_test.go b/xds/server_security_ext_test.go index 5436c2addd55..fbc21e556e46 100644 --- a/xds/server_security_ext_test.go +++ b/xds/server_security_ext_test.go @@ -35,8 +35,8 @@ import ( "google.golang.org/grpc/internal/testutils" "google.golang.org/grpc/internal/testutils/xds/e2e" "google.golang.org/grpc/internal/xds/bootstrap" + "google.golang.org/grpc/internal/xds/xdsclient" "google.golang.org/grpc/xds" - "google.golang.org/grpc/xds/internal/xdsclient" "google.golang.org/protobuf/types/known/wrapperspb" v3corepb "github.com/envoyproxy/go-control-plane/envoy/config/core/v3" diff --git a/xds/server_serving_mode_ext_test.go b/xds/server_serving_mode_ext_test.go index ce4f65f1e2a8..678bf3808bfa 100644 --- a/xds/server_serving_mode_ext_test.go +++ b/xds/server_serving_mode_ext_test.go @@ -33,9 +33,9 @@ import ( "google.golang.org/grpc/internal/testutils/xds/e2e" "google.golang.org/grpc/internal/testutils/xds/e2e/setup" "google.golang.org/grpc/internal/xds/bootstrap" + "google.golang.org/grpc/internal/xds/xdsclient" "google.golang.org/grpc/status" "google.golang.org/grpc/xds" - "google.golang.org/grpc/xds/internal/xdsclient" v3listenerpb "github.com/envoyproxy/go-control-plane/envoy/config/listener/v3" v3routepb "github.com/envoyproxy/go-control-plane/envoy/config/route/v3" diff --git a/xds/server_test.go b/xds/server_test.go index 921b8864570a..df631410a6a1 100644 --- a/xds/server_test.go +++ b/xds/server_test.go @@ -42,13 +42,13 @@ import ( "google.golang.org/grpc/internal/testutils" "google.golang.org/grpc/internal/testutils/xds/e2e" "google.golang.org/grpc/internal/xds/bootstrap" - "google.golang.org/grpc/xds/internal/xdsclient" - "google.golang.org/grpc/xds/internal/xdsclient/xdsresource/version" + "google.golang.org/grpc/internal/xds/xdsclient" + "google.golang.org/grpc/internal/xds/xdsclient/xdsresource/version" v3listenerpb "github.com/envoyproxy/go-control-plane/envoy/config/listener/v3" v3discoverypb "github.com/envoyproxy/go-control-plane/envoy/service/discovery/v3" - _ "google.golang.org/grpc/xds/internal/httpfilter/router" // Register the router filter + _ "google.golang.org/grpc/internal/xds/httpfilter/router" // Register the router filter ) const ( diff --git a/xds/test/eds_resource_missing_test.go b/xds/test/eds_resource_missing_test.go index ce334b2cc758..247270540e73 100644 --- a/xds/test/eds_resource_missing_test.go +++ b/xds/test/eds_resource_missing_test.go @@ -34,9 +34,9 @@ import ( "google.golang.org/grpc/internal/testutils/xds/e2e" "google.golang.org/grpc/internal/testutils/xds/e2e/setup" "google.golang.org/grpc/internal/xds/bootstrap" + "google.golang.org/grpc/internal/xds/xdsclient" "google.golang.org/grpc/resolver" "google.golang.org/grpc/status" - "google.golang.org/grpc/xds/internal/xdsclient" v3clusterpb "github.com/envoyproxy/go-control-plane/envoy/config/cluster/v3" v3endpointpb "github.com/envoyproxy/go-control-plane/envoy/config/endpoint/v3" diff --git a/xds/xds.go b/xds/xds.go index 943d09f17e0f..c6a1f25f7aad 100644 --- a/xds/xds.go +++ b/xds/xds.go @@ -38,13 +38,13 @@ import ( "google.golang.org/grpc/xds/csds" _ "google.golang.org/grpc/credentials/tls/certprovider/pemfile" // Register the file watcher certificate provider plugin. - _ "google.golang.org/grpc/xds/internal/balancer" // Register the balancers. - _ "google.golang.org/grpc/xds/internal/clusterspecifier/rls" // Register the RLS cluster specifier plugin. Note that this does not register the RLS LB policy. - _ "google.golang.org/grpc/xds/internal/httpfilter/fault" // Register the fault injection filter. - _ "google.golang.org/grpc/xds/internal/httpfilter/rbac" // Register the RBAC filter. - _ "google.golang.org/grpc/xds/internal/httpfilter/router" // Register the router filter. - _ "google.golang.org/grpc/xds/internal/resolver" // Register the xds_resolver. - _ "google.golang.org/grpc/xds/internal/xdsclient/xdslbregistry/converter" // Register the xDS LB Registry Converters. + _ "google.golang.org/grpc/internal/xds/balancer" // Register the balancers. + _ "google.golang.org/grpc/internal/xds/clusterspecifier/rls" // Register the RLS cluster specifier plugin. Note that this does not register the RLS LB policy. + _ "google.golang.org/grpc/internal/xds/httpfilter/fault" // Register the fault injection filter. + _ "google.golang.org/grpc/internal/xds/httpfilter/rbac" // Register the RBAC filter. + _ "google.golang.org/grpc/internal/xds/httpfilter/router" // Register the router filter. + _ "google.golang.org/grpc/internal/xds/resolver" // Register the xds_resolver. + _ "google.golang.org/grpc/internal/xds/xdsclient/xdslbregistry/converter" // Register the xDS LB Registry Converters. v3statusgrpc "github.com/envoyproxy/go-control-plane/envoy/service/status/v3" )