Merge pull request #9911 from dmcgowan/introspection-split
Cleanup introspection interface
This commit is contained in:
		| @@ -29,7 +29,6 @@ import ( | |||||||
| 	containersapi "github.com/containerd/containerd/v2/api/services/containers/v1" | 	containersapi "github.com/containerd/containerd/v2/api/services/containers/v1" | ||||||
| 	diffapi "github.com/containerd/containerd/v2/api/services/diff/v1" | 	diffapi "github.com/containerd/containerd/v2/api/services/diff/v1" | ||||||
| 	imagesapi "github.com/containerd/containerd/v2/api/services/images/v1" | 	imagesapi "github.com/containerd/containerd/v2/api/services/images/v1" | ||||||
| 	introspectionapi "github.com/containerd/containerd/v2/api/services/introspection/v1" |  | ||||||
| 	leasesapi "github.com/containerd/containerd/v2/api/services/leases/v1" | 	leasesapi "github.com/containerd/containerd/v2/api/services/leases/v1" | ||||||
| 	namespacesapi "github.com/containerd/containerd/v2/api/services/namespaces/v1" | 	namespacesapi "github.com/containerd/containerd/v2/api/services/namespaces/v1" | ||||||
| 	sandboxsapi "github.com/containerd/containerd/v2/api/services/sandbox/v1" | 	sandboxsapi "github.com/containerd/containerd/v2/api/services/sandbox/v1" | ||||||
| @@ -43,6 +42,8 @@ import ( | |||||||
| 	"github.com/containerd/containerd/v2/core/events" | 	"github.com/containerd/containerd/v2/core/events" | ||||||
| 	eventsproxy "github.com/containerd/containerd/v2/core/events/proxy" | 	eventsproxy "github.com/containerd/containerd/v2/core/events/proxy" | ||||||
| 	"github.com/containerd/containerd/v2/core/images" | 	"github.com/containerd/containerd/v2/core/images" | ||||||
|  | 	"github.com/containerd/containerd/v2/core/introspection" | ||||||
|  | 	introspectionproxy "github.com/containerd/containerd/v2/core/introspection/proxy" | ||||||
| 	"github.com/containerd/containerd/v2/core/leases" | 	"github.com/containerd/containerd/v2/core/leases" | ||||||
| 	leasesproxy "github.com/containerd/containerd/v2/core/leases/proxy" | 	leasesproxy "github.com/containerd/containerd/v2/core/leases/proxy" | ||||||
| 	"github.com/containerd/containerd/v2/core/remotes" | 	"github.com/containerd/containerd/v2/core/remotes" | ||||||
| @@ -55,7 +56,6 @@ import ( | |||||||
| 	"github.com/containerd/containerd/v2/pkg/dialer" | 	"github.com/containerd/containerd/v2/pkg/dialer" | ||||||
| 	"github.com/containerd/containerd/v2/pkg/namespaces" | 	"github.com/containerd/containerd/v2/pkg/namespaces" | ||||||
| 	"github.com/containerd/containerd/v2/plugins" | 	"github.com/containerd/containerd/v2/plugins" | ||||||
| 	"github.com/containerd/containerd/v2/plugins/services/introspection" |  | ||||||
| 	"github.com/containerd/containerd/v2/protobuf" | 	"github.com/containerd/containerd/v2/protobuf" | ||||||
| 	ptypes "github.com/containerd/containerd/v2/protobuf/types" | 	ptypes "github.com/containerd/containerd/v2/protobuf/types" | ||||||
| 	"github.com/containerd/errdefs" | 	"github.com/containerd/errdefs" | ||||||
| @@ -680,7 +680,7 @@ func (c *Client) IntrospectionService() introspection.Service { | |||||||
| 	} | 	} | ||||||
| 	c.connMu.Lock() | 	c.connMu.Lock() | ||||||
| 	defer c.connMu.Unlock() | 	defer c.connMu.Unlock() | ||||||
| 	return introspection.NewIntrospectionServiceFromClient(introspectionapi.NewIntrospectionClient(c.conn)) | 	return introspectionproxy.NewIntrospectionProxy(c.conn) | ||||||
| } | } | ||||||
|  |  | ||||||
| // LeasesService returns the underlying Leases Client | // LeasesService returns the underlying Leases Client | ||||||
| @@ -785,7 +785,7 @@ func (c *Client) Server(ctx context.Context) (ServerInfo, error) { | |||||||
| 	} | 	} | ||||||
| 	c.connMu.Unlock() | 	c.connMu.Unlock() | ||||||
|  |  | ||||||
| 	response, err := c.IntrospectionService().Server(ctx, &ptypes.Empty{}) | 	response, err := c.IntrospectionService().Server(ctx) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return ServerInfo{}, err | 		return ServerInfo{}, err | ||||||
| 	} | 	} | ||||||
| @@ -831,7 +831,7 @@ func (c *Client) GetSnapshotterSupportedPlatforms(ctx context.Context, snapshott | |||||||
| 	filters := []string{fmt.Sprintf("type==%s, id==%s", plugins.SnapshotPlugin, snapshotterName)} | 	filters := []string{fmt.Sprintf("type==%s, id==%s", plugins.SnapshotPlugin, snapshotterName)} | ||||||
| 	in := c.IntrospectionService() | 	in := c.IntrospectionService() | ||||||
|  |  | ||||||
| 	resp, err := in.Plugins(ctx, filters) | 	resp, err := in.Plugins(ctx, filters...) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return nil, err | 		return nil, err | ||||||
| 	} | 	} | ||||||
| @@ -862,7 +862,7 @@ func (c *Client) GetSnapshotterCapabilities(ctx context.Context, snapshotterName | |||||||
| 	filters := []string{fmt.Sprintf("type==%s, id==%s", plugins.SnapshotPlugin, snapshotterName)} | 	filters := []string{fmt.Sprintf("type==%s, id==%s", plugins.SnapshotPlugin, snapshotterName)} | ||||||
| 	in := c.IntrospectionService() | 	in := c.IntrospectionService() | ||||||
|  |  | ||||||
| 	resp, err := in.Plugins(ctx, filters) | 	resp, err := in.Plugins(ctx, filters...) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return nil, err | 		return nil, err | ||||||
| 	} | 	} | ||||||
| @@ -903,20 +903,10 @@ func (c *Client) RuntimeInfo(ctx context.Context, runtimePath string, runtimeOpt | |||||||
| 			return nil, fmt.Errorf("failed to marshal %T: %w", runtimeOptions, err) | 			return nil, fmt.Errorf("failed to marshal %T: %w", runtimeOptions, err) | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	options, err := protobuf.MarshalAnyToProto(rr) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, fmt.Errorf("failed to marshal runtime requst: %w", err) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	s := c.IntrospectionService() | 	s := c.IntrospectionService() | ||||||
|  |  | ||||||
| 	req := &introspectionapi.PluginInfoRequest{ | 	resp, err := s.PluginInfo(ctx, string(plugins.RuntimePluginV2), "task", rr) | ||||||
| 		Type:    string(plugins.RuntimePluginV2), |  | ||||||
| 		ID:      "task", |  | ||||||
| 		Options: options, |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	resp, err := s.PluginInfo(ctx, req) |  | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return nil, err | 		return nil, err | ||||||
| 	} | 	} | ||||||
|   | |||||||
| @@ -112,8 +112,7 @@ func (c *Client) getInstallPath(ctx context.Context, config InstallConfig) (stri | |||||||
| 	if config.Path != "" { | 	if config.Path != "" { | ||||||
| 		return config.Path, nil | 		return config.Path, nil | ||||||
| 	} | 	} | ||||||
| 	filters := []string{"id==opt"} | 	resp, err := c.IntrospectionService().Plugins(ctx, "id==opt") | ||||||
| 	resp, err := c.IntrospectionService().Plugins(ctx, filters) |  | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return "", err | 		return "", err | ||||||
| 	} | 	} | ||||||
|   | |||||||
| @@ -22,19 +22,18 @@ import ( | |||||||
| 	containersapi "github.com/containerd/containerd/v2/api/services/containers/v1" | 	containersapi "github.com/containerd/containerd/v2/api/services/containers/v1" | ||||||
| 	"github.com/containerd/containerd/v2/api/services/diff/v1" | 	"github.com/containerd/containerd/v2/api/services/diff/v1" | ||||||
| 	imagesapi "github.com/containerd/containerd/v2/api/services/images/v1" | 	imagesapi "github.com/containerd/containerd/v2/api/services/images/v1" | ||||||
| 	introspectionapi "github.com/containerd/containerd/v2/api/services/introspection/v1" |  | ||||||
| 	namespacesapi "github.com/containerd/containerd/v2/api/services/namespaces/v1" | 	namespacesapi "github.com/containerd/containerd/v2/api/services/namespaces/v1" | ||||||
| 	"github.com/containerd/containerd/v2/api/services/tasks/v1" | 	"github.com/containerd/containerd/v2/api/services/tasks/v1" | ||||||
| 	"github.com/containerd/containerd/v2/core/containers" | 	"github.com/containerd/containerd/v2/core/containers" | ||||||
| 	"github.com/containerd/containerd/v2/core/content" | 	"github.com/containerd/containerd/v2/core/content" | ||||||
| 	"github.com/containerd/containerd/v2/core/images" | 	"github.com/containerd/containerd/v2/core/images" | ||||||
|  | 	"github.com/containerd/containerd/v2/core/introspection" | ||||||
| 	"github.com/containerd/containerd/v2/core/leases" | 	"github.com/containerd/containerd/v2/core/leases" | ||||||
| 	"github.com/containerd/containerd/v2/core/sandbox" | 	"github.com/containerd/containerd/v2/core/sandbox" | ||||||
| 	"github.com/containerd/containerd/v2/core/snapshots" | 	"github.com/containerd/containerd/v2/core/snapshots" | ||||||
| 	"github.com/containerd/containerd/v2/pkg/namespaces" | 	"github.com/containerd/containerd/v2/pkg/namespaces" | ||||||
| 	"github.com/containerd/containerd/v2/plugins" | 	"github.com/containerd/containerd/v2/plugins" | ||||||
| 	srv "github.com/containerd/containerd/v2/plugins/services" | 	srv "github.com/containerd/containerd/v2/plugins/services" | ||||||
| 	"github.com/containerd/containerd/v2/plugins/services/introspection" |  | ||||||
| 	"github.com/containerd/plugin" | 	"github.com/containerd/plugin" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| @@ -150,13 +149,6 @@ func WithLeasesService(leasesService leases.Manager) ServicesOpt { | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| // WithIntrospectionClient sets the introspection service using an introspection client. |  | ||||||
| func WithIntrospectionClient(in introspectionapi.IntrospectionClient) ServicesOpt { |  | ||||||
| 	return func(s *services) { |  | ||||||
| 		s.introspectionService = introspection.NewIntrospectionServiceFromClient(in) |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // WithIntrospectionService sets the introspection service. | // WithIntrospectionService sets the introspection service. | ||||||
| func WithIntrospectionService(in introspection.Service) ServicesOpt { | func WithIntrospectionService(in introspection.Service) ServicesOpt { | ||||||
| 	return func(s *services) { | 	return func(s *services) { | ||||||
| @@ -221,7 +213,7 @@ func WithInMemoryServices(ic *plugin.InitContext) Opt { | |||||||
| 				return WithNamespaceClient(s.(namespacesapi.NamespacesClient)) | 				return WithNamespaceClient(s.(namespacesapi.NamespacesClient)) | ||||||
| 			}, | 			}, | ||||||
| 			srv.IntrospectionService: func(s interface{}) ServicesOpt { | 			srv.IntrospectionService: func(s interface{}) ServicesOpt { | ||||||
| 				return WithIntrospectionClient(s.(introspectionapi.IntrospectionClient)) | 				return WithIntrospectionService(s.(introspection.Service)) | ||||||
| 			}, | 			}, | ||||||
| 		} { | 		} { | ||||||
| 			i := plugins[s] | 			i := plugins[s] | ||||||
|   | |||||||
| @@ -24,7 +24,6 @@ import ( | |||||||
| 	containerd "github.com/containerd/containerd/v2/client" | 	containerd "github.com/containerd/containerd/v2/client" | ||||||
| 	"github.com/containerd/containerd/v2/pkg/epoch" | 	"github.com/containerd/containerd/v2/pkg/epoch" | ||||||
| 	"github.com/containerd/containerd/v2/pkg/namespaces" | 	"github.com/containerd/containerd/v2/pkg/namespaces" | ||||||
| 	ptypes "github.com/containerd/containerd/v2/protobuf/types" |  | ||||||
| 	"github.com/containerd/log" | 	"github.com/containerd/log" | ||||||
| 	"github.com/urfave/cli/v2" | 	"github.com/urfave/cli/v2" | ||||||
| ) | ) | ||||||
| @@ -73,7 +72,7 @@ func NewClient(context *cli.Context, opts ...containerd.Opt) (*containerd.Client | |||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	if !suppressDeprecationWarnings { | 	if !suppressDeprecationWarnings { | ||||||
| 		resp, err := client.IntrospectionService().Server(ctx, &ptypes.Empty{}) | 		resp, err := client.IntrospectionService().Server(ctx) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			log.L.WithError(err).Warn("Failed to check deprecations") | 			log.L.WithError(err).Warn("Failed to check deprecations") | ||||||
| 		} else { | 		} else { | ||||||
|   | |||||||
| @@ -27,7 +27,6 @@ import ( | |||||||
| 	api "github.com/containerd/containerd/v2/api/services/introspection/v1" | 	api "github.com/containerd/containerd/v2/api/services/introspection/v1" | ||||||
| 	"github.com/containerd/containerd/v2/cmd/ctr/commands" | 	"github.com/containerd/containerd/v2/cmd/ctr/commands" | ||||||
| 	"github.com/containerd/containerd/v2/protobuf" | 	"github.com/containerd/containerd/v2/protobuf" | ||||||
| 	ptypes "github.com/containerd/containerd/v2/protobuf/types" |  | ||||||
| ) | ) | ||||||
|  |  | ||||||
| // Command is the parent for all commands under "deprecations" | // Command is the parent for all commands under "deprecations" | ||||||
| @@ -56,7 +55,7 @@ var listCommand = &cli.Command{ | |||||||
| 		} | 		} | ||||||
| 		defer cancel() | 		defer cancel() | ||||||
|  |  | ||||||
| 		resp, err := client.IntrospectionService().Server(ctx, &ptypes.Empty{}) | 		resp, err := client.IntrospectionService().Server(ctx) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			return err | 			return err | ||||||
| 		} | 		} | ||||||
|   | |||||||
| @@ -19,7 +19,6 @@ package info | |||||||
| import ( | import ( | ||||||
| 	api "github.com/containerd/containerd/v2/api/services/introspection/v1" | 	api "github.com/containerd/containerd/v2/api/services/introspection/v1" | ||||||
| 	"github.com/containerd/containerd/v2/cmd/ctr/commands" | 	"github.com/containerd/containerd/v2/cmd/ctr/commands" | ||||||
| 	ptypes "github.com/containerd/containerd/v2/protobuf/types" |  | ||||||
| 	"github.com/urfave/cli/v2" | 	"github.com/urfave/cli/v2" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| @@ -38,7 +37,7 @@ var Command = &cli.Command{ | |||||||
| 		} | 		} | ||||||
| 		defer cancel() | 		defer cancel() | ||||||
| 		var info Info | 		var info Info | ||||||
| 		info.Server, err = client.IntrospectionService().Server(ctx, &ptypes.Empty{}) | 		info.Server, err = client.IntrospectionService().Server(ctx) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			return err | 			return err | ||||||
| 		} | 		} | ||||||
|   | |||||||
| @@ -71,7 +71,7 @@ var listCommand = &cli.Command{ | |||||||
| 		} | 		} | ||||||
| 		defer cancel() | 		defer cancel() | ||||||
| 		ps := client.IntrospectionService() | 		ps := client.IntrospectionService() | ||||||
| 		response, err := ps.Plugins(ctx, context.Args().Slice()) | 		response, err := ps.Plugins(ctx, context.Args().Slice()...) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			return err | 			return err | ||||||
| 		} | 		} | ||||||
|   | |||||||
							
								
								
									
										30
									
								
								core/introspection/introspection.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								core/introspection/introspection.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,30 @@ | |||||||
|  | /* | ||||||
|  |    Copyright The containerd 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 introspection | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	context "context" | ||||||
|  |  | ||||||
|  | 	api "github.com/containerd/containerd/v2/api/services/introspection/v1" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // Service defines the introspection service interface | ||||||
|  | type Service interface { | ||||||
|  | 	Plugins(context.Context, ...string) (*api.PluginsResponse, error) | ||||||
|  | 	Server(context.Context) (*api.ServerResponse, error) | ||||||
|  | 	PluginInfo(context.Context, string, string, any) (*api.PluginInfoResponse, error) | ||||||
|  | } | ||||||
							
								
								
									
										108
									
								
								core/introspection/proxy/remote.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										108
									
								
								core/introspection/proxy/remote.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,108 @@ | |||||||
|  | /* | ||||||
|  |    Copyright The containerd 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 introspectionproxy | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"context" | ||||||
|  | 	"fmt" | ||||||
|  |  | ||||||
|  | 	api "github.com/containerd/containerd/v2/api/services/introspection/v1" | ||||||
|  | 	"github.com/containerd/containerd/v2/core/introspection" | ||||||
|  | 	"github.com/containerd/containerd/v2/protobuf" | ||||||
|  | 	"github.com/containerd/errdefs" | ||||||
|  | 	"github.com/containerd/log" | ||||||
|  | 	"github.com/containerd/ttrpc" | ||||||
|  | 	"google.golang.org/grpc" | ||||||
|  | 	"google.golang.org/protobuf/types/known/anypb" | ||||||
|  | 	"google.golang.org/protobuf/types/known/emptypb" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | var _ = (introspection.Service)(&introspectionRemote{}) | ||||||
|  |  | ||||||
|  | // NewIntrospectionServiceFromClient creates a new introspection service from an API client | ||||||
|  | func NewIntrospectionProxy(client any) introspection.Service { | ||||||
|  | 	switch c := client.(type) { | ||||||
|  | 	case api.IntrospectionClient: | ||||||
|  | 		return &introspectionRemote{client: convertIntrospection{c}} | ||||||
|  | 	case api.TTRPCIntrospectionService: | ||||||
|  | 		return &introspectionRemote{client: c} | ||||||
|  | 	case grpc.ClientConnInterface: | ||||||
|  | 		return &introspectionRemote{client: convertIntrospection{api.NewIntrospectionClient(c)}} | ||||||
|  | 	case *ttrpc.Client: | ||||||
|  | 		return &introspectionRemote{client: api.NewTTRPCIntrospectionClient(c)} | ||||||
|  | 	default: | ||||||
|  | 		panic(fmt.Errorf("unsupported introspection client %T: %w", client, errdefs.ErrNotImplemented)) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type introspectionRemote struct { | ||||||
|  | 	client api.TTRPCIntrospectionService | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (i *introspectionRemote) Plugins(ctx context.Context, filters ...string) (*api.PluginsResponse, error) { | ||||||
|  | 	log.G(ctx).WithField("filters", filters).Debug("remote introspection plugin filters") | ||||||
|  | 	resp, err := i.client.Plugins(ctx, &api.PluginsRequest{ | ||||||
|  | 		Filters: filters, | ||||||
|  | 	}) | ||||||
|  |  | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, errdefs.FromGRPC(err) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return resp, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (i *introspectionRemote) Server(ctx context.Context) (*api.ServerResponse, error) { | ||||||
|  | 	resp, err := i.client.Server(ctx, &emptypb.Empty{}) | ||||||
|  |  | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, errdefs.FromGRPC(err) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return resp, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (i *introspectionRemote) PluginInfo(ctx context.Context, pluginType, id string, options any) (resp *api.PluginInfoResponse, err error) { | ||||||
|  | 	var optionsPB *anypb.Any | ||||||
|  | 	if options != nil { | ||||||
|  | 		optionsPB, err = protobuf.MarshalAnyToProto(options) | ||||||
|  | 		if err != nil { | ||||||
|  | 			return nil, fmt.Errorf("failed to marshal runtime requst: %w", err) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	resp, err = i.client.PluginInfo(ctx, &api.PluginInfoRequest{ | ||||||
|  | 		Type:    pluginType, | ||||||
|  | 		ID:      id, | ||||||
|  | 		Options: optionsPB, | ||||||
|  | 	}) | ||||||
|  |  | ||||||
|  | 	return resp, errdefs.FromGRPC(err) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type convertIntrospection struct { | ||||||
|  | 	client api.IntrospectionClient | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (c convertIntrospection) Plugins(ctx context.Context, req *api.PluginsRequest) (*api.PluginsResponse, error) { | ||||||
|  | 	return c.client.Plugins(ctx, req) | ||||||
|  | } | ||||||
|  | func (c convertIntrospection) Server(ctx context.Context, in *emptypb.Empty) (*api.ServerResponse, error) { | ||||||
|  | 	return c.client.Server(ctx, in) | ||||||
|  | } | ||||||
|  | func (c convertIntrospection) PluginInfo(ctx context.Context, req *api.PluginInfoRequest) (*api.PluginInfoResponse, error) { | ||||||
|  | 	return c.client.PluginInfo(ctx, req) | ||||||
|  | } | ||||||
| @@ -34,9 +34,9 @@ import ( | |||||||
| 	runtime "k8s.io/cri-api/pkg/apis/runtime/v1" | 	runtime "k8s.io/cri-api/pkg/apis/runtime/v1" | ||||||
| 	"k8s.io/kubelet/pkg/cri/streaming" | 	"k8s.io/kubelet/pkg/cri/streaming" | ||||||
|  |  | ||||||
| 	introspectionapi "github.com/containerd/containerd/v2/api/services/introspection/v1" |  | ||||||
| 	apitypes "github.com/containerd/containerd/v2/api/types" | 	apitypes "github.com/containerd/containerd/v2/api/types" | ||||||
| 	containerd "github.com/containerd/containerd/v2/client" | 	containerd "github.com/containerd/containerd/v2/client" | ||||||
|  | 	"github.com/containerd/containerd/v2/core/introspection" | ||||||
| 	_ "github.com/containerd/containerd/v2/core/runtime" // for typeurl init | 	_ "github.com/containerd/containerd/v2/core/runtime" // for typeurl init | ||||||
| 	"github.com/containerd/containerd/v2/core/sandbox" | 	"github.com/containerd/containerd/v2/core/sandbox" | ||||||
| 	"github.com/containerd/containerd/v2/internal/cri/config" | 	"github.com/containerd/containerd/v2/internal/cri/config" | ||||||
| @@ -54,7 +54,6 @@ import ( | |||||||
| 	"github.com/containerd/containerd/v2/pkg/oci" | 	"github.com/containerd/containerd/v2/pkg/oci" | ||||||
| 	osinterface "github.com/containerd/containerd/v2/pkg/os" | 	osinterface "github.com/containerd/containerd/v2/pkg/os" | ||||||
| 	"github.com/containerd/containerd/v2/plugins" | 	"github.com/containerd/containerd/v2/plugins" | ||||||
| 	"github.com/containerd/containerd/v2/plugins/services/introspection" |  | ||||||
| 	"github.com/containerd/containerd/v2/protobuf" | 	"github.com/containerd/containerd/v2/protobuf" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| @@ -407,10 +406,7 @@ func introspectRuntimeFeatures(ctx context.Context, intro introspection.Service, | |||||||
| 			plugins.RuntimeRuncV2, r.Type) | 			plugins.RuntimeRuncV2, r.Type) | ||||||
| 		// For other runtimes, protobuf.MarshalAnyToProto will cause nil panic during typeurl dereference | 		// For other runtimes, protobuf.MarshalAnyToProto will cause nil panic during typeurl dereference | ||||||
| 	} | 	} | ||||||
| 	infoReq := &introspectionapi.PluginInfoRequest{ |  | ||||||
| 		Type: string(plugins.RuntimePluginV2), // "io.containerd.runtime.v2" |  | ||||||
| 		ID:   "task", |  | ||||||
| 	} |  | ||||||
| 	rr := &apitypes.RuntimeRequest{ | 	rr := &apitypes.RuntimeRequest{ | ||||||
| 		RuntimePath: r.Type, // "io.containerd.runc.v2" | 		RuntimePath: r.Type, // "io.containerd.runc.v2" | ||||||
| 	} | 	} | ||||||
| @@ -425,11 +421,8 @@ func introspectRuntimeFeatures(ctx context.Context, intro introspection.Service, | |||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return nil, fmt.Errorf("failed to marshal %T: %w", options, err) | 		return nil, fmt.Errorf("failed to marshal %T: %w", options, err) | ||||||
| 	} | 	} | ||||||
| 	infoReq.Options, err = protobuf.MarshalAnyToProto(rr) |  | ||||||
| 	if err != nil { | 	infoResp, err := intro.PluginInfo(ctx, string(plugins.RuntimePluginV2), "task", rr) | ||||||
| 		return nil, fmt.Errorf("failed to marshal %T: %w", rr, err) |  | ||||||
| 	} |  | ||||||
| 	infoResp, err := intro.PluginInfo(ctx, infoReq) |  | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return nil, fmt.Errorf("failed to call PluginInfo: %w", err) | 		return nil, fmt.Errorf("failed to call PluginInfo: %w", err) | ||||||
| 	} | 	} | ||||||
|   | |||||||
| @@ -23,7 +23,6 @@ import ( | |||||||
| 	goruntime "runtime" | 	goruntime "runtime" | ||||||
|  |  | ||||||
| 	"github.com/containerd/containerd/v2/api/services/introspection/v1" | 	"github.com/containerd/containerd/v2/api/services/introspection/v1" | ||||||
| 	ptypes "github.com/containerd/containerd/v2/protobuf/types" |  | ||||||
| 	"github.com/containerd/log" | 	"github.com/containerd/log" | ||||||
| 	runtime "k8s.io/cri-api/pkg/apis/runtime/v1" | 	runtime "k8s.io/cri-api/pkg/apis/runtime/v1" | ||||||
| ) | ) | ||||||
| @@ -97,7 +96,7 @@ func (c *criService) Status(ctx context.Context, r *runtime.StatusRequest) (*run | |||||||
| 		} | 		} | ||||||
| 		resp.Info["lastCNILoadStatus"] = defaultStatus | 		resp.Info["lastCNILoadStatus"] = defaultStatus | ||||||
| 	} | 	} | ||||||
| 	intro, err := c.client.IntrospectionService().Server(ctx, &ptypes.Empty{}) | 	intro, err := c.client.IntrospectionService().Server(ctx) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return nil, err | 		return nil, err | ||||||
| 	} | 	} | ||||||
|   | |||||||
| @@ -1,77 +0,0 @@ | |||||||
| /* |  | ||||||
|    Copyright The containerd 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 introspection |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	context "context" |  | ||||||
|  |  | ||||||
| 	api "github.com/containerd/containerd/v2/api/services/introspection/v1" |  | ||||||
| 	ptypes "github.com/containerd/containerd/v2/protobuf/types" |  | ||||||
| 	"github.com/containerd/errdefs" |  | ||||||
| 	"github.com/containerd/log" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| // Service defines the introspection service interface |  | ||||||
| type Service interface { |  | ||||||
| 	Plugins(context.Context, []string) (*api.PluginsResponse, error) |  | ||||||
| 	Server(context.Context, *ptypes.Empty) (*api.ServerResponse, error) |  | ||||||
| 	PluginInfo(ctx context.Context, in *api.PluginInfoRequest) (*api.PluginInfoResponse, error) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| type introspectionRemote struct { |  | ||||||
| 	client api.IntrospectionClient |  | ||||||
| } |  | ||||||
|  |  | ||||||
| var _ = (Service)(&introspectionRemote{}) |  | ||||||
|  |  | ||||||
| // NewIntrospectionServiceFromClient creates a new introspection service from an API client |  | ||||||
| func NewIntrospectionServiceFromClient(c api.IntrospectionClient) Service { |  | ||||||
| 	return &introspectionRemote{client: c} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (i *introspectionRemote) Plugins(ctx context.Context, filters []string) (*api.PluginsResponse, error) { |  | ||||||
| 	log.G(ctx).WithField("filters", filters).Debug("remote introspection plugin filters") |  | ||||||
| 	resp, err := i.client.Plugins(ctx, &api.PluginsRequest{ |  | ||||||
| 		Filters: filters, |  | ||||||
| 	}) |  | ||||||
|  |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, errdefs.FromGRPC(err) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return resp, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (i *introspectionRemote) Server(ctx context.Context, in *ptypes.Empty) (*api.ServerResponse, error) { |  | ||||||
| 	resp, err := i.client.Server(ctx, in) |  | ||||||
|  |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, errdefs.FromGRPC(err) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return resp, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (i *introspectionRemote) PluginInfo(ctx context.Context, in *api.PluginInfoRequest) (*api.PluginInfoResponse, error) { |  | ||||||
| 	resp, err := i.client.PluginInfo(ctx, in) |  | ||||||
|  |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, errdefs.FromGRPC(err) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return resp, nil |  | ||||||
| } |  | ||||||
| @@ -28,11 +28,11 @@ import ( | |||||||
| 	"github.com/google/uuid" | 	"github.com/google/uuid" | ||||||
| 	"google.golang.org/genproto/googleapis/rpc/code" | 	"google.golang.org/genproto/googleapis/rpc/code" | ||||||
| 	rpc "google.golang.org/genproto/googleapis/rpc/status" | 	rpc "google.golang.org/genproto/googleapis/rpc/status" | ||||||
| 	"google.golang.org/grpc" |  | ||||||
| 	"google.golang.org/grpc/status" | 	"google.golang.org/grpc/status" | ||||||
|  |  | ||||||
| 	api "github.com/containerd/containerd/v2/api/services/introspection/v1" | 	api "github.com/containerd/containerd/v2/api/services/introspection/v1" | ||||||
| 	"github.com/containerd/containerd/v2/api/types" | 	"github.com/containerd/containerd/v2/api/types" | ||||||
|  | 	"github.com/containerd/containerd/v2/core/introspection" | ||||||
| 	"github.com/containerd/containerd/v2/pkg/filters" | 	"github.com/containerd/containerd/v2/pkg/filters" | ||||||
| 	"github.com/containerd/containerd/v2/plugins" | 	"github.com/containerd/containerd/v2/plugins" | ||||||
| 	"github.com/containerd/containerd/v2/plugins/services" | 	"github.com/containerd/containerd/v2/plugins/services" | ||||||
| @@ -80,7 +80,7 @@ type Local struct { | |||||||
| 	warningClient warning.Service | 	warningClient warning.Service | ||||||
| } | } | ||||||
|  |  | ||||||
| var _ = (api.IntrospectionClient)(&Local{}) | var _ = (introspection.Service)(&Local{}) | ||||||
|  |  | ||||||
| // UpdateLocal updates the local introspection service | // UpdateLocal updates the local introspection service | ||||||
| func (l *Local) UpdateLocal(root string) { | func (l *Local) UpdateLocal(root string) { | ||||||
| @@ -90,10 +90,10 @@ func (l *Local) UpdateLocal(root string) { | |||||||
| } | } | ||||||
|  |  | ||||||
| // Plugins returns the locally defined plugins | // Plugins returns the locally defined plugins | ||||||
| func (l *Local) Plugins(ctx context.Context, req *api.PluginsRequest, _ ...grpc.CallOption) (*api.PluginsResponse, error) { | func (l *Local) Plugins(ctx context.Context, fs ...string) (*api.PluginsResponse, error) { | ||||||
| 	filter, err := filters.ParseAll(req.Filters...) | 	filter, err := filters.ParseAll(fs...) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return nil, errdefs.ToGRPCf(errdefs.ErrInvalidArgument, err.Error()) | 		return nil, fmt.Errorf("%w: %w", errdefs.ErrInvalidArgument, err) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	var plugins []*api.Plugin | 	var plugins []*api.Plugin | ||||||
| @@ -121,17 +121,17 @@ func (l *Local) getPlugins() []*api.Plugin { | |||||||
| } | } | ||||||
|  |  | ||||||
| // Server returns the local server information | // Server returns the local server information | ||||||
| func (l *Local) Server(ctx context.Context, _ *ptypes.Empty, _ ...grpc.CallOption) (*api.ServerResponse, error) { | func (l *Local) Server(ctx context.Context) (*api.ServerResponse, error) { | ||||||
| 	u, err := l.getUUID() | 	u, err := l.getUUID() | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return nil, errdefs.ToGRPC(err) | 		return nil, err | ||||||
| 	} | 	} | ||||||
| 	pid := os.Getpid() | 	pid := os.Getpid() | ||||||
| 	var pidns uint64 | 	var pidns uint64 | ||||||
| 	if runtime.GOOS == "linux" { | 	if runtime.GOOS == "linux" { | ||||||
| 		pidns, err = statPIDNS(pid) | 		pidns, err = statPIDNS(pid) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			return nil, errdefs.ToGRPC(err) | 			return nil, err | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	return &api.ServerResponse{ | 	return &api.ServerResponse{ | ||||||
| @@ -278,11 +278,10 @@ type pluginInfoProvider interface { | |||||||
| 	PluginInfo(context.Context, interface{}) (interface{}, error) | 	PluginInfo(context.Context, interface{}) (interface{}, error) | ||||||
| } | } | ||||||
|  |  | ||||||
| func (l *Local) PluginInfo(ctx context.Context, req *api.PluginInfoRequest, _ ...grpc.CallOption) (*api.PluginInfoResponse, error) { | func (l *Local) PluginInfo(ctx context.Context, pluginType, id string, options any) (*api.PluginInfoResponse, error) { | ||||||
| 	p := l.plugins.Get(plugin.Type(req.Type), req.ID) | 	p := l.plugins.Get(plugin.Type(pluginType), id) | ||||||
| 	if p == nil { | 	if p == nil { | ||||||
| 		err := fmt.Errorf("plugin %s.%s not found: %w", req.Type, req.ID, errdefs.ErrNotFound) | 		return nil, fmt.Errorf("plugin %s.%s not found: %w", pluginType, id, errdefs.ErrNotFound) | ||||||
| 		return nil, errdefs.ToGRPC(err) |  | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	resp := &api.PluginInfoResponse{ | 	resp := &api.PluginInfoResponse{ | ||||||
| @@ -290,35 +289,26 @@ func (l *Local) PluginInfo(ctx context.Context, req *api.PluginInfoRequest, _ .. | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	// Request additional info from plugin instance | 	// Request additional info from plugin instance | ||||||
| 	if req.Options != nil { | 	if options != nil { | ||||||
| 		if p.Err() != nil { | 		if p.Err() != nil { | ||||||
| 			err := fmt.Errorf("cannot get extra info, plugin not successfully loaded: %w", errdefs.ErrFailedPrecondition) | 			return resp, fmt.Errorf("cannot get extra info, plugin not successfully loaded: %w", errdefs.ErrFailedPrecondition) | ||||||
| 			return resp, errdefs.ToGRPC(err) |  | ||||||
| 		} | 		} | ||||||
| 		inst, err := p.Instance() | 		inst, err := p.Instance() | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			err := fmt.Errorf("failed to get plugin instance: %w", errdefs.ErrFailedPrecondition) | 			return resp, fmt.Errorf("failed to get plugin instance: %w", errdefs.ErrFailedPrecondition) | ||||||
| 			return resp, errdefs.ToGRPC(err) |  | ||||||
| 		} | 		} | ||||||
| 		pi, ok := inst.(pluginInfoProvider) | 		pi, ok := inst.(pluginInfoProvider) | ||||||
| 		if !ok { | 		if !ok { | ||||||
| 			err := fmt.Errorf("plugin does not provided extra information: %w", errdefs.ErrNotImplemented) | 			return resp, fmt.Errorf("plugin does not provided extra information: %w", errdefs.ErrNotImplemented) | ||||||
| 			return resp, errdefs.ToGRPC(err) |  | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		options, err := typeurl.UnmarshalAny(req.Options) |  | ||||||
| 		if err != nil { |  | ||||||
| 			err = fmt.Errorf("failed to unmarshal plugin info Options: %w", err) |  | ||||||
| 			return resp, errdefs.ToGRPC(err) |  | ||||||
| 		} |  | ||||||
| 		info, err := pi.PluginInfo(ctx, options) | 		info, err := pi.PluginInfo(ctx, options) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			return resp, errdefs.ToGRPC(err) | 			return resp, errdefs.ToGRPC(err) | ||||||
| 		} | 		} | ||||||
| 		ai, err := typeurl.MarshalAny(info) | 		ai, err := typeurl.MarshalAny(info) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			err = fmt.Errorf("failed to marshal plugin info: %w", err) | 			return resp, fmt.Errorf("failed to marshal plugin info: %w", err) | ||||||
| 			return resp, errdefs.ToGRPC(err) |  | ||||||
| 		} | 		} | ||||||
| 		resp.Extra = &ptypes.Any{ | 		resp.Extra = &ptypes.Any{ | ||||||
| 			TypeUrl: ai.GetTypeUrl(), | 			TypeUrl: ai.GetTypeUrl(), | ||||||
|   | |||||||
| @@ -19,13 +19,17 @@ package introspection | |||||||
| import ( | import ( | ||||||
| 	context "context" | 	context "context" | ||||||
| 	"errors" | 	"errors" | ||||||
|  | 	"fmt" | ||||||
|  |  | ||||||
| 	api "github.com/containerd/containerd/v2/api/services/introspection/v1" | 	api "github.com/containerd/containerd/v2/api/services/introspection/v1" | ||||||
|  | 	"github.com/containerd/containerd/v2/core/introspection" | ||||||
| 	"github.com/containerd/containerd/v2/plugins" | 	"github.com/containerd/containerd/v2/plugins" | ||||||
| 	"github.com/containerd/containerd/v2/plugins/services" | 	"github.com/containerd/containerd/v2/plugins/services" | ||||||
| 	ptypes "github.com/containerd/containerd/v2/protobuf/types" | 	ptypes "github.com/containerd/containerd/v2/protobuf/types" | ||||||
|  | 	"github.com/containerd/errdefs" | ||||||
| 	"github.com/containerd/plugin" | 	"github.com/containerd/plugin" | ||||||
| 	"github.com/containerd/plugin/registry" | 	"github.com/containerd/plugin/registry" | ||||||
|  | 	"github.com/containerd/typeurl/v2" | ||||||
| 	"google.golang.org/grpc" | 	"google.golang.org/grpc" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| @@ -54,7 +58,7 @@ func init() { | |||||||
| } | } | ||||||
|  |  | ||||||
| type server struct { | type server struct { | ||||||
| 	local api.IntrospectionClient | 	local introspection.Service | ||||||
| 	api.UnimplementedIntrospectionServer | 	api.UnimplementedIntrospectionServer | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -65,14 +69,25 @@ func (s *server) Register(server *grpc.Server) error { | |||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
|  |  | ||||||
| func (s *server) Plugins(ctx context.Context, req *api.PluginsRequest) (*api.PluginsResponse, error) { | func (s *server) Plugins(ctx context.Context, req *api.PluginsRequest) (resp *api.PluginsResponse, err error) { | ||||||
| 	return s.local.Plugins(ctx, req) | 	resp, err = s.local.Plugins(ctx, req.Filters...) | ||||||
|  | 	return resp, errdefs.ToGRPC(err) | ||||||
| } | } | ||||||
|  |  | ||||||
| func (s *server) Server(ctx context.Context, empty *ptypes.Empty) (*api.ServerResponse, error) { | func (s *server) Server(ctx context.Context, _ *ptypes.Empty) (resp *api.ServerResponse, err error) { | ||||||
| 	return s.local.Server(ctx, empty) | 	resp, err = s.local.Server(ctx) | ||||||
|  | 	return resp, errdefs.ToGRPC(err) | ||||||
| } | } | ||||||
|  |  | ||||||
| func (s *server) PluginInfo(ctx context.Context, req *api.PluginInfoRequest) (*api.PluginInfoResponse, error) { | func (s *server) PluginInfo(ctx context.Context, req *api.PluginInfoRequest) (resp *api.PluginInfoResponse, err error) { | ||||||
| 	return s.local.PluginInfo(ctx, req) | 	var options any | ||||||
|  | 	if req.Options != nil { | ||||||
|  | 		options, err = typeurl.UnmarshalAny(req.Options) | ||||||
|  | 		if err != nil { | ||||||
|  | 			return resp, errdefs.ToGRPC(fmt.Errorf("failed to unmarshal plugin info Options: %w", err)) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	resp, err = s.local.PluginInfo(ctx, req.Type, req.ID, options) | ||||||
|  | 	return resp, errdefs.ToGRPC(err) | ||||||
| } | } | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Maksym Pavlenko
					Maksym Pavlenko