Cleanup introspection interface
Split service proxy from service plugin. Make introspection service easier for clients to use. Update service proxy to support grpc and ttrpc. Signed-off-by: Derek McGowan <derek@mcg.dev>
This commit is contained in:
parent
9a2b85561a
commit
1bf781d8eb
@ -31,7 +31,6 @@ import (
|
|||||||
diffapi "github.com/containerd/containerd/v2/api/services/diff/v1"
|
diffapi "github.com/containerd/containerd/v2/api/services/diff/v1"
|
||||||
eventsapi "github.com/containerd/containerd/v2/api/services/events/v1"
|
eventsapi "github.com/containerd/containerd/v2/api/services/events/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"
|
||||||
@ -44,6 +43,8 @@ import (
|
|||||||
contentproxy "github.com/containerd/containerd/v2/core/content/proxy"
|
contentproxy "github.com/containerd/containerd/v2/core/content/proxy"
|
||||||
"github.com/containerd/containerd/v2/core/events"
|
"github.com/containerd/containerd/v2/core/events"
|
||||||
"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"
|
||||||
@ -56,7 +57,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"
|
||||||
@ -681,7 +681,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)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user