Use typeurl.Any instead of github.com/gogo/protobuf/types.Any

This commit upgrades github.com/containerd/typeurl to use typeurl.Any.
The interface hides gogo/protobuf/types.Any from containerd's Go client.

Signed-off-by: Kazuyoshi Kato <katokazu@amazon.com>
This commit is contained in:
Kazuyoshi Kato 2022-03-22 00:40:39 +00:00
parent 551516a18d
commit 96b16b447d
42 changed files with 336 additions and 152 deletions

View File

@ -38,13 +38,13 @@ import (
"github.com/containerd/containerd/events"
"github.com/containerd/containerd/namespaces"
"github.com/containerd/containerd/pkg/process"
"github.com/containerd/containerd/protobuf"
shimlog "github.com/containerd/containerd/runtime/v1"
"github.com/containerd/containerd/runtime/v1/shim"
shimapi "github.com/containerd/containerd/runtime/v1/shim/v1"
"github.com/containerd/containerd/sys/reaper"
"github.com/containerd/containerd/version"
"github.com/containerd/ttrpc"
"github.com/containerd/typeurl"
ptypes "github.com/gogo/protobuf/types"
"github.com/sirupsen/logrus"
exec "golang.org/x/sys/execabs"
@ -301,7 +301,7 @@ type remoteEventsPublisher struct {
func (l *remoteEventsPublisher) Publish(ctx context.Context, topic string, event events.Event) error {
ns, _ := namespaces.Namespace(ctx)
encoded, err := typeurl.MarshalAny(event)
encoded, err := protobuf.MarshalAnyToProto(event)
if err != nil {
return err
}

View File

@ -280,7 +280,7 @@ var infoCommand = cli.Command{
return nil
}
if info.Spec != nil && info.Spec.Value != nil {
if info.Spec != nil && info.Spec.GetValue() != nil {
v, err := typeurl.UnmarshalAny(info.Spec)
if err != nil {
return err

View File

@ -42,7 +42,7 @@ func RemoveCniNetworkIfExist(ctx context.Context, container containerd.Container
return nil
}
data, err := typeurl.UnmarshalAny(&networkMeta)
data, err := typeurl.UnmarshalAny(networkMeta)
if err != nil {
return fmt.Errorf("failed to unmarshal cni metadata extension %s", commands.CtrCniMetadataExtension)
}

View File

@ -32,10 +32,10 @@ import (
"github.com/containerd/containerd/errdefs"
"github.com/containerd/containerd/images"
"github.com/containerd/containerd/oci"
"github.com/containerd/containerd/protobuf"
"github.com/containerd/containerd/runtime/v2/runc/options"
"github.com/containerd/fifo"
"github.com/containerd/typeurl"
prototypes "github.com/gogo/protobuf/types"
ver "github.com/opencontainers/image-spec/specs-go"
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/opencontainers/selinux/go-selinux/label"
@ -74,7 +74,7 @@ type Container interface {
// SetLabels sets the provided labels for the container and returns the final label set
SetLabels(context.Context, map[string]string) (map[string]string, error)
// Extensions returns the extensions set on the container
Extensions(context.Context) (map[string]prototypes.Any, error)
Extensions(context.Context) (map[string]typeurl.Any, error)
// Update a container
Update(context.Context, ...UpdateContainerOpts) error
// Checkpoint creates a checkpoint image of the current container
@ -120,7 +120,7 @@ func (c *container) Info(ctx context.Context, opts ...InfoOpts) (containers.Cont
return c.metadata, nil
}
func (c *container) Extensions(ctx context.Context) (map[string]prototypes.Any, error) {
func (c *container) Extensions(ctx context.Context) (map[string]typeurl.Any, error) {
r, err := c.get(ctx)
if err != nil {
return nil, err
@ -163,7 +163,7 @@ func (c *container) Spec(ctx context.Context) (*oci.Spec, error) {
return nil, err
}
var s oci.Spec
if err := json.Unmarshal(r.Spec.Value, &s); err != nil {
if err := json.Unmarshal(r.Spec.GetValue(), &s); err != nil {
return nil, err
}
return &s, nil
@ -284,7 +284,7 @@ func (c *container) NewTask(ctx context.Context, ioCreate cio.Creator, opts ...N
if err != nil {
return nil, err
}
request.Options = any
request.Options = protobuf.FromAny(any)
}
t := &task{
client: c.client,

View File

@ -28,9 +28,9 @@ import (
"github.com/containerd/containerd/diff"
"github.com/containerd/containerd/images"
"github.com/containerd/containerd/platforms"
"github.com/containerd/containerd/protobuf"
"github.com/containerd/containerd/rootfs"
"github.com/containerd/containerd/runtime/v2/runc/options"
"github.com/containerd/typeurl"
"github.com/opencontainers/go-digest"
imagespec "github.com/opencontainers/image-spec/specs-go/v1"
)
@ -57,7 +57,7 @@ func WithCheckpointImage(ctx context.Context, client *Client, c *containers.Cont
// WithCheckpointTask includes the running task
func WithCheckpointTask(ctx context.Context, client *Client, c *containers.Container, index *imagespec.Index, copts *options.CheckpointOptions) error {
any, err := typeurl.MarshalAny(copts)
any, err := protobuf.MarshalAnyToProto(copts)
if err != nil {
return nil
}
@ -98,8 +98,8 @@ func WithCheckpointTask(ctx context.Context, client *Client, c *containers.Conta
// WithCheckpointRuntime includes the container runtime info
func WithCheckpointRuntime(ctx context.Context, client *Client, c *containers.Container, index *imagespec.Index, copts *options.CheckpointOptions) error {
if c.Runtime.Options != nil {
data, err := c.Runtime.Options.Marshal()
if c.Runtime.Options != nil && c.Runtime.Options.GetValue() != nil {
data, err := protobuf.FromAny(c.Runtime.Options).Marshal()
if err != nil {
return err
}

View File

@ -27,9 +27,9 @@ import (
"github.com/containerd/containerd/errdefs"
"github.com/containerd/containerd/images"
"github.com/containerd/containerd/oci"
"github.com/containerd/containerd/protobuf"
"github.com/containerd/containerd/snapshots"
"github.com/containerd/typeurl"
"github.com/gogo/protobuf/types"
"github.com/opencontainers/image-spec/identity"
v1 "github.com/opencontainers/image-spec/specs-go/v1"
)
@ -57,7 +57,7 @@ type InfoConfig struct {
func WithRuntime(name string, options interface{}) NewContainerOpts {
return func(ctx context.Context, client *Client, c *containers.Container) error {
var (
any *types.Any
any typeurl.Any
err error
)
if options != nil {
@ -288,9 +288,9 @@ func WithContainerExtension(name string, extension interface{}) NewContainerOpts
}
if c.Extensions == nil {
c.Extensions = make(map[string]types.Any)
c.Extensions = make(map[string]typeurl.Any)
}
c.Extensions[name] = *any
c.Extensions[name] = any
return nil
}
}
@ -315,7 +315,7 @@ func WithSpec(s *oci.Spec, opts ...oci.SpecOpts) NewContainerOpts {
}
var err error
c.Spec, err = typeurl.MarshalAny(s)
c.Spec, err = protobuf.MarshalAnyToProto(s)
return err
}
}

View File

@ -20,7 +20,7 @@ import (
"context"
"time"
"github.com/gogo/protobuf/types"
"github.com/containerd/typeurl"
)
// Container represents the set of data pinned by a container. Unless otherwise
@ -53,7 +53,7 @@ type Container struct {
// container.
//
// This field is required but mutable.
Spec *types.Any
Spec typeurl.Any
// SnapshotKey specifies the snapshot key to use for the container's root
// filesystem. When starting a task from this container, a caller should
@ -75,13 +75,13 @@ type Container struct {
UpdatedAt time.Time
// Extensions stores client-specified metadata
Extensions map[string]types.Any
Extensions map[string]typeurl.Any
}
// RuntimeInfo holds runtime specific information
type RuntimeInfo struct {
Name string
Options *types.Any
Options typeurl.Any
}
// Store interacts with the underlying container storage

View File

@ -24,6 +24,8 @@ import (
containersapi "github.com/containerd/containerd/api/services/containers/v1"
"github.com/containerd/containerd/containers"
"github.com/containerd/containerd/errdefs"
"github.com/containerd/containerd/protobuf"
"github.com/containerd/typeurl"
ptypes "github.com/gogo/protobuf/types"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
@ -148,18 +150,22 @@ func (r *remoteContainers) Delete(ctx context.Context, id string) error {
}
func containerToProto(container *containers.Container) containersapi.Container {
extensions := make(map[string]ptypes.Any)
for k, v := range container.Extensions {
extensions[k] = *protobuf.FromAny(v)
}
return containersapi.Container{
ID: container.ID,
Labels: container.Labels,
Image: container.Image,
Runtime: &containersapi.Container_Runtime{
Name: container.Runtime.Name,
Options: container.Runtime.Options,
Options: protobuf.FromAny(container.Runtime.Options),
},
Spec: container.Spec,
Spec: protobuf.FromAny(container.Spec),
Snapshotter: container.Snapshotter,
SnapshotKey: container.SnapshotKey,
Extensions: container.Extensions,
Extensions: extensions,
}
}
@ -171,6 +177,11 @@ func containerFromProto(containerpb *containersapi.Container) containers.Contain
Options: containerpb.Runtime.Options,
}
}
extensions := make(map[string]typeurl.Any)
for k, v := range containerpb.Extensions {
v := v
extensions[k] = &v
}
return containers.Container{
ID: containerpb.ID,
Labels: containerpb.Labels,
@ -181,7 +192,7 @@ func containerFromProto(containerpb *containersapi.Container) containers.Contain
SnapshotKey: containerpb.SnapshotKey,
CreatedAt: containerpb.CreatedAt,
UpdatedAt: containerpb.UpdatedAt,
Extensions: containerpb.Extensions,
Extensions: extensions,
}
}

View File

@ -22,6 +22,7 @@ import (
eventsapi "github.com/containerd/containerd/api/services/events/v1"
"github.com/containerd/containerd/errdefs"
"github.com/containerd/containerd/events"
"github.com/containerd/containerd/protobuf"
"github.com/containerd/typeurl"
)
@ -51,7 +52,7 @@ func (e *eventRemote) Publish(ctx context.Context, topic string, event events.Ev
}
req := &eventsapi.PublishRequest{
Topic: topic,
Event: any,
Event: protobuf.FromAny(any),
}
if _, err := e.client.Publish(ctx, req); err != nil {
return errdefs.FromGRPC(err)
@ -65,7 +66,7 @@ func (e *eventRemote) Forward(ctx context.Context, envelope *events.Envelope) er
Timestamp: envelope.Timestamp,
Namespace: envelope.Namespace,
Topic: envelope.Topic,
Event: envelope.Event,
Event: protobuf.FromAny(envelope.Event),
},
}
if _, err := e.client.Forward(ctx, req); err != nil {

View File

@ -21,7 +21,6 @@ import (
"time"
"github.com/containerd/typeurl"
"github.com/gogo/protobuf/types"
)
// Envelope provides the packaging for an event.
@ -29,7 +28,7 @@ type Envelope struct {
Timestamp time.Time
Namespace string
Topic string
Event *types.Any
Event typeurl.Any
}
// Field returns the value for the given fieldpath as a string, if defined.

View File

@ -30,7 +30,6 @@ import (
"github.com/containerd/containerd/namespaces"
"github.com/containerd/typeurl"
goevents "github.com/docker/go-events"
"github.com/gogo/protobuf/types"
"github.com/sirupsen/logrus"
)
@ -63,7 +62,7 @@ func (e *Exchange) Forward(ctx context.Context, envelope *events.Envelope) (err
logger := log.G(ctx).WithFields(logrus.Fields{
"topic": envelope.Topic,
"ns": envelope.Namespace,
"type": envelope.Event.TypeUrl,
"type": envelope.Event.GetTypeUrl(),
})
if err != nil {
@ -82,7 +81,6 @@ func (e *Exchange) Forward(ctx context.Context, envelope *events.Envelope) (err
func (e *Exchange) Publish(ctx context.Context, topic string, event events.Event) (err error) {
var (
namespace string
encoded *types.Any
envelope events.Envelope
)
@ -94,7 +92,7 @@ func (e *Exchange) Publish(ctx context.Context, topic string, event events.Event
return fmt.Errorf("envelope topic %q: %w", topic, err)
}
encoded, err = typeurl.MarshalAny(event)
encoded, err := typeurl.MarshalAny(event)
if err != nil {
return err
}
@ -108,7 +106,7 @@ func (e *Exchange) Publish(ctx context.Context, topic string, event events.Event
logger := log.G(ctx).WithFields(logrus.Fields{
"topic": envelope.Topic,
"ns": envelope.Namespace,
"type": envelope.Event.TypeUrl,
"type": envelope.Event.GetTypeUrl(),
})
if err != nil {

2
go.mod
View File

@ -17,7 +17,7 @@ require (
github.com/containerd/imgcrypt v1.1.4-0.20220322210345-7eff50ecc4f6
github.com/containerd/nri v0.1.0
github.com/containerd/ttrpc v1.1.0
github.com/containerd/typeurl v1.0.2
github.com/containerd/typeurl v1.0.3-0.20220324183432-6193a0e03259
github.com/containerd/zfs v1.0.0
github.com/containernetworking/plugins v1.0.1
github.com/coreos/go-systemd/v22 v22.3.2

3
go.sum
View File

@ -253,8 +253,9 @@ github.com/containerd/ttrpc v1.1.0/go.mod h1:XX4ZTnoOId4HklF4edwc4DcqskFZuvXB1Ev
github.com/containerd/typeurl v0.0.0-20180627222232-a93fcdb778cd/go.mod h1:Cm3kwCdlkCfMSHURc+r6fwoGH6/F1hH3S4sg0rLFWPc=
github.com/containerd/typeurl v0.0.0-20190911142611-5eb25027c9fd/go.mod h1:GeKYzf2pQcqv7tJ0AoCuuhtnqhva5LNU3U+OyKxxJpk=
github.com/containerd/typeurl v1.0.1/go.mod h1:TB1hUtrpaiO88KEK56ijojHS1+NeF0izUACaJW2mdXg=
github.com/containerd/typeurl v1.0.2 h1:Chlt8zIieDbzQFzXzAeBEF92KhExuE4p9p92/QmY7aY=
github.com/containerd/typeurl v1.0.2/go.mod h1:9trJWW2sRlGub4wZJRTW83VtbOLS6hwcDZXTn6oPz9s=
github.com/containerd/typeurl v1.0.3-0.20220324183432-6193a0e03259 h1:bJv9qgjarrsdd4XIIczeRdYXON88Fgn3GdXVfnQjcSo=
github.com/containerd/typeurl v1.0.3-0.20220324183432-6193a0e03259/go.mod h1:HDkcKOXRnX6yKnXv3P0QrogFi0DoiauK/LpQi961f0A=
github.com/containerd/zfs v0.0.0-20200918131355-0a33824f23a2/go.mod h1:8IgZOBdv8fAgXddBT4dBXJPtxyRsejFIpXoklgxgEjw=
github.com/containerd/zfs v0.0.0-20210301145711-11e8f1707f62/go.mod h1:A9zfAbMlQwE+/is6hi0Xw8ktpL+6glmqZYtevJgaB8Y=
github.com/containerd/zfs v0.0.0-20210315114300-dde8f0fda960/go.mod h1:m+m51S1DvAP6r3FcmYCp54bQ34pyOwTieQDNRIRHsFY=

View File

@ -1440,11 +1440,11 @@ func TestContainerExtensions(t *testing.T) {
if len(cExts) != 1 {
t.Errorf("expected 1 container extension")
}
if cExts["hello"].TypeUrl != ext.TypeUrl {
t.Errorf("got unexpected type url for extension: %s", cExts["hello"].TypeUrl)
if actual := cExts["hello"].GetTypeUrl(); actual != ext.TypeUrl {
t.Errorf("got unexpected type url for extension: %s", actual)
}
if !bytes.Equal(cExts["hello"].Value, ext.Value) {
t.Errorf("expected extension value %q, got: %q", ext.Value, cExts["hello"].Value)
if actual := cExts["hello"].GetValue(); !bytes.Equal(actual, ext.Value) {
t.Errorf("expected extension value %q, got: %q", ext.Value, actual)
}
}

View File

@ -10,7 +10,7 @@ require (
github.com/containerd/containerd v1.5.10
github.com/containerd/go-runc v1.0.0
github.com/containerd/ttrpc v1.1.0
github.com/containerd/typeurl v1.0.2
github.com/containerd/typeurl v1.0.3-0.20220324183432-6193a0e03259
github.com/gogo/protobuf v1.3.2
github.com/opencontainers/go-digest v1.0.0
github.com/opencontainers/image-spec v1.0.3-0.20220303224323-02efb9a75ee1

View File

@ -152,8 +152,9 @@ github.com/containerd/ttrpc v1.0.2/go.mod h1:UAxOpgT9ziI0gJrmKvgcZivgxOp8iFPSk8h
github.com/containerd/ttrpc v1.1.0 h1:GbtyLRxb0gOLR0TYQWt3O6B0NvT8tMdorEHqIQo/lWI=
github.com/containerd/ttrpc v1.1.0/go.mod h1:XX4ZTnoOId4HklF4edwc4DcqskFZuvXB1Evzy5KFQpQ=
github.com/containerd/typeurl v1.0.1/go.mod h1:TB1hUtrpaiO88KEK56ijojHS1+NeF0izUACaJW2mdXg=
github.com/containerd/typeurl v1.0.2 h1:Chlt8zIieDbzQFzXzAeBEF92KhExuE4p9p92/QmY7aY=
github.com/containerd/typeurl v1.0.2/go.mod h1:9trJWW2sRlGub4wZJRTW83VtbOLS6hwcDZXTn6oPz9s=
github.com/containerd/typeurl v1.0.3-0.20220324183432-6193a0e03259 h1:bJv9qgjarrsdd4XIIczeRdYXON88Fgn3GdXVfnQjcSo=
github.com/containerd/typeurl v1.0.3-0.20220324183432-6193a0e03259/go.mod h1:HDkcKOXRnX6yKnXv3P0QrogFi0DoiauK/LpQi961f0A=
github.com/containerd/zfs v1.0.0/go.mod h1:m+m51S1DvAP6r3FcmYCp54bQ34pyOwTieQDNRIRHsFY=
github.com/containernetworking/cni v1.0.1/go.mod h1:AKuhXbN5EzmD4yTNtfSsX3tPcmtrBI6QcRV0NiNt15Y=
github.com/containernetworking/plugins v1.0.1/go.mod h1:QHCfGpaTwYTbbH+nZXKVTxNBDZcxSOplJT5ico8/FLE=

View File

@ -20,6 +20,8 @@ import (
"fmt"
"time"
"github.com/containerd/containerd/protobuf"
"github.com/containerd/typeurl"
"github.com/gogo/protobuf/proto"
"github.com/gogo/protobuf/types"
bolt "go.etcd.io/bbolt"
@ -151,7 +153,7 @@ func WriteTimestamps(bkt *bolt.Bucket, created, updated time.Time) error {
// WriteExtensions will write a KV map to the given bucket,
// where `K` is a string key and `V` is a protobuf's Any type that represents a generic extension.
func WriteExtensions(bkt *bolt.Bucket, extensions map[string]types.Any) error {
func WriteExtensions(bkt *bolt.Bucket, extensions map[string]typeurl.Any) error {
if len(extensions) == 0 {
return nil
}
@ -162,8 +164,8 @@ func WriteExtensions(bkt *bolt.Bucket, extensions map[string]types.Any) error {
}
for name, ext := range extensions {
ext := ext
p, err := proto.Marshal(&ext)
ext := protobuf.FromAny(ext)
p, err := proto.Marshal(ext)
if err != nil {
return err
}
@ -177,9 +179,9 @@ func WriteExtensions(bkt *bolt.Bucket, extensions map[string]types.Any) error {
}
// ReadExtensions will read back a map of extensions from the given bucket, previously written by WriteExtensions
func ReadExtensions(bkt *bolt.Bucket) (map[string]types.Any, error) {
func ReadExtensions(bkt *bolt.Bucket) (map[string]typeurl.Any, error) {
var (
extensions = make(map[string]types.Any)
extensions = make(map[string]typeurl.Any)
ebkt = bkt.Bucket(bucketKeyExtensions)
)
@ -193,7 +195,7 @@ func ReadExtensions(bkt *bolt.Bucket) (map[string]types.Any, error) {
return err
}
extensions[string(k)] = t
extensions[string(k)] = &t
return nil
}); err != nil {
return nil, err
@ -203,12 +205,13 @@ func ReadExtensions(bkt *bolt.Bucket) (map[string]types.Any, error) {
}
// WriteAny write a protobuf's Any type to the bucket
func WriteAny(bkt *bolt.Bucket, name []byte, any *types.Any) error {
if any == nil {
func WriteAny(bkt *bolt.Bucket, name []byte, any typeurl.Any) error {
pbany := protobuf.FromAny(any)
if pbany == nil {
return nil
}
data, err := proto.Marshal(any)
data, err := proto.Marshal(pbany)
if err != nil {
return err
}

View File

@ -30,6 +30,7 @@ import (
"github.com/containerd/containerd/labels"
"github.com/containerd/containerd/metadata/boltutil"
"github.com/containerd/containerd/namespaces"
"github.com/containerd/typeurl"
"github.com/gogo/protobuf/proto"
"github.com/gogo/protobuf/types"
bolt "go.etcd.io/bbolt"
@ -211,7 +212,7 @@ func (s *containerStore) Update(ctx context.Context, container containers.Contai
if strings.HasPrefix(path, "extensions.") {
if updated.Extensions == nil {
updated.Extensions = map[string]types.Any{}
updated.Extensions = map[string]typeurl.Any{}
}
key := strings.TrimPrefix(path, "extensions.")
updated.Extensions[key] = container.Extensions[key]

View File

@ -30,10 +30,13 @@ import (
"github.com/containerd/containerd/filters"
"github.com/containerd/containerd/log/logtest"
"github.com/containerd/containerd/namespaces"
"github.com/containerd/containerd/protobuf"
"github.com/containerd/typeurl"
"github.com/gogo/protobuf/types"
"github.com/google/go-cmp/cmp"
specs "github.com/opencontainers/runtime-spec/specs-go"
bolt "go.etcd.io/bbolt"
"gotest.tools/v3/assert"
)
func init() {
@ -47,7 +50,7 @@ func TestContainersList(t *testing.T) {
store := NewContainerStore(NewDB(db, nil, nil))
spec := &specs.Spec{}
encoded, err := typeurl.MarshalAny(spec)
encoded, err := protobuf.MarshalAnyToProto(spec)
if err != nil {
t.Fatal(err)
}
@ -179,13 +182,13 @@ func TestContainersCreateUpdateDelete(t *testing.T) {
store := NewContainerStore(NewDB(db, nil, nil))
spec := &specs.Spec{}
encoded, err := typeurl.MarshalAny(spec)
encoded, err := protobuf.MarshalAnyToProto(spec)
if err != nil {
t.Fatal(err)
}
spec.Annotations = map[string]string{"updated": "true"}
encodedUpdated, err := typeurl.MarshalAny(spec)
encodedUpdated, err := protobuf.MarshalAnyToProto(spec)
if err != nil {
t.Fatal(err)
}
@ -467,8 +470,8 @@ func TestContainersCreateUpdateDelete(t *testing.T) {
Runtime: containers.RuntimeInfo{
Name: "testruntime",
},
Extensions: map[string]types.Any{
"hello": {
Extensions: map[string]typeurl.Any{
"hello": &types.Any{
TypeUrl: "test.update.extensions",
Value: []byte("hello"),
},
@ -479,8 +482,8 @@ func TestContainersCreateUpdateDelete(t *testing.T) {
Runtime: containers.RuntimeInfo{
Name: "testruntime",
},
Extensions: map[string]types.Any{
"hello": {
Extensions: map[string]typeurl.Any{
"hello": &types.Any{
TypeUrl: "test.update.extensions",
Value: []byte("world"),
},
@ -491,8 +494,8 @@ func TestContainersCreateUpdateDelete(t *testing.T) {
Runtime: containers.RuntimeInfo{
Name: "testruntime",
},
Extensions: map[string]types.Any{
"hello": {
Extensions: map[string]typeurl.Any{
"hello": &types.Any{
TypeUrl: "test.update.extensions",
Value: []byte("world"),
},
@ -506,8 +509,8 @@ func TestContainersCreateUpdateDelete(t *testing.T) {
Runtime: containers.RuntimeInfo{
Name: "testruntime",
},
Extensions: map[string]types.Any{
"hello": {
Extensions: map[string]typeurl.Any{
"hello": &types.Any{
TypeUrl: "test.update.extensions",
Value: []byte("hello"),
},
@ -518,8 +521,8 @@ func TestContainersCreateUpdateDelete(t *testing.T) {
Runtime: containers.RuntimeInfo{
Name: "testruntime",
},
Extensions: map[string]types.Any{
"hello": {
Extensions: map[string]typeurl.Any{
"hello": &types.Any{
TypeUrl: "test.update.extensions",
Value: []byte("world"),
},
@ -531,8 +534,8 @@ func TestContainersCreateUpdateDelete(t *testing.T) {
Runtime: containers.RuntimeInfo{
Name: "testruntime",
},
Extensions: map[string]types.Any{
"hello": {
Extensions: map[string]typeurl.Any{
"hello": &types.Any{
TypeUrl: "test.update.extensions",
Value: []byte("hello"),
},
@ -546,8 +549,8 @@ func TestContainersCreateUpdateDelete(t *testing.T) {
Runtime: containers.RuntimeInfo{
Name: "testruntime",
},
Extensions: map[string]types.Any{
"hello": {
Extensions: map[string]typeurl.Any{
"hello": &types.Any{
TypeUrl: "test.update.extensions",
Value: []byte("hello"),
},
@ -557,8 +560,8 @@ func TestContainersCreateUpdateDelete(t *testing.T) {
Labels: map[string]string{
"foo": "one",
},
Extensions: map[string]types.Any{
"hello": {
Extensions: map[string]typeurl.Any{
"hello": &types.Any{
TypeUrl: "test.update.extensions",
Value: []byte("world"),
},
@ -570,8 +573,8 @@ func TestContainersCreateUpdateDelete(t *testing.T) {
Runtime: containers.RuntimeInfo{
Name: "testruntime",
},
Extensions: map[string]types.Any{
"hello": {
Extensions: map[string]typeurl.Any{
"hello": &types.Any{
TypeUrl: "test.update.extensions",
Value: []byte("world"),
},
@ -585,21 +588,21 @@ func TestContainersCreateUpdateDelete(t *testing.T) {
Runtime: containers.RuntimeInfo{
Name: "testruntime",
},
Extensions: map[string]types.Any{
Extensions: map[string]typeurl.Any{
// leaves hello in place.
"hello": {
"hello": &types.Any{
TypeUrl: "test.update.extensions",
Value: []byte("hello"),
},
},
},
input: containers.Container{
Extensions: map[string]types.Any{
"hello": {
Extensions: map[string]typeurl.Any{
"hello": &types.Any{
TypeUrl: "test.update.extensions",
Value: []byte("universe"), // this will be ignored
},
"bar": {
"bar": &types.Any{
TypeUrl: "test.update.extensions",
Value: []byte("foo"), // this will be added
},
@ -611,12 +614,12 @@ func TestContainersCreateUpdateDelete(t *testing.T) {
Runtime: containers.RuntimeInfo{
Name: "testruntime",
},
Extensions: map[string]types.Any{
"hello": {
Extensions: map[string]typeurl.Any{
"hello": &types.Any{
TypeUrl: "test.update.extensions",
Value: []byte("hello"), // remains as world
},
"bar": {
"bar": &types.Any{
TypeUrl: "test.update.extensions",
Value: []byte("foo"), // this will be added
},
@ -702,10 +705,26 @@ func checkContainerTimestamps(t *testing.T, c *containers.Container, now time.Ti
}
}
func checkContainersEqual(t *testing.T, a, b *containers.Container, format string, args ...interface{}) {
if !reflect.DeepEqual(a, b) {
t.Fatalf("containers not equal \n\t%v != \n\t%v: "+format, append([]interface{}{a, b}, args...)...)
// isNil returns true if the given parameter is nil or typed nil.
func isNil(x interface{}) bool {
if x == nil {
return true
}
v := reflect.ValueOf(x)
return v.Kind() == reflect.Ptr && v.IsNil()
}
func checkContainersEqual(t *testing.T, a, b *containers.Container, format string, args ...interface{}) {
// Ignore the difference of nil and typed nil.
opt := cmp.FilterValues(
func(x, y interface{}) bool {
return isNil(x) && isNil(y)
},
cmp.Comparer(func(_, _ interface{}) bool {
return true
}),
)
assert.DeepEqual(t, a, b, opt)
}
func testEnv(t *testing.T) (context.Context, *bolt.DB, func()) {

View File

@ -33,7 +33,6 @@ import (
sandboxstore "github.com/containerd/containerd/pkg/cri/store/sandbox"
ctrdutil "github.com/containerd/containerd/pkg/cri/util"
"github.com/containerd/typeurl"
gogotypes "github.com/gogo/protobuf/types"
"github.com/sirupsen/logrus"
"k8s.io/utils/clock"
)
@ -207,7 +206,7 @@ func (em *eventMonitor) startContainerExitMonitor(ctx context.Context, id string
return stopCh
}
func convertEvent(e *gogotypes.Any) (string, interface{}, error) {
func convertEvent(e typeurl.Any) (string, interface{}, error) {
id := ""
evt, err := typeurl.UnmarshalAny(e)
if err != nil {

View File

@ -374,10 +374,11 @@ func getRuntimeOptionsType(t string) interface{} {
// getRuntimeOptions get runtime options from container metadata.
func getRuntimeOptions(c containers.Container) (interface{}, error) {
if c.Runtime.Options == nil {
from := c.Runtime.Options
if from == nil || from.GetValue() == nil {
return nil, nil
}
opts, err := typeurl.UnmarshalAny(c.Runtime.Options)
opts, err := typeurl.UnmarshalAny(from)
if err != nil {
return nil, err
}

View File

@ -23,6 +23,7 @@ import (
"testing"
"time"
"github.com/containerd/containerd/containers"
"github.com/containerd/containerd/errdefs"
"github.com/containerd/containerd/oci"
criconfig "github.com/containerd/containerd/pkg/cri/config"
@ -32,6 +33,8 @@ import (
"github.com/containerd/containerd/reference/docker"
"github.com/containerd/containerd/runtime/linux/runctypes"
runcoptions "github.com/containerd/containerd/runtime/v2/runc/options"
"github.com/containerd/typeurl"
"github.com/gogo/protobuf/types"
imagedigest "github.com/opencontainers/go-digest"
runtimespec "github.com/opencontainers/runtime-spec/specs-go"
@ -599,3 +602,13 @@ func TestValidateTargetContainer(t *testing.T) {
}
}
func TestGetRuntimeOptions(t *testing.T) {
_, err := getRuntimeOptions(containers.Container{})
require.NoError(t, err)
var pbany *types.Any // This is nil.
var typeurlAny typeurl.Any = pbany // This is typed nil.
_, err = getRuntimeOptions(containers.Container{Runtime: containers.RuntimeInfo{Options: typeurlAny}})
require.NoError(t, err)
}

View File

@ -166,7 +166,7 @@ func (c *criService) loadContainer(ctx context.Context, cntr containerd.Containe
if !ok {
return container, fmt.Errorf("metadata extension %q not found", containerMetadataExtension)
}
data, err := typeurl.UnmarshalAny(&ext)
data, err := typeurl.UnmarshalAny(ext)
if err != nil {
return container, fmt.Errorf("failed to unmarshal metadata extension %q: %w", ext, err)
}
@ -335,7 +335,7 @@ func (c *criService) loadSandbox(ctx context.Context, cntr containerd.Container)
if !ok {
return sandbox, fmt.Errorf("metadata extension %q not found", sandboxMetadataExtension)
}
data, err := typeurl.UnmarshalAny(&ext)
data, err := typeurl.UnmarshalAny(ext)
if err != nil {
return sandbox, fmt.Errorf("failed to unmarshal metadata extension %q: %w", ext, err)
}

47
protobuf/any.go Normal file
View File

@ -0,0 +1,47 @@
/*
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 protobuf
import (
"github.com/containerd/typeurl"
"github.com/gogo/protobuf/types"
)
// FromAny converts typeurl.Any to github.com/gogo/protobuf/types.Any.
func FromAny(from typeurl.Any) *types.Any {
if from == nil {
return nil
}
if pbany, ok := from.(*types.Any); ok {
return pbany
}
return &types.Any{
TypeUrl: from.GetTypeUrl(),
Value: from.GetValue(),
}
}
// FromAny converts an arbitrary interface to github.com/gogo/protobuf/types.Any.
func MarshalAnyToProto(from interface{}) (*types.Any, error) {
any, err := typeurl.MarshalAny(from)
if err != nil {
return nil, err
}
return FromAny(any), nil
}

26
protobuf/any_test.go Normal file
View File

@ -0,0 +1,26 @@
/*
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 protobuf
import "testing"
func TestFromAny(t *testing.T) {
actual := FromAny(nil)
if actual != nil {
t.Fatalf("expected nil, got %v", actual)
}
}

View File

@ -21,7 +21,7 @@ import (
"time"
"github.com/containerd/containerd/mount"
"github.com/gogo/protobuf/types"
"github.com/containerd/typeurl"
)
// IO holds process IO information
@ -35,7 +35,7 @@ type IO struct {
// CreateOpts contains task creation data
type CreateOpts struct {
// Spec is the OCI runtime spec
Spec *types.Any
Spec typeurl.Any
// Rootfs mounts to perform to gain access to the container's filesystem
Rootfs []mount.Mount
// IO for the container's main process
@ -43,9 +43,9 @@ type CreateOpts struct {
// Checkpoint digest to restore container state
Checkpoint string
// RuntimeOptions for the runtime
RuntimeOptions *types.Any
RuntimeOptions typeurl.Any
// TaskOptions received for the task
TaskOptions *types.Any
TaskOptions typeurl.Any
// Runtime name to use (e.g. `io.containerd.NAME.VERSION`).
// As an alternative full abs path to binary may be specified instead.
Runtime string

View File

@ -41,6 +41,7 @@ import (
"github.com/containerd/containerd/pkg/process"
"github.com/containerd/containerd/platforms"
"github.com/containerd/containerd/plugin"
"github.com/containerd/containerd/protobuf"
"github.com/containerd/containerd/runtime"
"github.com/containerd/containerd/runtime/linux/runctypes"
v1 "github.com/containerd/containerd/runtime/v1"
@ -178,7 +179,7 @@ func (r *Runtime) Create(ctx context.Context, id string, opts runtime.CreateOpts
bundle, err := newBundle(id,
filepath.Join(r.state, namespace),
filepath.Join(r.root, namespace),
opts.Spec.Value)
opts.Spec.GetValue())
if err != nil {
return nil, err
}
@ -191,7 +192,7 @@ func (r *Runtime) Create(ctx context.Context, id string, opts runtime.CreateOpts
shimopt := ShimLocal(r.config, r.events)
if !r.config.NoShim {
var cgroup string
if opts.TaskOptions != nil {
if opts.TaskOptions != nil && opts.TaskOptions.GetValue() != nil {
v, err := typeurl.UnmarshalAny(opts.TaskOptions)
if err != nil {
return nil, err
@ -244,7 +245,7 @@ func (r *Runtime) Create(ctx context.Context, id string, opts runtime.CreateOpts
Stderr: opts.IO.Stderr,
Terminal: opts.IO.Terminal,
Checkpoint: opts.Checkpoint,
Options: opts.TaskOptions,
Options: protobuf.FromAny(opts.TaskOptions),
}
for _, m := range opts.Rootfs {
sopts.Rootfs = append(sopts.Rootfs, &types.Mount{
@ -537,7 +538,7 @@ func (r *Runtime) getRuncOptions(ctx context.Context, id string) (*runctypes.Run
return nil, err
}
if container.Runtime.Options != nil {
if container.Runtime.Options != nil && container.Runtime.Options.GetValue() != nil {
v, err := typeurl.UnmarshalAny(container.Runtime.Options)
if err != nil {
return nil, err

View File

@ -31,11 +31,11 @@ import (
"github.com/containerd/containerd/events/exchange"
"github.com/containerd/containerd/identifiers"
"github.com/containerd/containerd/log"
"github.com/containerd/containerd/protobuf"
"github.com/containerd/containerd/runtime"
"github.com/containerd/containerd/runtime/v1/shim/client"
"github.com/containerd/containerd/runtime/v1/shim/v1"
"github.com/containerd/ttrpc"
"github.com/containerd/typeurl"
"github.com/gogo/protobuf/types"
)
@ -326,7 +326,7 @@ func (t *Task) Stats(ctx context.Context) (*types.Any, error) {
if err != nil {
return nil, err
}
return typeurl.MarshalAny(stats)
return protobuf.MarshalAnyToProto(stats)
}
// Cgroup returns the underlying cgroup for a linux task

View File

@ -37,6 +37,7 @@ import (
"github.com/containerd/containerd/namespaces"
"github.com/containerd/containerd/pkg/process"
"github.com/containerd/containerd/pkg/stdio"
"github.com/containerd/containerd/protobuf"
"github.com/containerd/containerd/runtime"
"github.com/containerd/containerd/runtime/linux/runctypes"
shimapi "github.com/containerd/containerd/runtime/v1/shim/v1"
@ -417,7 +418,7 @@ func (s *Service) ListPids(ctx context.Context, r *shimapi.ListPidsRequest) (*sh
if err != nil {
return nil, fmt.Errorf("failed to marshal process %d info: %w", pid, err)
}
pInfo.Info = a
pInfo.Info = protobuf.FromAny(a)
break
}
}

View File

@ -34,6 +34,7 @@ import (
"github.com/containerd/containerd/pkg/timeout"
"github.com/containerd/containerd/platforms"
"github.com/containerd/containerd/plugin"
"github.com/containerd/containerd/protobuf"
"github.com/containerd/containerd/runtime"
shimbinary "github.com/containerd/containerd/runtime/v2/shim"
"github.com/containerd/containerd/runtime/v2/task"
@ -157,7 +158,7 @@ func (m *ShimManager) ID() string {
// Start launches a new shim instance
func (m *ShimManager) Start(ctx context.Context, id string, opts runtime.CreateOpts) (_ ShimProcess, retErr error) {
bundle, err := NewBundle(ctx, m.root, m.state, id, opts.Spec.Value)
bundle, err := NewBundle(ctx, m.root, m.state, id, opts.Spec.GetValue())
if err != nil {
return nil, err
}
@ -198,7 +199,7 @@ func (m *ShimManager) startShim(ctx context.Context, bundle *Bundle, id string,
}
topts := opts.TaskOptions
if topts == nil {
if topts == nil || topts.GetValue() == nil {
topts = opts.RuntimeOptions
}
@ -213,7 +214,7 @@ func (m *ShimManager) startShim(ctx context.Context, bundle *Bundle, id string,
ttrpcAddress: m.containerdTTRPCAddress,
schedCore: m.schedCore,
})
shim, err := b.Start(ctx, topts, func() {
shim, err := b.Start(ctx, protobuf.FromAny(topts), func() {
log.G(ctx).WithField("id", id).Info("shim disconnected")
cleanupAfterDeadShim(context.Background(), id, ns, m.shims, m.events, b)

View File

@ -49,12 +49,14 @@ func NewContainer(ctx context.Context, platform stdio.Platform, r *task.CreateTa
}
var opts options.Options
if r.Options != nil && r.Options.GetTypeUrl() != "" {
if r.Options.GetValue() != nil {
v, err := typeurl.UnmarshalAny(r.Options)
if err != nil {
return nil, err
}
opts = *v.(*options.Options)
if v != nil {
opts = *v.(*options.Options)
}
}
var mounts []process.Mount

View File

@ -38,6 +38,7 @@ import (
"github.com/containerd/containerd/pkg/shutdown"
"github.com/containerd/containerd/pkg/stdio"
"github.com/containerd/containerd/pkg/userns"
"github.com/containerd/containerd/protobuf"
"github.com/containerd/containerd/runtime/v2/runc"
"github.com/containerd/containerd/runtime/v2/runc/options"
"github.com/containerd/containerd/runtime/v2/shim"
@ -375,7 +376,7 @@ func (s *service) Pids(ctx context.Context, r *taskAPI.PidsRequest) (*taskAPI.Pi
d := &options.ProcessDetails{
ExecID: p.ID(),
}
a, err := typeurl.MarshalAny(d)
a, err := protobuf.MarshalAnyToProto(d)
if err != nil {
return nil, fmt.Errorf("failed to marshal process %d info: %w", pid, err)
}
@ -503,7 +504,7 @@ func (s *service) Stats(ctx context.Context, r *taskAPI.StatsRequest) (*taskAPI.
return nil, err
}
return &taskAPI.StatsResponse{
Stats: data,
Stats: protobuf.FromAny(data),
}, nil
}

View File

@ -41,6 +41,7 @@ import (
"github.com/containerd/containerd/pkg/process"
"github.com/containerd/containerd/pkg/schedcore"
"github.com/containerd/containerd/pkg/stdio"
"github.com/containerd/containerd/protobuf"
"github.com/containerd/containerd/runtime/v2/runc"
"github.com/containerd/containerd/runtime/v2/runc/options"
"github.com/containerd/containerd/runtime/v2/shim"
@ -507,7 +508,7 @@ func (s *service) Pids(ctx context.Context, r *taskAPI.PidsRequest) (*taskAPI.Pi
d := &options.ProcessDetails{
ExecID: p.ID(),
}
a, err := typeurl.MarshalAny(d)
a, err := protobuf.MarshalAnyToProto(d)
if err != nil {
return nil, fmt.Errorf("failed to marshal process %d info: %w", pid, err)
}
@ -617,7 +618,7 @@ func (s *service) Stats(ctx context.Context, r *taskAPI.StatsRequest) (*taskAPI.
return nil, err
}
return &taskAPI.StatsResponse{
Stats: data,
Stats: protobuf.FromAny(data),
}, nil
}

View File

@ -33,6 +33,7 @@ import (
"github.com/containerd/containerd/log"
"github.com/containerd/containerd/namespaces"
"github.com/containerd/containerd/pkg/timeout"
"github.com/containerd/containerd/protobuf"
"github.com/containerd/containerd/runtime"
client "github.com/containerd/containerd/runtime/v2/shim"
"github.com/containerd/containerd/runtime/v2/task"
@ -323,7 +324,7 @@ func (s *shimTask) delete(ctx context.Context, removeTask func(ctx context.Conte
func (s *shimTask) Create(ctx context.Context, opts runtime.CreateOpts) (runtime.Task, error) {
topts := opts.TaskOptions
if topts == nil {
if topts == nil || topts.GetValue() == nil {
topts = opts.RuntimeOptions
}
request := &task.CreateTaskRequest{
@ -334,7 +335,7 @@ func (s *shimTask) Create(ctx context.Context, opts runtime.CreateOpts) (runtime
Stderr: opts.IO.Stderr,
Terminal: opts.IO.Terminal,
Checkpoint: opts.Checkpoint,
Options: topts,
Options: protobuf.FromAny(topts),
}
for _, m := range opts.Rootfs {
request.Rootfs = append(request.Rootfs, &types.Mount{

View File

@ -25,8 +25,8 @@ import (
"github.com/containerd/containerd/events"
"github.com/containerd/containerd/namespaces"
"github.com/containerd/containerd/pkg/ttrpcutil"
"github.com/containerd/containerd/protobuf"
"github.com/containerd/ttrpc"
"github.com/containerd/typeurl"
"github.com/sirupsen/logrus"
)
@ -110,7 +110,7 @@ func (l *RemoteEventsPublisher) Publish(ctx context.Context, topic string, event
if err != nil {
return err
}
any, err := typeurl.MarshalAny(event)
any, err := protobuf.MarshalAnyToProto(event)
if err != nil {
return err
}

View File

@ -19,6 +19,9 @@ package containers
import (
api "github.com/containerd/containerd/api/services/containers/v1"
"github.com/containerd/containerd/containers"
"github.com/containerd/containerd/protobuf"
"github.com/containerd/typeurl"
"github.com/gogo/protobuf/types"
)
func containersToProto(containers []containers.Container) []api.Container {
@ -33,20 +36,24 @@ func containersToProto(containers []containers.Container) []api.Container {
}
func containerToProto(container *containers.Container) api.Container {
extensions := make(map[string]types.Any)
for k, v := range container.Extensions {
extensions[k] = *protobuf.FromAny(v)
}
return api.Container{
ID: container.ID,
Labels: container.Labels,
Image: container.Image,
Runtime: &api.Container_Runtime{
Name: container.Runtime.Name,
Options: container.Runtime.Options,
Options: protobuf.FromAny(container.Runtime.Options),
},
Spec: container.Spec,
Spec: protobuf.FromAny(container.Spec),
Snapshotter: container.Snapshotter,
SnapshotKey: container.SnapshotKey,
CreatedAt: container.CreatedAt,
UpdatedAt: container.UpdatedAt,
Extensions: container.Extensions,
Extensions: extensions,
}
}
@ -58,6 +65,11 @@ func containerFromProto(containerpb *api.Container) containers.Container {
Options: containerpb.Runtime.Options,
}
}
extensions := make(map[string]typeurl.Any)
for k, v := range containerpb.Extensions {
v := v
extensions[k] = &v
}
return containers.Container{
ID: containerpb.ID,
Labels: containerpb.Labels,
@ -66,6 +78,6 @@ func containerFromProto(containerpb *api.Container) containers.Container {
Spec: containerpb.Spec,
Snapshotter: containerpb.Snapshotter,
SnapshotKey: containerpb.SnapshotKey,
Extensions: containerpb.Extensions,
Extensions: extensions,
}
}

View File

@ -26,6 +26,7 @@ import (
"github.com/containerd/containerd/events"
"github.com/containerd/containerd/events/exchange"
"github.com/containerd/containerd/plugin"
"github.com/containerd/containerd/protobuf"
"github.com/containerd/ttrpc"
ptypes "github.com/gogo/protobuf/types"
"google.golang.org/grpc"
@ -115,7 +116,7 @@ func toProto(env *events.Envelope) *api.Envelope {
Timestamp: env.Timestamp,
Namespace: env.Namespace,
Topic: env.Topic,
Event: env.Event,
Event: protobuf.FromAny(env.Event),
}
}

View File

@ -41,6 +41,7 @@ import (
"github.com/containerd/containerd/mount"
"github.com/containerd/containerd/pkg/timeout"
"github.com/containerd/containerd/plugin"
"github.com/containerd/containerd/protobuf"
"github.com/containerd/containerd/runtime"
"github.com/containerd/containerd/runtime/linux/runctypes"
"github.com/containerd/containerd/runtime/v2/runc/options"
@ -462,7 +463,7 @@ func (l *local) ListPids(ctx context.Context, r *api.ListPidsRequest, _ ...grpc.
Pid: p.Pid,
}
if p.Info != nil {
a, err := typeurl.MarshalAny(p.Info)
a, err := protobuf.MarshalAnyToProto(p.Info)
if err != nil {
return nil, fmt.Errorf("failed to marshal process %d info: %w", p.Pid, err)
}
@ -577,7 +578,7 @@ func (l *local) Checkpoint(ctx context.Context, r *api.CheckpointTaskRequest, _
return nil, err
}
// write the config to the content store
data, err := container.Spec.Marshal()
data, err := protobuf.FromAny(container.Spec).Marshal()
if err != nil {
return nil, err
}

View File

@ -38,6 +38,7 @@ import (
"github.com/containerd/containerd/mount"
"github.com/containerd/containerd/oci"
"github.com/containerd/containerd/plugin"
"github.com/containerd/containerd/protobuf"
"github.com/containerd/containerd/rootfs"
"github.com/containerd/containerd/runtime/linux/runctypes"
"github.com/containerd/containerd/runtime/v2/runc/options"
@ -346,7 +347,7 @@ func (t *task) Exec(ctx context.Context, id string, spec *specs.Process, ioCreat
i.Close()
}
}()
any, err := typeurl.MarshalAny(spec)
any, err := protobuf.MarshalAnyToProto(spec)
if err != nil {
return nil, err
}
@ -446,7 +447,7 @@ func (t *task) Checkpoint(ctx context.Context, opts ...CheckpointTaskOpts) (Imag
}
request.ParentCheckpoint = i.ParentCheckpoint.String()
if i.Options != nil {
any, err := typeurl.MarshalAny(i.Options)
any, err := protobuf.MarshalAnyToProto(i.Options)
if err != nil {
return nil, err
}
@ -535,7 +536,7 @@ func (t *task) Update(ctx context.Context, opts ...UpdateTaskOpts) error {
if err != nil {
return err
}
request.Resources = any
request.Resources = protobuf.FromAny(any)
}
if i.Annotations != nil {
request.Annotations = i.Annotations

View File

@ -7,7 +7,7 @@
A Go package for managing the registration, marshaling, and unmarshaling of encoded types.
This package helps when types are sent over a GRPC API and marshaled as a [protobuf.Any](https://github.com/gogo/protobuf/blob/master/protobuf/google/protobuf/any.proto).
This package helps when types are sent over a ttrpc/GRPC API and marshaled as a protobuf [Any](https://pkg.go.dev/google.golang.org/protobuf@v1.27.1/types/known/anypb#Any)
## Project details

View File

@ -18,13 +18,14 @@ package typeurl
import (
"encoding/json"
"errors"
"fmt"
"path"
"reflect"
"sync"
"github.com/gogo/protobuf/proto"
"github.com/gogo/protobuf/types"
"github.com/pkg/errors"
gogoproto "github.com/gogo/protobuf/proto"
"google.golang.org/protobuf/proto"
)
var (
@ -39,10 +40,35 @@ var (
//
// To detect an error class, use errors.Is() functions to tell whether an
// error is of this type.
var (
ErrNotFound = errors.New("not found")
)
type Any interface {
GetTypeUrl() string
GetValue() []byte
}
type any struct {
typeURL string
value []byte
}
func (a *any) GetTypeUrl() string {
if a == nil {
return ""
}
return a.typeURL
}
func (a *any) GetValue() []byte {
if a == nil {
return nil
}
return a.value
}
// Register a type with a base URL for JSON marshaling. When the MarshalAny and
// UnmarshalAny functions are called they will treat the Any type value as JSON.
// To use protocol buffers for handling the Any value the proto.Register
@ -56,7 +82,7 @@ func Register(v interface{}, args ...string) {
defer mu.Unlock()
if et, ok := registry[t]; ok {
if et != p {
panic(errors.Errorf("type registered with alternate path %q != %q", et, p))
panic(fmt.Errorf("type registered with alternate path %q != %q", et, p))
}
return
}
@ -69,41 +95,47 @@ func TypeURL(v interface{}) (string, error) {
u, ok := registry[tryDereference(v)]
mu.RUnlock()
if !ok {
// fallback to the proto registry if it is a proto message
pb, ok := v.(proto.Message)
if !ok {
return "", errors.Wrapf(ErrNotFound, "type %s", reflect.TypeOf(v))
switch t := v.(type) {
case proto.Message:
return string(t.ProtoReflect().Descriptor().FullName()), nil
case gogoproto.Message:
return gogoproto.MessageName(t), nil
default:
return "", fmt.Errorf("type %s: %w", reflect.TypeOf(v), ErrNotFound)
}
return proto.MessageName(pb), nil
}
return u, nil
}
// Is returns true if the type of the Any is the same as v.
func Is(any *types.Any, v interface{}) bool {
func Is(any Any, v interface{}) bool {
// call to check that v is a pointer
tryDereference(v)
url, err := TypeURL(v)
if err != nil {
return false
}
return any.TypeUrl == url
return any.GetTypeUrl() == url
}
// MarshalAny marshals the value v into an any with the correct TypeUrl.
// If the provided object is already a proto.Any message, then it will be
// returned verbatim. If it is of type proto.Message, it will be marshaled as a
// protocol buffer. Otherwise, the object will be marshaled to json.
func MarshalAny(v interface{}) (*types.Any, error) {
func MarshalAny(v interface{}) (Any, error) {
var marshal func(v interface{}) ([]byte, error)
switch t := v.(type) {
case *types.Any:
case Any:
// avoid reserializing the type if we have an any.
return t, nil
case proto.Message:
marshal = func(v interface{}) ([]byte, error) {
return proto.Marshal(t)
}
case gogoproto.Message:
marshal = func(v interface{}) ([]byte, error) {
return gogoproto.Marshal(t)
}
default:
marshal = json.Marshal
}
@ -117,15 +149,15 @@ func MarshalAny(v interface{}) (*types.Any, error) {
if err != nil {
return nil, err
}
return &types.Any{
TypeUrl: url,
Value: data,
return &any{
typeURL: url,
value: data,
}, nil
}
// UnmarshalAny unmarshals the any type into a concrete type.
func UnmarshalAny(any *types.Any) (interface{}, error) {
return UnmarshalByTypeURL(any.TypeUrl, any.Value)
func UnmarshalAny(any Any) (interface{}, error) {
return UnmarshalByTypeURL(any.GetTypeUrl(), any.GetValue())
}
// UnmarshalByTypeURL unmarshals the given type and value to into a concrete type.
@ -136,11 +168,11 @@ func UnmarshalByTypeURL(typeURL string, value []byte) (interface{}, error) {
// UnmarshalTo unmarshals the any type into a concrete type passed in the out
// argument. It is identical to UnmarshalAny, but lets clients provide a
// destination type through the out argument.
func UnmarshalTo(any *types.Any, out interface{}) error {
return UnmarshalToByTypeURL(any.TypeUrl, any.Value, out)
func UnmarshalTo(any Any, out interface{}) error {
return UnmarshalToByTypeURL(any.GetTypeUrl(), any.GetValue(), out)
}
// UnmarshalTo unmarshals the given type and value into a concrete type passed
// UnmarshalToByTypeURL unmarshals the given type and value into a concrete type passed
// in the out argument. It is identical to UnmarshalByTypeURL, but lets clients
// provide a destination type through the out argument.
func UnmarshalToByTypeURL(typeURL string, value []byte, out interface{}) error {
@ -149,6 +181,10 @@ func UnmarshalToByTypeURL(typeURL string, value []byte, out interface{}) error {
}
func unmarshal(typeURL string, value []byte, v interface{}) (interface{}, error) {
if value == nil {
return nil, nil
}
t, err := getTypeByUrl(typeURL)
if err != nil {
return nil, err
@ -163,12 +199,17 @@ func unmarshal(typeURL string, value []byte, v interface{}) (interface{}, error)
return nil, err
}
if typeURL != vURL {
return nil, errors.Errorf("can't unmarshal type %q to output %q", typeURL, vURL)
return nil, fmt.Errorf("can't unmarshal type %q to output %q", typeURL, vURL)
}
}
if t.isProto {
err = proto.Unmarshal(value, v.(proto.Message))
switch t := v.(type) {
case proto.Message:
err = proto.Unmarshal(value, t)
case gogoproto.Message:
err = gogoproto.Unmarshal(value, t)
}
} else {
err = json.Unmarshal(value, v)
}
@ -193,7 +234,7 @@ func getTypeByUrl(url string) (urlType, error) {
}
mu.RUnlock()
// fallback to proto registry
t := proto.MessageType(url)
t := gogoproto.MessageType(url)
if t != nil {
return urlType{
// get the underlying Elem because proto returns a pointer to the type
@ -201,7 +242,7 @@ func getTypeByUrl(url string) (urlType, error) {
isProto: true,
}, nil
}
return urlType{}, errors.Wrapf(ErrNotFound, "type with url %s", url)
return urlType{}, fmt.Errorf("type with url %s: %w", url, ErrNotFound)
}
func tryDereference(v interface{}) reflect.Type {

2
vendor/modules.txt vendored
View File

@ -116,7 +116,7 @@ github.com/containerd/nri/types/v1
## explicit; go 1.13
github.com/containerd/ttrpc
github.com/containerd/ttrpc/plugin
# github.com/containerd/typeurl v1.0.2
# github.com/containerd/typeurl v1.0.3-0.20220324183432-6193a0e03259
## explicit; go 1.13
github.com/containerd/typeurl
# github.com/containerd/zfs v1.0.0