-
Notifications
You must be signed in to change notification settings - Fork 4.4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
admin: implement admin services (#4274)
- Loading branch information
Showing
27 changed files
with
499 additions
and
130 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
/* | ||
* | ||
* 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 admin provides a convenient method for registering a collection of | ||
// administration services to a gRPC server. The services registered are: | ||
// | ||
// - Channelz: https://github.com/grpc/proposal/blob/master/A14-channelz.md | ||
// - CSDS: https://github.com/grpc/proposal/blob/master/A40-csds-support.md | ||
// | ||
// Experimental | ||
// | ||
// Notice: All APIs in this package are experimental and may be removed in a | ||
// later release. | ||
package admin | ||
|
||
import ( | ||
"google.golang.org/grpc" | ||
channelzservice "google.golang.org/grpc/channelz/service" | ||
internaladmin "google.golang.org/grpc/internal/admin" | ||
) | ||
|
||
func init() { | ||
// Add a list of default services to admin here. Optional services, like | ||
// CSDS, will be added by other packages. | ||
internaladmin.AddService(func(registrar grpc.ServiceRegistrar) (func(), error) { | ||
channelzservice.RegisterChannelzServiceToServer(registrar) | ||
return nil, nil | ||
}) | ||
} | ||
|
||
// Register registers the set of admin services to the given server. | ||
// | ||
// The returned cleanup function should be called to clean up the resources | ||
// allocated for the service handlers after the server is stopped. | ||
// | ||
// Note that if `s` is not a *grpc.Server or a *xds.GRPCServer, CSDS will not be | ||
// registered because CSDS generated code is old and doesn't support interface | ||
// `grpc.ServiceRegistrar`. | ||
// https://github.com/envoyproxy/go-control-plane/issues/403 | ||
func Register(s grpc.ServiceRegistrar) (cleanup func(), _ error) { | ||
return internaladmin.Register(s) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
/* | ||
* | ||
* 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 admin_test | ||
|
||
import ( | ||
"testing" | ||
|
||
"google.golang.org/grpc/admin/test" | ||
"google.golang.org/grpc/codes" | ||
) | ||
|
||
func TestRegisterNoCSDS(t *testing.T) { | ||
test.RunRegisterTests(t, test.ExpectedStatusCodes{ | ||
ChannelzCode: codes.OK, | ||
// CSDS is not registered because xDS isn't imported. | ||
CSDSCode: codes.Unimplemented, | ||
}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
/* | ||
* | ||
* 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. | ||
* | ||
*/ | ||
|
||
// This file has the same content as admin_test.go, difference is that this is | ||
// in another package, and it imports "xds", so we can test that csds is | ||
// registered when xds is imported. | ||
|
||
package test_test | ||
|
||
import ( | ||
"testing" | ||
|
||
"google.golang.org/grpc/admin/test" | ||
"google.golang.org/grpc/codes" | ||
_ "google.golang.org/grpc/xds" | ||
) | ||
|
||
func TestRegisterWithCSDS(t *testing.T) { | ||
test.RunRegisterTests(t, test.ExpectedStatusCodes{ | ||
ChannelzCode: codes.OK, | ||
CSDSCode: codes.OK, | ||
}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
/* | ||
* | ||
* 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 test contains test only functions for package admin. It's used by | ||
// admin/admin_test.go and admin/test/admin_test.go. | ||
package test | ||
|
||
import ( | ||
"context" | ||
"net" | ||
"testing" | ||
"time" | ||
|
||
v3statuspb "github.com/envoyproxy/go-control-plane/envoy/service/status/v3" | ||
"github.com/google/uuid" | ||
"google.golang.org/grpc" | ||
"google.golang.org/grpc/admin" | ||
channelzpb "google.golang.org/grpc/channelz/grpc_channelz_v1" | ||
"google.golang.org/grpc/codes" | ||
"google.golang.org/grpc/internal/xds" | ||
"google.golang.org/grpc/status" | ||
) | ||
|
||
const ( | ||
defaultTestTimeout = 10 * time.Second | ||
) | ||
|
||
// ExpectedStatusCodes contains the expected status code for each RPC (can be | ||
// OK). | ||
type ExpectedStatusCodes struct { | ||
ChannelzCode codes.Code | ||
CSDSCode codes.Code | ||
} | ||
|
||
// RunRegisterTests makes a client, runs the RPCs, and compares the status | ||
// codes. | ||
func RunRegisterTests(t *testing.T, ec ExpectedStatusCodes) { | ||
nodeID := uuid.New().String() | ||
bootstrapCleanup, err := xds.SetupBootstrapFile(xds.BootstrapOptions{ | ||
Version: xds.TransportV3, | ||
NodeID: nodeID, | ||
ServerURI: "no.need.for.a.server", | ||
}) | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
defer bootstrapCleanup() | ||
|
||
lis, err := net.Listen("tcp", "localhost:0") | ||
if err != nil { | ||
t.Fatalf("cannot create listener: %v", err) | ||
} | ||
|
||
server := grpc.NewServer() | ||
defer server.Stop() | ||
cleanup, err := admin.Register(server) | ||
if err != nil { | ||
t.Fatalf("failed to register admin: %v", err) | ||
} | ||
defer cleanup() | ||
go func() { | ||
server.Serve(lis) | ||
}() | ||
|
||
conn, err := grpc.Dial(lis.Addr().String(), grpc.WithInsecure()) | ||
if err != nil { | ||
t.Fatalf("cannot connect to server: %v", err) | ||
} | ||
|
||
t.Run("channelz", func(t *testing.T) { | ||
if err := RunChannelz(conn); status.Code(err) != ec.ChannelzCode { | ||
t.Fatalf("%s RPC failed with error %v, want code %v", "channelz", err, ec.ChannelzCode) | ||
} | ||
}) | ||
t.Run("csds", func(t *testing.T) { | ||
if err := RunCSDS(conn); status.Code(err) != ec.CSDSCode { | ||
t.Fatalf("%s RPC failed with error %v, want code %v", "CSDS", err, ec.CSDSCode) | ||
} | ||
}) | ||
} | ||
|
||
// RunChannelz makes a channelz RPC. | ||
func RunChannelz(conn *grpc.ClientConn) error { | ||
c := channelzpb.NewChannelzClient(conn) | ||
ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) | ||
defer cancel() | ||
_, err := c.GetTopChannels(ctx, &channelzpb.GetTopChannelsRequest{}, grpc.WaitForReady(true)) | ||
return err | ||
} | ||
|
||
// RunCSDS makes a CSDS RPC. | ||
func RunCSDS(conn *grpc.ClientConn) error { | ||
c := v3statuspb.NewClientStatusDiscoveryServiceClient(conn) | ||
ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) | ||
defer cancel() | ||
_, err := c.FetchClientStatus(ctx, &v3statuspb.ClientStatusRequest{}, grpc.WaitForReady(true)) | ||
return err | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
/* | ||
* | ||
* 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 admin contains internal implementation for admin service. | ||
package admin | ||
|
||
import "google.golang.org/grpc" | ||
|
||
// services is a map from name to service register functions. | ||
var services []func(grpc.ServiceRegistrar) (func(), error) | ||
|
||
// AddService adds a service to the list of admin services. | ||
// | ||
// NOTE: this function must only be called during initialization time (i.e. in | ||
// an init() function), and is not thread-safe. | ||
// | ||
// If multiple services with the same service name are added (e.g. two services | ||
// for `grpc.channelz.v1.Channelz`), the server will panic on `Register()`. | ||
func AddService(f func(grpc.ServiceRegistrar) (func(), error)) { | ||
services = append(services, f) | ||
} | ||
|
||
// Register registers the set of admin services to the given server. | ||
func Register(s grpc.ServiceRegistrar) (cleanup func(), _ error) { | ||
var cleanups []func() | ||
for _, f := range services { | ||
cleanup, err := f(s) | ||
if err != nil { | ||
callFuncs(cleanups) | ||
return nil, err | ||
} | ||
if cleanup != nil { | ||
cleanups = append(cleanups, cleanup) | ||
} | ||
} | ||
return func() { | ||
callFuncs(cleanups) | ||
}, nil | ||
} | ||
|
||
func callFuncs(fs []func()) { | ||
for _, f := range fs { | ||
f() | ||
} | ||
} |
Oops, something went wrong.