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" | ||||
| 	diffapi "github.com/containerd/containerd/v2/api/services/diff/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" | ||||
| 	namespacesapi "github.com/containerd/containerd/v2/api/services/namespaces/v1" | ||||
| 	sandboxsapi "github.com/containerd/containerd/v2/api/services/sandbox/v1" | ||||
| @@ -43,6 +42,8 @@ import ( | ||||
| 	"github.com/containerd/containerd/v2/core/events" | ||||
| 	eventsproxy "github.com/containerd/containerd/v2/core/events/proxy" | ||||
| 	"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" | ||||
| 	leasesproxy "github.com/containerd/containerd/v2/core/leases/proxy" | ||||
| 	"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/namespaces" | ||||
| 	"github.com/containerd/containerd/v2/plugins" | ||||
| 	"github.com/containerd/containerd/v2/plugins/services/introspection" | ||||
| 	"github.com/containerd/containerd/v2/protobuf" | ||||
| 	ptypes "github.com/containerd/containerd/v2/protobuf/types" | ||||
| 	"github.com/containerd/errdefs" | ||||
| @@ -680,7 +680,7 @@ func (c *Client) IntrospectionService() introspection.Service { | ||||
| 	} | ||||
| 	c.connMu.Lock() | ||||
| 	defer c.connMu.Unlock() | ||||
| 	return introspection.NewIntrospectionServiceFromClient(introspectionapi.NewIntrospectionClient(c.conn)) | ||||
| 	return introspectionproxy.NewIntrospectionProxy(c.conn) | ||||
| } | ||||
|  | ||||
| // LeasesService returns the underlying Leases Client | ||||
| @@ -785,7 +785,7 @@ func (c *Client) Server(ctx context.Context) (ServerInfo, error) { | ||||
| 	} | ||||
| 	c.connMu.Unlock() | ||||
|  | ||||
| 	response, err := c.IntrospectionService().Server(ctx, &ptypes.Empty{}) | ||||
| 	response, err := c.IntrospectionService().Server(ctx) | ||||
| 	if err != nil { | ||||
| 		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)} | ||||
| 	in := c.IntrospectionService() | ||||
|  | ||||
| 	resp, err := in.Plugins(ctx, filters) | ||||
| 	resp, err := in.Plugins(ctx, filters...) | ||||
| 	if err != nil { | ||||
| 		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)} | ||||
| 	in := c.IntrospectionService() | ||||
|  | ||||
| 	resp, err := in.Plugins(ctx, filters) | ||||
| 	resp, err := in.Plugins(ctx, filters...) | ||||
| 	if err != nil { | ||||
| 		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) | ||||
| 		} | ||||
| 	} | ||||
| 	options, err := protobuf.MarshalAnyToProto(rr) | ||||
| 	if err != nil { | ||||
| 		return nil, fmt.Errorf("failed to marshal runtime requst: %w", err) | ||||
| 	} | ||||
|  | ||||
| 	s := c.IntrospectionService() | ||||
|  | ||||
| 	req := &introspectionapi.PluginInfoRequest{ | ||||
| 		Type:    string(plugins.RuntimePluginV2), | ||||
| 		ID:      "task", | ||||
| 		Options: options, | ||||
| 	} | ||||
|  | ||||
| 	resp, err := s.PluginInfo(ctx, req) | ||||
| 	resp, err := s.PluginInfo(ctx, string(plugins.RuntimePluginV2), "task", rr) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|   | ||||
| @@ -112,8 +112,7 @@ func (c *Client) getInstallPath(ctx context.Context, config InstallConfig) (stri | ||||
| 	if config.Path != "" { | ||||
| 		return config.Path, nil | ||||
| 	} | ||||
| 	filters := []string{"id==opt"} | ||||
| 	resp, err := c.IntrospectionService().Plugins(ctx, filters) | ||||
| 	resp, err := c.IntrospectionService().Plugins(ctx, "id==opt") | ||||
| 	if err != nil { | ||||
| 		return "", err | ||||
| 	} | ||||
|   | ||||
| @@ -22,19 +22,18 @@ import ( | ||||
| 	containersapi "github.com/containerd/containerd/v2/api/services/containers/v1" | ||||
| 	"github.com/containerd/containerd/v2/api/services/diff/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" | ||||
| 	"github.com/containerd/containerd/v2/api/services/tasks/v1" | ||||
| 	"github.com/containerd/containerd/v2/core/containers" | ||||
| 	"github.com/containerd/containerd/v2/core/content" | ||||
| 	"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/sandbox" | ||||
| 	"github.com/containerd/containerd/v2/core/snapshots" | ||||
| 	"github.com/containerd/containerd/v2/pkg/namespaces" | ||||
| 	"github.com/containerd/containerd/v2/plugins" | ||||
| 	srv "github.com/containerd/containerd/v2/plugins/services" | ||||
| 	"github.com/containerd/containerd/v2/plugins/services/introspection" | ||||
| 	"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. | ||||
| func WithIntrospectionService(in introspection.Service) ServicesOpt { | ||||
| 	return func(s *services) { | ||||
| @@ -221,7 +213,7 @@ func WithInMemoryServices(ic *plugin.InitContext) Opt { | ||||
| 				return WithNamespaceClient(s.(namespacesapi.NamespacesClient)) | ||||
| 			}, | ||||
| 			srv.IntrospectionService: func(s interface{}) ServicesOpt { | ||||
| 				return WithIntrospectionClient(s.(introspectionapi.IntrospectionClient)) | ||||
| 				return WithIntrospectionService(s.(introspection.Service)) | ||||
| 			}, | ||||
| 		} { | ||||
| 			i := plugins[s] | ||||
|   | ||||
| @@ -24,7 +24,6 @@ import ( | ||||
| 	containerd "github.com/containerd/containerd/v2/client" | ||||
| 	"github.com/containerd/containerd/v2/pkg/epoch" | ||||
| 	"github.com/containerd/containerd/v2/pkg/namespaces" | ||||
| 	ptypes "github.com/containerd/containerd/v2/protobuf/types" | ||||
| 	"github.com/containerd/log" | ||||
| 	"github.com/urfave/cli/v2" | ||||
| ) | ||||
| @@ -73,7 +72,7 @@ func NewClient(context *cli.Context, opts ...containerd.Opt) (*containerd.Client | ||||
| 		} | ||||
| 	} | ||||
| 	if !suppressDeprecationWarnings { | ||||
| 		resp, err := client.IntrospectionService().Server(ctx, &ptypes.Empty{}) | ||||
| 		resp, err := client.IntrospectionService().Server(ctx) | ||||
| 		if err != nil { | ||||
| 			log.L.WithError(err).Warn("Failed to check deprecations") | ||||
| 		} else { | ||||
|   | ||||
| @@ -27,7 +27,6 @@ import ( | ||||
| 	api "github.com/containerd/containerd/v2/api/services/introspection/v1" | ||||
| 	"github.com/containerd/containerd/v2/cmd/ctr/commands" | ||||
| 	"github.com/containerd/containerd/v2/protobuf" | ||||
| 	ptypes "github.com/containerd/containerd/v2/protobuf/types" | ||||
| ) | ||||
|  | ||||
| // Command is the parent for all commands under "deprecations" | ||||
| @@ -56,7 +55,7 @@ var listCommand = &cli.Command{ | ||||
| 		} | ||||
| 		defer cancel() | ||||
|  | ||||
| 		resp, err := client.IntrospectionService().Server(ctx, &ptypes.Empty{}) | ||||
| 		resp, err := client.IntrospectionService().Server(ctx) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
|   | ||||
| @@ -19,7 +19,6 @@ package info | ||||
| import ( | ||||
| 	api "github.com/containerd/containerd/v2/api/services/introspection/v1" | ||||
| 	"github.com/containerd/containerd/v2/cmd/ctr/commands" | ||||
| 	ptypes "github.com/containerd/containerd/v2/protobuf/types" | ||||
| 	"github.com/urfave/cli/v2" | ||||
| ) | ||||
|  | ||||
| @@ -38,7 +37,7 @@ var Command = &cli.Command{ | ||||
| 		} | ||||
| 		defer cancel() | ||||
| 		var info Info | ||||
| 		info.Server, err = client.IntrospectionService().Server(ctx, &ptypes.Empty{}) | ||||
| 		info.Server, err = client.IntrospectionService().Server(ctx) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
|   | ||||
| @@ -71,7 +71,7 @@ var listCommand = &cli.Command{ | ||||
| 		} | ||||
| 		defer cancel() | ||||
| 		ps := client.IntrospectionService() | ||||
| 		response, err := ps.Plugins(ctx, context.Args().Slice()) | ||||
| 		response, err := ps.Plugins(ctx, context.Args().Slice()...) | ||||
| 		if err != nil { | ||||
| 			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" | ||||
| 	"k8s.io/kubelet/pkg/cri/streaming" | ||||
|  | ||||
| 	introspectionapi "github.com/containerd/containerd/v2/api/services/introspection/v1" | ||||
| 	apitypes "github.com/containerd/containerd/v2/api/types" | ||||
| 	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/sandbox" | ||||
| 	"github.com/containerd/containerd/v2/internal/cri/config" | ||||
| @@ -54,7 +54,6 @@ import ( | ||||
| 	"github.com/containerd/containerd/v2/pkg/oci" | ||||
| 	osinterface "github.com/containerd/containerd/v2/pkg/os" | ||||
| 	"github.com/containerd/containerd/v2/plugins" | ||||
| 	"github.com/containerd/containerd/v2/plugins/services/introspection" | ||||
| 	"github.com/containerd/containerd/v2/protobuf" | ||||
| ) | ||||
|  | ||||
| @@ -407,10 +406,7 @@ func introspectRuntimeFeatures(ctx context.Context, intro introspection.Service, | ||||
| 			plugins.RuntimeRuncV2, r.Type) | ||||
| 		// 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{ | ||||
| 		RuntimePath: r.Type, // "io.containerd.runc.v2" | ||||
| 	} | ||||
| @@ -425,11 +421,8 @@ func introspectRuntimeFeatures(ctx context.Context, intro introspection.Service, | ||||
| 	if err != nil { | ||||
| 		return nil, fmt.Errorf("failed to marshal %T: %w", options, err) | ||||
| 	} | ||||
| 	infoReq.Options, err = protobuf.MarshalAnyToProto(rr) | ||||
| 	if err != nil { | ||||
| 		return nil, fmt.Errorf("failed to marshal %T: %w", rr, err) | ||||
| 	} | ||||
| 	infoResp, err := intro.PluginInfo(ctx, infoReq) | ||||
|  | ||||
| 	infoResp, err := intro.PluginInfo(ctx, string(plugins.RuntimePluginV2), "task", rr) | ||||
| 	if err != nil { | ||||
| 		return nil, fmt.Errorf("failed to call PluginInfo: %w", err) | ||||
| 	} | ||||
|   | ||||
| @@ -23,7 +23,6 @@ import ( | ||||
| 	goruntime "runtime" | ||||
|  | ||||
| 	"github.com/containerd/containerd/v2/api/services/introspection/v1" | ||||
| 	ptypes "github.com/containerd/containerd/v2/protobuf/types" | ||||
| 	"github.com/containerd/log" | ||||
| 	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 | ||||
| 	} | ||||
| 	intro, err := c.client.IntrospectionService().Server(ctx, &ptypes.Empty{}) | ||||
| 	intro, err := c.client.IntrospectionService().Server(ctx) | ||||
| 	if err != nil { | ||||
| 		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" | ||||
| 	"google.golang.org/genproto/googleapis/rpc/code" | ||||
| 	rpc "google.golang.org/genproto/googleapis/rpc/status" | ||||
| 	"google.golang.org/grpc" | ||||
| 	"google.golang.org/grpc/status" | ||||
|  | ||||
| 	api "github.com/containerd/containerd/v2/api/services/introspection/v1" | ||||
| 	"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/plugins" | ||||
| 	"github.com/containerd/containerd/v2/plugins/services" | ||||
| @@ -80,7 +80,7 @@ type Local struct { | ||||
| 	warningClient warning.Service | ||||
| } | ||||
|  | ||||
| var _ = (api.IntrospectionClient)(&Local{}) | ||||
| var _ = (introspection.Service)(&Local{}) | ||||
|  | ||||
| // UpdateLocal updates the local introspection service | ||||
| func (l *Local) UpdateLocal(root string) { | ||||
| @@ -90,10 +90,10 @@ func (l *Local) UpdateLocal(root string) { | ||||
| } | ||||
|  | ||||
| // Plugins returns the locally defined plugins | ||||
| func (l *Local) Plugins(ctx context.Context, req *api.PluginsRequest, _ ...grpc.CallOption) (*api.PluginsResponse, error) { | ||||
| 	filter, err := filters.ParseAll(req.Filters...) | ||||
| func (l *Local) Plugins(ctx context.Context, fs ...string) (*api.PluginsResponse, error) { | ||||
| 	filter, err := filters.ParseAll(fs...) | ||||
| 	if err != nil { | ||||
| 		return nil, errdefs.ToGRPCf(errdefs.ErrInvalidArgument, err.Error()) | ||||
| 		return nil, fmt.Errorf("%w: %w", errdefs.ErrInvalidArgument, err) | ||||
| 	} | ||||
|  | ||||
| 	var plugins []*api.Plugin | ||||
| @@ -121,17 +121,17 @@ func (l *Local) getPlugins() []*api.Plugin { | ||||
| } | ||||
|  | ||||
| // 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() | ||||
| 	if err != nil { | ||||
| 		return nil, errdefs.ToGRPC(err) | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	pid := os.Getpid() | ||||
| 	var pidns uint64 | ||||
| 	if runtime.GOOS == "linux" { | ||||
| 		pidns, err = statPIDNS(pid) | ||||
| 		if err != nil { | ||||
| 			return nil, errdefs.ToGRPC(err) | ||||
| 			return nil, err | ||||
| 		} | ||||
| 	} | ||||
| 	return &api.ServerResponse{ | ||||
| @@ -278,11 +278,10 @@ type pluginInfoProvider interface { | ||||
| 	PluginInfo(context.Context, interface{}) (interface{}, error) | ||||
| } | ||||
|  | ||||
| func (l *Local) PluginInfo(ctx context.Context, req *api.PluginInfoRequest, _ ...grpc.CallOption) (*api.PluginInfoResponse, error) { | ||||
| 	p := l.plugins.Get(plugin.Type(req.Type), req.ID) | ||||
| func (l *Local) PluginInfo(ctx context.Context, pluginType, id string, options any) (*api.PluginInfoResponse, error) { | ||||
| 	p := l.plugins.Get(plugin.Type(pluginType), id) | ||||
| 	if p == nil { | ||||
| 		err := fmt.Errorf("plugin %s.%s not found: %w", req.Type, req.ID, errdefs.ErrNotFound) | ||||
| 		return nil, errdefs.ToGRPC(err) | ||||
| 		return nil, fmt.Errorf("plugin %s.%s not found: %w", pluginType, id, errdefs.ErrNotFound) | ||||
| 	} | ||||
|  | ||||
| 	resp := &api.PluginInfoResponse{ | ||||
| @@ -290,35 +289,26 @@ func (l *Local) PluginInfo(ctx context.Context, req *api.PluginInfoRequest, _ .. | ||||
| 	} | ||||
|  | ||||
| 	// Request additional info from plugin instance | ||||
| 	if req.Options != nil { | ||||
| 	if options != nil { | ||||
| 		if p.Err() != nil { | ||||
| 			err := fmt.Errorf("cannot get extra info, plugin not successfully loaded: %w", errdefs.ErrFailedPrecondition) | ||||
| 			return resp, errdefs.ToGRPC(err) | ||||
| 			return resp, fmt.Errorf("cannot get extra info, plugin not successfully loaded: %w", errdefs.ErrFailedPrecondition) | ||||
| 		} | ||||
| 		inst, err := p.Instance() | ||||
| 		if err != nil { | ||||
| 			err := fmt.Errorf("failed to get plugin instance: %w", errdefs.ErrFailedPrecondition) | ||||
| 			return resp, errdefs.ToGRPC(err) | ||||
| 			return resp, fmt.Errorf("failed to get plugin instance: %w", errdefs.ErrFailedPrecondition) | ||||
| 		} | ||||
| 		pi, ok := inst.(pluginInfoProvider) | ||||
| 		if !ok { | ||||
| 			err := fmt.Errorf("plugin does not provided extra information: %w", errdefs.ErrNotImplemented) | ||||
| 			return resp, errdefs.ToGRPC(err) | ||||
| 			return resp, fmt.Errorf("plugin does not provided extra information: %w", errdefs.ErrNotImplemented) | ||||
| 		} | ||||
|  | ||||
| 		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) | ||||
| 		if err != nil { | ||||
| 			return resp, errdefs.ToGRPC(err) | ||||
| 		} | ||||
| 		ai, err := typeurl.MarshalAny(info) | ||||
| 		if err != nil { | ||||
| 			err = fmt.Errorf("failed to marshal plugin info: %w", err) | ||||
| 			return resp, errdefs.ToGRPC(err) | ||||
| 			return resp, fmt.Errorf("failed to marshal plugin info: %w", err) | ||||
| 		} | ||||
| 		resp.Extra = &ptypes.Any{ | ||||
| 			TypeUrl: ai.GetTypeUrl(), | ||||
|   | ||||
| @@ -19,13 +19,17 @@ package introspection | ||||
| import ( | ||||
| 	context "context" | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
|  | ||||
| 	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/services" | ||||
| 	ptypes "github.com/containerd/containerd/v2/protobuf/types" | ||||
| 	"github.com/containerd/errdefs" | ||||
| 	"github.com/containerd/plugin" | ||||
| 	"github.com/containerd/plugin/registry" | ||||
| 	"github.com/containerd/typeurl/v2" | ||||
| 	"google.golang.org/grpc" | ||||
| ) | ||||
|  | ||||
| @@ -54,7 +58,7 @@ func init() { | ||||
| } | ||||
|  | ||||
| type server struct { | ||||
| 	local api.IntrospectionClient | ||||
| 	local introspection.Service | ||||
| 	api.UnimplementedIntrospectionServer | ||||
| } | ||||
|  | ||||
| @@ -65,14 +69,25 @@ func (s *server) Register(server *grpc.Server) error { | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (s *server) Plugins(ctx context.Context, req *api.PluginsRequest) (*api.PluginsResponse, error) { | ||||
| 	return s.local.Plugins(ctx, req) | ||||
| func (s *server) Plugins(ctx context.Context, req *api.PluginsRequest) (resp *api.PluginsResponse, err error) { | ||||
| 	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) { | ||||
| 	return s.local.Server(ctx, empty) | ||||
| func (s *server) Server(ctx context.Context, _ *ptypes.Empty) (resp *api.ServerResponse, err error) { | ||||
| 	resp, err = s.local.Server(ctx) | ||||
| 	return resp, errdefs.ToGRPC(err) | ||||
| } | ||||
|  | ||||
| func (s *server) PluginInfo(ctx context.Context, req *api.PluginInfoRequest) (*api.PluginInfoResponse, error) { | ||||
| 	return s.local.PluginInfo(ctx, req) | ||||
| func (s *server) PluginInfo(ctx context.Context, req *api.PluginInfoRequest) (resp *api.PluginInfoResponse, err error) { | ||||
| 	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