Skip to content

Commit 1bf781d

Browse files
committed
Cleanup introspection interface
Split service proxy from service plugin. Make introspection service easier for clients to use. Update service proxy to support grpc and ttrpc. Signed-off-by: Derek McGowan <[email protected]>
1 parent 9a2b855 commit 1bf781d

File tree

14 files changed

+195
-159
lines changed

14 files changed

+195
-159
lines changed

client/client.go

Lines changed: 7 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@ import (
3131
diffapi "github.com/containerd/containerd/v2/api/services/diff/v1"
3232
eventsapi "github.com/containerd/containerd/v2/api/services/events/v1"
3333
imagesapi "github.com/containerd/containerd/v2/api/services/images/v1"
34-
introspectionapi "github.com/containerd/containerd/v2/api/services/introspection/v1"
3534
leasesapi "github.com/containerd/containerd/v2/api/services/leases/v1"
3635
namespacesapi "github.com/containerd/containerd/v2/api/services/namespaces/v1"
3736
sandboxsapi "github.com/containerd/containerd/v2/api/services/sandbox/v1"
@@ -44,6 +43,8 @@ import (
4443
contentproxy "github.com/containerd/containerd/v2/core/content/proxy"
4544
"github.com/containerd/containerd/v2/core/events"
4645
"github.com/containerd/containerd/v2/core/images"
46+
"github.com/containerd/containerd/v2/core/introspection"
47+
introspectionproxy "github.com/containerd/containerd/v2/core/introspection/proxy"
4748
"github.com/containerd/containerd/v2/core/leases"
4849
leasesproxy "github.com/containerd/containerd/v2/core/leases/proxy"
4950
"github.com/containerd/containerd/v2/core/remotes"
@@ -56,7 +57,6 @@ import (
5657
"github.com/containerd/containerd/v2/pkg/dialer"
5758
"github.com/containerd/containerd/v2/pkg/namespaces"
5859
"github.com/containerd/containerd/v2/plugins"
59-
"github.com/containerd/containerd/v2/plugins/services/introspection"
6060
"github.com/containerd/containerd/v2/protobuf"
6161
ptypes "github.com/containerd/containerd/v2/protobuf/types"
6262
"github.com/containerd/errdefs"
@@ -681,7 +681,7 @@ func (c *Client) IntrospectionService() introspection.Service {
681681
}
682682
c.connMu.Lock()
683683
defer c.connMu.Unlock()
684-
return introspection.NewIntrospectionServiceFromClient(introspectionapi.NewIntrospectionClient(c.conn))
684+
return introspectionproxy.NewIntrospectionProxy(c.conn)
685685
}
686686

687687
// LeasesService returns the underlying Leases Client
@@ -785,7 +785,7 @@ func (c *Client) Server(ctx context.Context) (ServerInfo, error) {
785785
}
786786
c.connMu.Unlock()
787787

788-
response, err := c.IntrospectionService().Server(ctx, &ptypes.Empty{})
788+
response, err := c.IntrospectionService().Server(ctx)
789789
if err != nil {
790790
return ServerInfo{}, err
791791
}
@@ -831,7 +831,7 @@ func (c *Client) GetSnapshotterSupportedPlatforms(ctx context.Context, snapshott
831831
filters := []string{fmt.Sprintf("type==%s, id==%s", plugins.SnapshotPlugin, snapshotterName)}
832832
in := c.IntrospectionService()
833833

834-
resp, err := in.Plugins(ctx, filters)
834+
resp, err := in.Plugins(ctx, filters...)
835835
if err != nil {
836836
return nil, err
837837
}
@@ -862,7 +862,7 @@ func (c *Client) GetSnapshotterCapabilities(ctx context.Context, snapshotterName
862862
filters := []string{fmt.Sprintf("type==%s, id==%s", plugins.SnapshotPlugin, snapshotterName)}
863863
in := c.IntrospectionService()
864864

865-
resp, err := in.Plugins(ctx, filters)
865+
resp, err := in.Plugins(ctx, filters...)
866866
if err != nil {
867867
return nil, err
868868
}
@@ -903,20 +903,10 @@ func (c *Client) RuntimeInfo(ctx context.Context, runtimePath string, runtimeOpt
903903
return nil, fmt.Errorf("failed to marshal %T: %w", runtimeOptions, err)
904904
}
905905
}
906-
options, err := protobuf.MarshalAnyToProto(rr)
907-
if err != nil {
908-
return nil, fmt.Errorf("failed to marshal runtime requst: %w", err)
909-
}
910906

911907
s := c.IntrospectionService()
912908

913-
req := &introspectionapi.PluginInfoRequest{
914-
Type: string(plugins.RuntimePluginV2),
915-
ID: "task",
916-
Options: options,
917-
}
918-
919-
resp, err := s.PluginInfo(ctx, req)
909+
resp, err := s.PluginInfo(ctx, string(plugins.RuntimePluginV2), "task", rr)
920910
if err != nil {
921911
return nil, err
922912
}

client/install.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -112,8 +112,7 @@ func (c *Client) getInstallPath(ctx context.Context, config InstallConfig) (stri
112112
if config.Path != "" {
113113
return config.Path, nil
114114
}
115-
filters := []string{"id==opt"}
116-
resp, err := c.IntrospectionService().Plugins(ctx, filters)
115+
resp, err := c.IntrospectionService().Plugins(ctx, "id==opt")
117116
if err != nil {
118117
return "", err
119118
}

client/services.go

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -22,19 +22,18 @@ import (
2222
containersapi "github.com/containerd/containerd/v2/api/services/containers/v1"
2323
"github.com/containerd/containerd/v2/api/services/diff/v1"
2424
imagesapi "github.com/containerd/containerd/v2/api/services/images/v1"
25-
introspectionapi "github.com/containerd/containerd/v2/api/services/introspection/v1"
2625
namespacesapi "github.com/containerd/containerd/v2/api/services/namespaces/v1"
2726
"github.com/containerd/containerd/v2/api/services/tasks/v1"
2827
"github.com/containerd/containerd/v2/core/containers"
2928
"github.com/containerd/containerd/v2/core/content"
3029
"github.com/containerd/containerd/v2/core/images"
30+
"github.com/containerd/containerd/v2/core/introspection"
3131
"github.com/containerd/containerd/v2/core/leases"
3232
"github.com/containerd/containerd/v2/core/sandbox"
3333
"github.com/containerd/containerd/v2/core/snapshots"
3434
"github.com/containerd/containerd/v2/pkg/namespaces"
3535
"github.com/containerd/containerd/v2/plugins"
3636
srv "github.com/containerd/containerd/v2/plugins/services"
37-
"github.com/containerd/containerd/v2/plugins/services/introspection"
3837
"github.com/containerd/plugin"
3938
)
4039

@@ -150,13 +149,6 @@ func WithLeasesService(leasesService leases.Manager) ServicesOpt {
150149
}
151150
}
152151

153-
// WithIntrospectionClient sets the introspection service using an introspection client.
154-
func WithIntrospectionClient(in introspectionapi.IntrospectionClient) ServicesOpt {
155-
return func(s *services) {
156-
s.introspectionService = introspection.NewIntrospectionServiceFromClient(in)
157-
}
158-
}
159-
160152
// WithIntrospectionService sets the introspection service.
161153
func WithIntrospectionService(in introspection.Service) ServicesOpt {
162154
return func(s *services) {
@@ -221,7 +213,7 @@ func WithInMemoryServices(ic *plugin.InitContext) Opt {
221213
return WithNamespaceClient(s.(namespacesapi.NamespacesClient))
222214
},
223215
srv.IntrospectionService: func(s interface{}) ServicesOpt {
224-
return WithIntrospectionClient(s.(introspectionapi.IntrospectionClient))
216+
return WithIntrospectionService(s.(introspection.Service))
225217
},
226218
} {
227219
i := plugins[s]

cmd/ctr/commands/client.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ import (
2424
containerd "github.com/containerd/containerd/v2/client"
2525
"github.com/containerd/containerd/v2/pkg/epoch"
2626
"github.com/containerd/containerd/v2/pkg/namespaces"
27-
ptypes "github.com/containerd/containerd/v2/protobuf/types"
2827
"github.com/containerd/log"
2928
"github.com/urfave/cli/v2"
3029
)
@@ -73,7 +72,7 @@ func NewClient(context *cli.Context, opts ...containerd.Opt) (*containerd.Client
7372
}
7473
}
7574
if !suppressDeprecationWarnings {
76-
resp, err := client.IntrospectionService().Server(ctx, &ptypes.Empty{})
75+
resp, err := client.IntrospectionService().Server(ctx)
7776
if err != nil {
7877
log.L.WithError(err).Warn("Failed to check deprecations")
7978
} else {

cmd/ctr/commands/deprecations/deprecations.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ import (
2727
api "github.com/containerd/containerd/v2/api/services/introspection/v1"
2828
"github.com/containerd/containerd/v2/cmd/ctr/commands"
2929
"github.com/containerd/containerd/v2/protobuf"
30-
ptypes "github.com/containerd/containerd/v2/protobuf/types"
3130
)
3231

3332
// Command is the parent for all commands under "deprecations"
@@ -56,7 +55,7 @@ var listCommand = &cli.Command{
5655
}
5756
defer cancel()
5857

59-
resp, err := client.IntrospectionService().Server(ctx, &ptypes.Empty{})
58+
resp, err := client.IntrospectionService().Server(ctx)
6059
if err != nil {
6160
return err
6261
}

cmd/ctr/commands/info/info.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ package info
1919
import (
2020
api "github.com/containerd/containerd/v2/api/services/introspection/v1"
2121
"github.com/containerd/containerd/v2/cmd/ctr/commands"
22-
ptypes "github.com/containerd/containerd/v2/protobuf/types"
2322
"github.com/urfave/cli/v2"
2423
)
2524

@@ -38,7 +37,7 @@ var Command = &cli.Command{
3837
}
3938
defer cancel()
4039
var info Info
41-
info.Server, err = client.IntrospectionService().Server(ctx, &ptypes.Empty{})
40+
info.Server, err = client.IntrospectionService().Server(ctx)
4241
if err != nil {
4342
return err
4443
}

cmd/ctr/commands/plugins/plugins.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ var listCommand = &cli.Command{
7171
}
7272
defer cancel()
7373
ps := client.IntrospectionService()
74-
response, err := ps.Plugins(ctx, context.Args().Slice())
74+
response, err := ps.Plugins(ctx, context.Args().Slice()...)
7575
if err != nil {
7676
return err
7777
}

core/introspection/introspection.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/*
2+
Copyright The containerd Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package introspection
18+
19+
import (
20+
context "context"
21+
22+
api "github.com/containerd/containerd/v2/api/services/introspection/v1"
23+
)
24+
25+
// Service defines the introspection service interface
26+
type Service interface {
27+
Plugins(context.Context, ...string) (*api.PluginsResponse, error)
28+
Server(context.Context) (*api.ServerResponse, error)
29+
PluginInfo(context.Context, string, string, any) (*api.PluginInfoResponse, error)
30+
}

core/introspection/proxy/remote.go

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
/*
2+
Copyright The containerd Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package introspectionproxy
18+
19+
import (
20+
"context"
21+
"fmt"
22+
23+
api "github.com/containerd/containerd/v2/api/services/introspection/v1"
24+
"github.com/containerd/containerd/v2/core/introspection"
25+
"github.com/containerd/containerd/v2/protobuf"
26+
"github.com/containerd/errdefs"
27+
"github.com/containerd/log"
28+
"github.com/containerd/ttrpc"
29+
"google.golang.org/grpc"
30+
"google.golang.org/protobuf/types/known/anypb"
31+
"google.golang.org/protobuf/types/known/emptypb"
32+
)
33+
34+
var _ = (introspection.Service)(&introspectionRemote{})
35+
36+
// NewIntrospectionServiceFromClient creates a new introspection service from an API client
37+
func NewIntrospectionProxy(client any) introspection.Service {
38+
switch c := client.(type) {
39+
case api.IntrospectionClient:
40+
return &introspectionRemote{client: convertIntrospection{c}}
41+
case api.TTRPCIntrospectionService:
42+
return &introspectionRemote{client: c}
43+
case grpc.ClientConnInterface:
44+
return &introspectionRemote{client: convertIntrospection{api.NewIntrospectionClient(c)}}
45+
case *ttrpc.Client:
46+
return &introspectionRemote{client: api.NewTTRPCIntrospectionClient(c)}
47+
default:
48+
panic(fmt.Errorf("unsupported introspection client %T: %w", client, errdefs.ErrNotImplemented))
49+
}
50+
}
51+
52+
type introspectionRemote struct {
53+
client api.TTRPCIntrospectionService
54+
}
55+
56+
func (i *introspectionRemote) Plugins(ctx context.Context, filters ...string) (*api.PluginsResponse, error) {
57+
log.G(ctx).WithField("filters", filters).Debug("remote introspection plugin filters")
58+
resp, err := i.client.Plugins(ctx, &api.PluginsRequest{
59+
Filters: filters,
60+
})
61+
62+
if err != nil {
63+
return nil, errdefs.FromGRPC(err)
64+
}
65+
66+
return resp, nil
67+
}
68+
69+
func (i *introspectionRemote) Server(ctx context.Context) (*api.ServerResponse, error) {
70+
resp, err := i.client.Server(ctx, &emptypb.Empty{})
71+
72+
if err != nil {
73+
return nil, errdefs.FromGRPC(err)
74+
}
75+
76+
return resp, nil
77+
}
78+
79+
func (i *introspectionRemote) PluginInfo(ctx context.Context, pluginType, id string, options any) (resp *api.PluginInfoResponse, err error) {
80+
var optionsPB *anypb.Any
81+
if options != nil {
82+
optionsPB, err = protobuf.MarshalAnyToProto(options)
83+
if err != nil {
84+
return nil, fmt.Errorf("failed to marshal runtime requst: %w", err)
85+
}
86+
}
87+
resp, err = i.client.PluginInfo(ctx, &api.PluginInfoRequest{
88+
Type: pluginType,
89+
ID: id,
90+
Options: optionsPB,
91+
})
92+
93+
return resp, errdefs.FromGRPC(err)
94+
}
95+
96+
type convertIntrospection struct {
97+
client api.IntrospectionClient
98+
}
99+
100+
func (c convertIntrospection) Plugins(ctx context.Context, req *api.PluginsRequest) (*api.PluginsResponse, error) {
101+
return c.client.Plugins(ctx, req)
102+
}
103+
func (c convertIntrospection) Server(ctx context.Context, in *emptypb.Empty) (*api.ServerResponse, error) {
104+
return c.client.Server(ctx, in)
105+
}
106+
func (c convertIntrospection) PluginInfo(ctx context.Context, req *api.PluginInfoRequest) (*api.PluginInfoResponse, error) {
107+
return c.client.PluginInfo(ctx, req)
108+
}

internal/cri/server/service.go

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,9 @@ import (
3434
runtime "k8s.io/cri-api/pkg/apis/runtime/v1"
3535
"k8s.io/kubelet/pkg/cri/streaming"
3636

37-
introspectionapi "github.com/containerd/containerd/v2/api/services/introspection/v1"
3837
apitypes "github.com/containerd/containerd/v2/api/types"
3938
containerd "github.com/containerd/containerd/v2/client"
39+
"github.com/containerd/containerd/v2/core/introspection"
4040
_ "github.com/containerd/containerd/v2/core/runtime" // for typeurl init
4141
"github.com/containerd/containerd/v2/core/sandbox"
4242
"github.com/containerd/containerd/v2/internal/cri/config"
@@ -54,7 +54,6 @@ import (
5454
"github.com/containerd/containerd/v2/pkg/oci"
5555
osinterface "github.com/containerd/containerd/v2/pkg/os"
5656
"github.com/containerd/containerd/v2/plugins"
57-
"github.com/containerd/containerd/v2/plugins/services/introspection"
5857
"github.com/containerd/containerd/v2/protobuf"
5958
)
6059

@@ -407,10 +406,7 @@ func introspectRuntimeFeatures(ctx context.Context, intro introspection.Service,
407406
plugins.RuntimeRuncV2, r.Type)
408407
// For other runtimes, protobuf.MarshalAnyToProto will cause nil panic during typeurl dereference
409408
}
410-
infoReq := &introspectionapi.PluginInfoRequest{
411-
Type: string(plugins.RuntimePluginV2), // "io.containerd.runtime.v2"
412-
ID: "task",
413-
}
409+
414410
rr := &apitypes.RuntimeRequest{
415411
RuntimePath: r.Type, // "io.containerd.runc.v2"
416412
}
@@ -425,11 +421,8 @@ func introspectRuntimeFeatures(ctx context.Context, intro introspection.Service,
425421
if err != nil {
426422
return nil, fmt.Errorf("failed to marshal %T: %w", options, err)
427423
}
428-
infoReq.Options, err = protobuf.MarshalAnyToProto(rr)
429-
if err != nil {
430-
return nil, fmt.Errorf("failed to marshal %T: %w", rr, err)
431-
}
432-
infoResp, err := intro.PluginInfo(ctx, infoReq)
424+
425+
infoResp, err := intro.PluginInfo(ctx, string(plugins.RuntimePluginV2), "task", rr)
433426
if err != nil {
434427
return nil, fmt.Errorf("failed to call PluginInfo: %w", err)
435428
}

0 commit comments

Comments
 (0)