Merge pull request #9911 from dmcgowan/introspection-split

Cleanup introspection interface
This commit is contained in:
Maksym Pavlenko 2024-03-05 03:20:45 +00:00 committed by GitHub
commit 7d2bc0620b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
14 changed files with 195 additions and 159 deletions

View File

@ -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
} }

View File

@ -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
} }

View File

@ -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]

View File

@ -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 {

View File

@ -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
} }

View File

@ -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
} }

View File

@ -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
} }

View 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)
}

View 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)
}

View File

@ -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)
} }

View File

@ -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
} }

View File

@ -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
}

View File

@ -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(),

View File

@ -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)
} }