From aff5b809c50414a0a3f714dc4f5865c8b753c790 Mon Sep 17 00:00:00 2001 From: Samuel Karp Date: Tue, 17 Oct 2023 11:09:49 -0700 Subject: [PATCH 1/8] deprecation: new package for deprecations This package enumerates the known deprecations in the current version of containerd. New deprecations should be added here, and old ones removed. Signed-off-by: Samuel Karp --- pkg/deprecation/deprecation.go | 46 ++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 pkg/deprecation/deprecation.go diff --git a/pkg/deprecation/deprecation.go b/pkg/deprecation/deprecation.go new file mode 100644 index 000000000000..49fdae88410b --- /dev/null +++ b/pkg/deprecation/deprecation.go @@ -0,0 +1,46 @@ +/* + 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 deprecation + +type Warning string + +const ( + // Prefix is a standard prefix for all Warnings, used for filtering plugin Exports + Prefix = "io.containerd.deprecation/" + // PullSchema1Image is a warning for the use of schema 1 images + PullSchema1Image Warning = Prefix + "pull-schema-1-image" + // GoPluginLibrary is a warning for the use of dynamic library Go plugins + GoPluginLibrary Warning = Prefix + "go-plugin-library" +) + +var messages = map[Warning]string{ + PullSchema1Image: "Schema 1 images are deprecated since containerd v1.7 and removed in containerd v2.0. " + + `Since containerd v1.7.8, schema 1 images are identified by the "io.containerd.image/converted-docker-schema1" label.`, + GoPluginLibrary: "Dynamically-linked Go plugins as containerd runtimes are deprecated since containerd v2.0 and removed in containerd v2.1.", +} + +// Valid checks whether a given Warning is valid +func Valid(id Warning) bool { + _, ok := messages[id] + return ok +} + +// Message returns the human-readable message for a given Warning +func Message(id Warning) (string, bool) { + msg, ok := messages[id] + return msg, ok +} From 240733ce2f9797ee83e3c9126b3a34486d2054c1 Mon Sep 17 00:00:00 2001 From: Samuel Karp Date: Tue, 17 Oct 2023 23:23:39 -0700 Subject: [PATCH 2/8] warning: new service for deprecations Signed-off-by: Samuel Karp --- cmd/containerd/builtins/builtins.go | 1 + plugins/types.go | 4 ++ services/warning/service.go | 95 +++++++++++++++++++++++++++++ 3 files changed, 100 insertions(+) create mode 100644 services/warning/service.go diff --git a/cmd/containerd/builtins/builtins.go b/cmd/containerd/builtins/builtins.go index a5232abcc695..0a0e09d7f692 100644 --- a/cmd/containerd/builtins/builtins.go +++ b/cmd/containerd/builtins/builtins.go @@ -46,4 +46,5 @@ import ( _ "github.com/containerd/containerd/services/tasks" _ "github.com/containerd/containerd/services/transfer" _ "github.com/containerd/containerd/services/version" + _ "github.com/containerd/containerd/services/warning" ) diff --git a/plugins/types.go b/plugins/types.go index 2f25f8c516de..4524a7e909ac 100644 --- a/plugins/types.go +++ b/plugins/types.go @@ -65,11 +65,15 @@ const ( SandboxControllerPlugin plugin.Type = "io.containerd.sandbox.controller.v1" // ImageVerifierPlugin implements an image verifier service ImageVerifierPlugin plugin.Type = "io.containerd.image-verifier.v1" + // WarningPlugin implements a warning service + WarningPlugin plugin.Type = "io.containerd.warning.v1" ) const ( // RuntimeRuncV2 is the runc runtime that supports multiple containers per shim RuntimeRuncV2 = "io.containerd.runc.v2" + + DeprecationsPlugin = "deprecations" ) const ( diff --git a/services/warning/service.go b/services/warning/service.go new file mode 100644 index 000000000000..dc35bc423a94 --- /dev/null +++ b/services/warning/service.go @@ -0,0 +1,95 @@ +/* + 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 warning + +import ( + "context" + "sync" + "time" + + "github.com/containerd/log" + + deprecation "github.com/containerd/containerd/pkg/deprecation" + "github.com/containerd/containerd/plugin" + "github.com/containerd/containerd/plugin/registry" + "github.com/containerd/containerd/plugins" +) + +type Service interface { + Emit(context.Context, deprecation.Warning) + Warnings() []Warning +} + +func init() { + registry.Register(&plugin.Registration{ + Type: plugins.WarningPlugin, + ID: plugins.DeprecationsPlugin, + InitFn: func(ic *plugin.InitContext) (interface{}, error) { + return &service{warnings: make(map[deprecation.Warning]time.Time)}, nil + }, + }) +} + +type Warning struct { + ID deprecation.Warning + LastOccurrence time.Time + Message string +} + +var _ Service = (*service)(nil) + +func init() { + registry.Register(&plugin.Registration{ + Type: plugins.InternalPlugin, + ID: "warning", + InitFn: func(ic *plugin.InitContext) (interface{}, error) { + return &service{warnings: make(map[deprecation.Warning]time.Time)}, nil + }, + }) +} + +type service struct { + warnings map[deprecation.Warning]time.Time + m sync.RWMutex +} + +func (s *service) Emit(ctx context.Context, warning deprecation.Warning) { + if !deprecation.Valid(warning) { + log.G(ctx).WithField("warningID", string(warning)).Warn("invalid deprecation warning") + return + } + s.m.Lock() + defer s.m.Unlock() + s.warnings[warning] = time.Now() +} +func (s *service) Warnings() []Warning { + s.m.RLock() + defer s.m.RUnlock() + var warnings []Warning + for k, v := range s.warnings { + msg, ok := deprecation.Message(k) + if !ok { + continue + } + warnings = append(warnings, Warning{ + ID: k, + LastOccurrence: v, + Message: msg, + }) + } + return warnings +} From 57c897f10df48556af799f71c85a91b889df2d70 Mon Sep 17 00:00:00 2001 From: Samuel Karp Date: Mon, 16 Oct 2023 23:06:01 -0700 Subject: [PATCH 3/8] api/introspection: deprecation warnings in server The Server rpc in introspection service is extended to expose deprecation warnings based on observed feature use in containerd. Signed-off-by: Samuel Karp --- api/next.pb.txt | 34 +++ .../introspection/v1/introspection.pb.go | 262 ++++++++++++------ .../introspection/v1/introspection.proto | 8 + 3 files changed, 225 insertions(+), 79 deletions(-) diff --git a/api/next.pb.txt b/api/next.pb.txt index b184223e2f6c..c68107a5f406 100644 --- a/api/next.pb.txt +++ b/api/next.pb.txt @@ -4344,6 +4344,7 @@ file { dependency: "github.com/containerd/containerd/api/types/platform.proto" dependency: "google/rpc/status.proto" dependency: "google/protobuf/empty.proto" + dependency: "google/protobuf/timestamp.proto" message_type { name: "Plugin" field { @@ -4463,6 +4464,39 @@ file { type: TYPE_UINT64 json_name: "pidns" } + field { + name: "deprecations" + number: 4 + label: LABEL_REPEATED + type: TYPE_MESSAGE + type_name: ".containerd.services.introspection.v1.DeprecationWarning" + json_name: "deprecations" + } + } + message_type { + name: "DeprecationWarning" + field { + name: "id" + number: 1 + label: LABEL_OPTIONAL + type: TYPE_STRING + json_name: "id" + } + field { + name: "message" + number: 2 + label: LABEL_OPTIONAL + type: TYPE_STRING + json_name: "message" + } + field { + name: "last_occurrence" + number: 3 + label: LABEL_OPTIONAL + type: TYPE_MESSAGE + type_name: ".google.protobuf.Timestamp" + json_name: "lastOccurrence" + } } service { name: "Introspection" diff --git a/api/services/introspection/v1/introspection.pb.go b/api/services/introspection/v1/introspection.pb.go index aeef7c3a0253..7768f81313ec 100644 --- a/api/services/introspection/v1/introspection.pb.go +++ b/api/services/introspection/v1/introspection.pb.go @@ -27,6 +27,7 @@ import ( protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" emptypb "google.golang.org/protobuf/types/known/emptypb" + timestamppb "google.golang.org/protobuf/types/known/timestamppb" reflect "reflect" sync "sync" ) @@ -272,9 +273,10 @@ type ServerResponse struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - UUID string `protobuf:"bytes,1,opt,name=uuid,proto3" json:"uuid,omitempty"` - Pid uint64 `protobuf:"varint,2,opt,name=pid,proto3" json:"pid,omitempty"` - Pidns uint64 `protobuf:"varint,3,opt,name=pidns,proto3" json:"pidns,omitempty"` // PID namespace, such as 4026531836 + UUID string `protobuf:"bytes,1,opt,name=uuid,proto3" json:"uuid,omitempty"` + Pid uint64 `protobuf:"varint,2,opt,name=pid,proto3" json:"pid,omitempty"` + Pidns uint64 `protobuf:"varint,3,opt,name=pidns,proto3" json:"pidns,omitempty"` // PID namespace, such as 4026531836 + Deprecations []*DeprecationWarning `protobuf:"bytes,4,rep,name=deprecations,proto3" json:"deprecations,omitempty"` } func (x *ServerResponse) Reset() { @@ -330,6 +332,76 @@ func (x *ServerResponse) GetPidns() uint64 { return 0 } +func (x *ServerResponse) GetDeprecations() []*DeprecationWarning { + if x != nil { + return x.Deprecations + } + return nil +} + +type DeprecationWarning struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Message string `protobuf:"bytes,2,opt,name=message,proto3" json:"message,omitempty"` + LastOccurrence *timestamppb.Timestamp `protobuf:"bytes,3,opt,name=last_occurrence,json=lastOccurrence,proto3" json:"last_occurrence,omitempty"` +} + +func (x *DeprecationWarning) Reset() { + *x = DeprecationWarning{} + if protoimpl.UnsafeEnabled { + mi := &file_github_com_containerd_containerd_api_services_introspection_v1_introspection_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DeprecationWarning) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeprecationWarning) ProtoMessage() {} + +func (x *DeprecationWarning) ProtoReflect() protoreflect.Message { + mi := &file_github_com_containerd_containerd_api_services_introspection_v1_introspection_proto_msgTypes[4] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DeprecationWarning.ProtoReflect.Descriptor instead. +func (*DeprecationWarning) Descriptor() ([]byte, []int) { + return file_github_com_containerd_containerd_api_services_introspection_v1_introspection_proto_rawDescGZIP(), []int{4} +} + +func (x *DeprecationWarning) GetID() string { + if x != nil { + return x.ID + } + return "" +} + +func (x *DeprecationWarning) GetMessage() string { + if x != nil { + return x.Message + } + return "" +} + +func (x *DeprecationWarning) GetLastOccurrence() *timestamppb.Timestamp { + if x != nil { + return x.LastOccurrence + } + return nil +} + var File_github_com_containerd_containerd_api_services_introspection_v1_introspection_proto protoreflect.FileDescriptor var file_github_com_containerd_containerd_api_services_introspection_v1_introspection_proto_rawDesc = []byte{ @@ -347,63 +419,79 @@ var file_github_com_containerd_containerd_api_services_introspection_v1_introspe 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x17, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x72, 0x70, 0x63, 0x2f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1b, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, - 0x65, 0x6d, 0x70, 0x74, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xe6, 0x02, 0x0a, 0x06, - 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, - 0x71, 0x75, 0x69, 0x72, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x72, 0x65, - 0x71, 0x75, 0x69, 0x72, 0x65, 0x73, 0x12, 0x38, 0x0a, 0x09, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, - 0x72, 0x6d, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x63, 0x6f, 0x6e, 0x74, - 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x50, 0x6c, 0x61, - 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x52, 0x09, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x73, - 0x12, 0x53, 0x0a, 0x07, 0x65, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, - 0x0b, 0x32, 0x39, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x73, + 0x65, 0x6d, 0x70, 0x74, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1f, 0x67, 0x6f, 0x6f, + 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x69, 0x6d, + 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xe6, 0x02, 0x0a, + 0x06, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, + 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x72, + 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x72, + 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x73, 0x12, 0x38, 0x0a, 0x09, 0x70, 0x6c, 0x61, 0x74, 0x66, + 0x6f, 0x72, 0x6d, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x63, 0x6f, 0x6e, + 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x50, 0x6c, + 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x52, 0x09, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, + 0x73, 0x12, 0x53, 0x0a, 0x07, 0x65, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x18, 0x05, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x39, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, + 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x69, 0x6e, 0x74, 0x72, 0x6f, 0x73, 0x70, + 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, + 0x2e, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x65, + 0x78, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x12, 0x22, 0x0a, 0x0c, 0x63, 0x61, 0x70, 0x61, 0x62, 0x69, + 0x6c, 0x69, 0x74, 0x69, 0x65, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0c, 0x63, 0x61, + 0x70, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x69, 0x65, 0x73, 0x12, 0x2d, 0x0a, 0x08, 0x69, 0x6e, + 0x69, 0x74, 0x5f, 0x65, 0x72, 0x72, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x67, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, + 0x52, 0x07, 0x69, 0x6e, 0x69, 0x74, 0x45, 0x72, 0x72, 0x1a, 0x3a, 0x0a, 0x0c, 0x45, 0x78, 0x70, + 0x6f, 0x72, 0x74, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, + 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, + 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x2a, 0x0a, 0x0e, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x73, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x66, 0x69, 0x6c, 0x74, 0x65, + 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, + 0x73, 0x22, 0x59, 0x0a, 0x0f, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x46, 0x0a, 0x07, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x73, 0x18, + 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, + 0x72, 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x69, 0x6e, 0x74, 0x72, + 0x6f, 0x73, 0x70, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x6c, 0x75, + 0x67, 0x69, 0x6e, 0x52, 0x07, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x73, 0x22, 0xaa, 0x01, 0x0a, + 0x0e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x12, 0x0a, 0x04, 0x75, 0x75, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x75, + 0x75, 0x69, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x70, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, + 0x52, 0x03, 0x70, 0x69, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x70, 0x69, 0x64, 0x6e, 0x73, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x70, 0x69, 0x64, 0x6e, 0x73, 0x12, 0x5c, 0x0a, 0x0c, 0x64, + 0x65, 0x70, 0x72, 0x65, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x38, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x69, 0x6e, 0x74, 0x72, 0x6f, 0x73, 0x70, 0x65, - 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x2e, - 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x65, 0x78, - 0x70, 0x6f, 0x72, 0x74, 0x73, 0x12, 0x22, 0x0a, 0x0c, 0x63, 0x61, 0x70, 0x61, 0x62, 0x69, 0x6c, - 0x69, 0x74, 0x69, 0x65, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0c, 0x63, 0x61, 0x70, - 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x69, 0x65, 0x73, 0x12, 0x2d, 0x0a, 0x08, 0x69, 0x6e, 0x69, - 0x74, 0x5f, 0x65, 0x72, 0x72, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x67, 0x6f, - 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, - 0x07, 0x69, 0x6e, 0x69, 0x74, 0x45, 0x72, 0x72, 0x1a, 0x3a, 0x0a, 0x0c, 0x45, 0x78, 0x70, 0x6f, - 0x72, 0x74, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, - 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, - 0x3a, 0x02, 0x38, 0x01, 0x22, 0x2a, 0x0a, 0x0e, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x73, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, - 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x73, - 0x22, 0x59, 0x0a, 0x0f, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x12, 0x46, 0x0a, 0x07, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x73, 0x18, 0x01, - 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, - 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x69, 0x6e, 0x74, 0x72, 0x6f, - 0x73, 0x70, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x6c, 0x75, 0x67, - 0x69, 0x6e, 0x52, 0x07, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x73, 0x22, 0x4c, 0x0a, 0x0e, 0x53, - 0x65, 0x72, 0x76, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x12, 0x0a, - 0x04, 0x75, 0x75, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x75, 0x75, 0x69, - 0x64, 0x12, 0x10, 0x0a, 0x03, 0x70, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x03, - 0x70, 0x69, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x70, 0x69, 0x64, 0x6e, 0x73, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x04, 0x52, 0x05, 0x70, 0x69, 0x64, 0x6e, 0x73, 0x32, 0xdf, 0x01, 0x0a, 0x0d, 0x49, 0x6e, - 0x74, 0x72, 0x6f, 0x73, 0x70, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x76, 0x0a, 0x07, 0x50, - 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x73, 0x12, 0x34, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, - 0x65, 0x72, 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x69, 0x6e, 0x74, - 0x72, 0x6f, 0x73, 0x70, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x6c, - 0x75, 0x67, 0x69, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x35, 0x2e, 0x63, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x70, 0x72, 0x65, 0x63, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x57, 0x61, 0x72, 0x6e, 0x69, 0x6e, 0x67, 0x52, 0x0c, 0x64, 0x65, 0x70, + 0x72, 0x65, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x83, 0x01, 0x0a, 0x12, 0x44, 0x65, + 0x70, 0x72, 0x65, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x57, 0x61, 0x72, 0x6e, 0x69, 0x6e, 0x67, + 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, + 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x43, 0x0a, 0x0f, 0x6c, 0x61, + 0x73, 0x74, 0x5f, 0x6f, 0x63, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, + 0x0e, 0x6c, 0x61, 0x73, 0x74, 0x4f, 0x63, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x32, + 0xdf, 0x01, 0x0a, 0x0d, 0x49, 0x6e, 0x74, 0x72, 0x6f, 0x73, 0x70, 0x65, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x12, 0x76, 0x0a, 0x07, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x73, 0x12, 0x34, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x69, 0x6e, 0x74, 0x72, 0x6f, 0x73, 0x70, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, - 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x12, 0x56, 0x0a, 0x06, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x12, 0x16, 0x2e, - 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, - 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x34, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, - 0x72, 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x69, 0x6e, 0x74, 0x72, - 0x6f, 0x73, 0x70, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x72, - 0x76, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x4e, 0x5a, 0x4c, 0x67, - 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, - 0x6e, 0x65, 0x72, 0x64, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2f, - 0x61, 0x70, 0x69, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2f, 0x69, 0x6e, 0x74, - 0x72, 0x6f, 0x73, 0x70, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x31, 0x3b, 0x69, 0x6e, - 0x74, 0x72, 0x6f, 0x73, 0x70, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x62, 0x06, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x33, + 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x35, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, + 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x69, 0x6e, 0x74, 0x72, 0x6f, 0x73, 0x70, + 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, + 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x56, 0x0a, 0x06, 0x53, 0x65, 0x72, + 0x76, 0x65, 0x72, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x34, 0x2e, 0x63, 0x6f, + 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, + 0x73, 0x2e, 0x69, 0x6e, 0x74, 0x72, 0x6f, 0x73, 0x70, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2e, + 0x76, 0x31, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x42, 0x4e, 0x5a, 0x4c, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, + 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x61, + 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, + 0x65, 0x73, 0x2f, 0x69, 0x6e, 0x74, 0x72, 0x6f, 0x73, 0x70, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x2f, 0x76, 0x31, 0x3b, 0x69, 0x6e, 0x74, 0x72, 0x6f, 0x73, 0x70, 0x65, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -418,31 +506,35 @@ func file_github_com_containerd_containerd_api_services_introspection_v1_introsp return file_github_com_containerd_containerd_api_services_introspection_v1_introspection_proto_rawDescData } -var file_github_com_containerd_containerd_api_services_introspection_v1_introspection_proto_msgTypes = make([]protoimpl.MessageInfo, 5) +var file_github_com_containerd_containerd_api_services_introspection_v1_introspection_proto_msgTypes = make([]protoimpl.MessageInfo, 6) var file_github_com_containerd_containerd_api_services_introspection_v1_introspection_proto_goTypes = []interface{}{ - (*Plugin)(nil), // 0: containerd.services.introspection.v1.Plugin - (*PluginsRequest)(nil), // 1: containerd.services.introspection.v1.PluginsRequest - (*PluginsResponse)(nil), // 2: containerd.services.introspection.v1.PluginsResponse - (*ServerResponse)(nil), // 3: containerd.services.introspection.v1.ServerResponse - nil, // 4: containerd.services.introspection.v1.Plugin.ExportsEntry - (*types.Platform)(nil), // 5: containerd.types.Platform - (*status.Status)(nil), // 6: google.rpc.Status - (*emptypb.Empty)(nil), // 7: google.protobuf.Empty + (*Plugin)(nil), // 0: containerd.services.introspection.v1.Plugin + (*PluginsRequest)(nil), // 1: containerd.services.introspection.v1.PluginsRequest + (*PluginsResponse)(nil), // 2: containerd.services.introspection.v1.PluginsResponse + (*ServerResponse)(nil), // 3: containerd.services.introspection.v1.ServerResponse + (*DeprecationWarning)(nil), // 4: containerd.services.introspection.v1.DeprecationWarning + nil, // 5: containerd.services.introspection.v1.Plugin.ExportsEntry + (*types.Platform)(nil), // 6: containerd.types.Platform + (*status.Status)(nil), // 7: google.rpc.Status + (*timestamppb.Timestamp)(nil), // 8: google.protobuf.Timestamp + (*emptypb.Empty)(nil), // 9: google.protobuf.Empty } var file_github_com_containerd_containerd_api_services_introspection_v1_introspection_proto_depIdxs = []int32{ - 5, // 0: containerd.services.introspection.v1.Plugin.platforms:type_name -> containerd.types.Platform - 4, // 1: containerd.services.introspection.v1.Plugin.exports:type_name -> containerd.services.introspection.v1.Plugin.ExportsEntry - 6, // 2: containerd.services.introspection.v1.Plugin.init_err:type_name -> google.rpc.Status + 6, // 0: containerd.services.introspection.v1.Plugin.platforms:type_name -> containerd.types.Platform + 5, // 1: containerd.services.introspection.v1.Plugin.exports:type_name -> containerd.services.introspection.v1.Plugin.ExportsEntry + 7, // 2: containerd.services.introspection.v1.Plugin.init_err:type_name -> google.rpc.Status 0, // 3: containerd.services.introspection.v1.PluginsResponse.plugins:type_name -> containerd.services.introspection.v1.Plugin - 1, // 4: containerd.services.introspection.v1.Introspection.Plugins:input_type -> containerd.services.introspection.v1.PluginsRequest - 7, // 5: containerd.services.introspection.v1.Introspection.Server:input_type -> google.protobuf.Empty - 2, // 6: containerd.services.introspection.v1.Introspection.Plugins:output_type -> containerd.services.introspection.v1.PluginsResponse - 3, // 7: containerd.services.introspection.v1.Introspection.Server:output_type -> containerd.services.introspection.v1.ServerResponse - 6, // [6:8] is the sub-list for method output_type - 4, // [4:6] is the sub-list for method input_type - 4, // [4:4] is the sub-list for extension type_name - 4, // [4:4] is the sub-list for extension extendee - 0, // [0:4] is the sub-list for field type_name + 4, // 4: containerd.services.introspection.v1.ServerResponse.deprecations:type_name -> containerd.services.introspection.v1.DeprecationWarning + 8, // 5: containerd.services.introspection.v1.DeprecationWarning.last_occurrence:type_name -> google.protobuf.Timestamp + 1, // 6: containerd.services.introspection.v1.Introspection.Plugins:input_type -> containerd.services.introspection.v1.PluginsRequest + 9, // 7: containerd.services.introspection.v1.Introspection.Server:input_type -> google.protobuf.Empty + 2, // 8: containerd.services.introspection.v1.Introspection.Plugins:output_type -> containerd.services.introspection.v1.PluginsResponse + 3, // 9: containerd.services.introspection.v1.Introspection.Server:output_type -> containerd.services.introspection.v1.ServerResponse + 8, // [8:10] is the sub-list for method output_type + 6, // [6:8] is the sub-list for method input_type + 6, // [6:6] is the sub-list for extension type_name + 6, // [6:6] is the sub-list for extension extendee + 0, // [0:6] is the sub-list for field type_name } func init() { @@ -501,6 +593,18 @@ func file_github_com_containerd_containerd_api_services_introspection_v1_introsp return nil } } + file_github_com_containerd_containerd_api_services_introspection_v1_introspection_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DeprecationWarning); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } } type x struct{} out := protoimpl.TypeBuilder{ @@ -508,7 +612,7 @@ func file_github_com_containerd_containerd_api_services_introspection_v1_introsp GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_github_com_containerd_containerd_api_services_introspection_v1_introspection_proto_rawDesc, NumEnums: 0, - NumMessages: 5, + NumMessages: 6, NumExtensions: 0, NumServices: 1, }, diff --git a/api/services/introspection/v1/introspection.proto b/api/services/introspection/v1/introspection.proto index 38864f1ec6d1..f27f1912e79d 100644 --- a/api/services/introspection/v1/introspection.proto +++ b/api/services/introspection/v1/introspection.proto @@ -21,6 +21,7 @@ package containerd.services.introspection.v1; import "github.com/containerd/containerd/api/types/platform.proto"; import "google/rpc/status.proto"; import "google/protobuf/empty.proto"; +import "google/protobuf/timestamp.proto"; option go_package = "github.com/containerd/containerd/api/services/introspection/v1;introspection"; @@ -102,4 +103,11 @@ message ServerResponse { string uuid = 1; uint64 pid = 2; uint64 pidns = 3; // PID namespace, such as 4026531836 + repeated DeprecationWarning deprecations = 4; } + +message DeprecationWarning { + string id = 1; + string message = 2; + google.protobuf.Timestamp last_occurrence = 3; +} \ No newline at end of file From 9aab446733b345402a7d13dfc1b8efb0d62fd295 Mon Sep 17 00:00:00 2001 From: Samuel Karp Date: Tue, 17 Oct 2023 22:34:59 -0700 Subject: [PATCH 4/8] introspection: add support for deprecations Deprecation warnings are retrieved from the warning service and returned via the Server RPC. Signed-off-by: Samuel Karp --- services/introspection/local.go | 73 ++++++++++++++++++++++++++------- 1 file changed, 58 insertions(+), 15 deletions(-) diff --git a/services/introspection/local.go b/services/introspection/local.go index 23cda5f08a96..78f421d741c3 100644 --- a/services/introspection/local.go +++ b/services/introspection/local.go @@ -18,11 +18,18 @@ package introspection import ( context "context" + "errors" "os" "path/filepath" "runtime" "sync" + "github.com/google/uuid" + "google.golang.org/genproto/googleapis/rpc/code" + rpc "google.golang.org/genproto/googleapis/rpc/status" + "google.golang.org/grpc" + "google.golang.org/grpc/status" + api "github.com/containerd/containerd/api/services/introspection/v1" "github.com/containerd/containerd/api/types" "github.com/containerd/containerd/errdefs" @@ -30,25 +37,42 @@ import ( "github.com/containerd/containerd/plugin" "github.com/containerd/containerd/plugin/registry" "github.com/containerd/containerd/plugins" + "github.com/containerd/containerd/protobuf" ptypes "github.com/containerd/containerd/protobuf/types" "github.com/containerd/containerd/services" - "github.com/google/uuid" - "google.golang.org/genproto/googleapis/rpc/code" - rpc "google.golang.org/genproto/googleapis/rpc/status" - "google.golang.org/grpc" - "google.golang.org/grpc/status" + "github.com/containerd/containerd/services/warning" ) func init() { registry.Register(&plugin.Registration{ Type: plugins.ServicePlugin, ID: services.IntrospectionService, - Requires: []plugin.Type{}, + Requires: []plugin.Type{plugins.WarningPlugin}, InitFn: func(ic *plugin.InitContext) (interface{}, error) { + sps, err := ic.GetByType(plugins.WarningPlugin) + if err != nil { + return nil, err + } + p, ok := sps[plugins.DeprecationsPlugin] + if !ok { + return nil, errors.New("warning service not found") + } + + i, err := p.Instance() + if err != nil { + return nil, err + } + + warningClient, ok := i.(warning.Service) + if !ok { + return nil, errors.New("could not create a local client for warning service") + } + // this service fetches all plugins through the plugin set of the plugin context return &Local{ - plugins: ic.Plugins(), - root: ic.Properties[plugins.PropertyRootDir], + plugins: ic.Plugins(), + root: ic.Properties[plugins.PropertyRootDir], + warningClient: warningClient, }, nil }, }) @@ -56,10 +80,11 @@ func init() { // Local is a local implementation of the introspection service type Local struct { - mu sync.Mutex - root string - plugins *plugin.Set - pluginCache []*api.Plugin + mu sync.Mutex + root string + plugins *plugin.Set + pluginCache []*api.Plugin + warningClient warning.Service } var _ = (api.IntrospectionClient)(&Local{}) @@ -117,9 +142,10 @@ func (l *Local) Server(ctx context.Context, _ *ptypes.Empty, _ ...grpc.CallOptio } } return &api.ServerResponse{ - UUID: u, - Pid: uint64(pid), - Pidns: pidns, + UUID: u, + Pid: uint64(pid), + Pidns: pidns, + Deprecations: l.getWarnings(ctx), }, nil } @@ -161,6 +187,10 @@ func (l *Local) uuidPath() string { return filepath.Join(l.root, "uuid") } +func (l *Local) getWarnings(ctx context.Context) []*api.DeprecationWarning { + return warningsPB(ctx, l.warningClient.Warnings()) +} + func adaptPlugin(o interface{}) filters.Adaptor { obj := o.(*api.Plugin) return filters.AdapterFunc(func(fieldpath []string) (string, bool) { @@ -233,3 +263,16 @@ func pluginsToPB(plugins []*plugin.Plugin) []*api.Plugin { return pluginsPB } + +func warningsPB(ctx context.Context, warnings []warning.Warning) []*api.DeprecationWarning { + var pb []*api.DeprecationWarning + + for _, w := range warnings { + pb = append(pb, &api.DeprecationWarning{ + ID: string(w.ID), + Message: w.Message, + LastOccurrence: protobuf.ToTimestamp(w.LastOccurrence), + }) + } + return pb +} From bc861b66f923b64b0351b26462beccfd9cf4154d Mon Sep 17 00:00:00 2001 From: Samuel Karp Date: Tue, 17 Oct 2023 22:46:30 -0700 Subject: [PATCH 5/8] pull: record deprecation warning for schema 1 Signed-off-by: Samuel Karp --- images/labels.go | 21 +++++++++++++++++++++ pull.go | 10 +++++----- services/images/local.go | 33 ++++++++++++++++++++++++++++----- 3 files changed, 54 insertions(+), 10 deletions(-) create mode 100644 images/labels.go diff --git a/images/labels.go b/images/labels.go new file mode 100644 index 000000000000..06dfed572d43 --- /dev/null +++ b/images/labels.go @@ -0,0 +1,21 @@ +/* + 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 images + +const ( + ConvertedDockerSchema1LabelKey = "io.containerd.image/converted-docker-schema1" +) diff --git a/pull.go b/pull.go index c35278aa2a30..d72702a5fb01 100644 --- a/pull.go +++ b/pull.go @@ -21,6 +21,9 @@ import ( "errors" "fmt" + ocispec "github.com/opencontainers/image-spec/specs-go/v1" + "golang.org/x/sync/semaphore" + "github.com/containerd/containerd/errdefs" "github.com/containerd/containerd/images" "github.com/containerd/containerd/pkg/unpack" @@ -29,13 +32,10 @@ import ( "github.com/containerd/containerd/remotes/docker" "github.com/containerd/containerd/remotes/docker/schema1" //nolint:staticcheck // Ignore SA1019. Need to keep deprecated package for compatibility. "github.com/containerd/containerd/tracing" - ocispec "github.com/opencontainers/image-spec/specs-go/v1" - "golang.org/x/sync/semaphore" ) const ( - pullSpanPrefix = "pull" - convertedDockerSchema1LabelKey = "io.containerd.image/converted-docker-schema1" + pullSpanPrefix = "pull" ) // Pull downloads the provided content into containerd's content store @@ -278,7 +278,7 @@ func (c *Client) fetch(ctx context.Context, rCtx *RemoteContext, ref string, lim if rCtx.Labels == nil { rCtx.Labels = make(map[string]string) } - rCtx.Labels[convertedDockerSchema1LabelKey] = originalSchema1Digest + rCtx.Labels[images.ConvertedDockerSchema1LabelKey] = originalSchema1Digest } return images.Image{ diff --git a/services/images/local.go b/services/images/local.go index 107232d41f50..c3b96b0bad24 100644 --- a/services/images/local.go +++ b/services/images/local.go @@ -19,6 +19,11 @@ package images import ( "context" + "github.com/containerd/log" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + eventstypes "github.com/containerd/containerd/api/events" imagesapi "github.com/containerd/containerd/api/services/images/v1" "github.com/containerd/containerd/errdefs" @@ -26,16 +31,14 @@ import ( "github.com/containerd/containerd/gc" "github.com/containerd/containerd/images" "github.com/containerd/containerd/metadata" + "github.com/containerd/containerd/pkg/deprecation" "github.com/containerd/containerd/pkg/epoch" "github.com/containerd/containerd/plugin" "github.com/containerd/containerd/plugin/registry" "github.com/containerd/containerd/plugins" ptypes "github.com/containerd/containerd/protobuf/types" "github.com/containerd/containerd/services" - "github.com/containerd/log" - "google.golang.org/grpc" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" + "github.com/containerd/containerd/services/warning" ) func init() { @@ -46,6 +49,7 @@ func init() { plugins.EventPlugin, plugins.MetadataPlugin, plugins.GCPlugin, + plugins.WarningPlugin, }, InitFn: func(ic *plugin.InitContext) (interface{}, error) { m, err := ic.Get(plugins.MetadataPlugin) @@ -56,16 +60,20 @@ func init() { if err != nil { return nil, err } - ep, err := ic.Get(plugins.EventPlugin) if err != nil { return nil, err } + w, err := ic.Get(plugins.WarningPlugin) + if err != nil { + return nil, err + } return &local{ store: metadata.NewImageStore(m.(*metadata.DB)), publisher: ep.(events.Publisher), gc: g.(gcScheduler), + warnings: w.(warning.Service), }, nil }, }) @@ -79,6 +87,7 @@ type local struct { store images.Store gc gcScheduler publisher events.Publisher + warnings warning.Service } var _ imagesapi.ImagesClient = &local{} @@ -134,6 +143,7 @@ func (l *local) Create(ctx context.Context, req *imagesapi.CreateImageRequest, _ return nil, err } + l.emitSchema1DeprecationWarning(ctx, &image) return &resp, nil } @@ -172,6 +182,7 @@ func (l *local) Update(ctx context.Context, req *imagesapi.UpdateImageRequest, _ return nil, err } + l.emitSchema1DeprecationWarning(ctx, &image) return &resp, nil } @@ -203,3 +214,15 @@ func (l *local) Delete(ctx context.Context, req *imagesapi.DeleteImageRequest, _ return &ptypes.Empty{}, nil } + +func (l *local) emitSchema1DeprecationWarning(ctx context.Context, image *images.Image) { + if image == nil { + return + } + dgst, ok := image.Labels[images.ConvertedDockerSchema1LabelKey] + if !ok { + return + } + log.G(ctx).WithField("name", image.Name).WithField("schema1digest", dgst).Warn("conversion from schema 1 images is deprecated") + l.warnings.Emit(ctx, deprecation.PullSchema1Image) +} From 260e71abc4a614196db99971983f11ba9b8b2043 Mon Sep 17 00:00:00 2001 From: Samuel Karp Date: Tue, 17 Oct 2023 14:21:52 -0700 Subject: [PATCH 6/8] server: add ability to record config deprecations Signed-off-by: Samuel Karp --- plugin/context.go | 13 ++++++++++ services/server/server.go | 50 +++++++++++++++++++++++++++++---------- 2 files changed, 51 insertions(+), 12 deletions(-) diff --git a/plugin/context.go b/plugin/context.go index de4457cb0f76..3f3364aaad8c 100644 --- a/plugin/context.go +++ b/plugin/context.go @@ -127,6 +127,19 @@ func (ps *Set) Get(t Type) (interface{}, error) { return nil, fmt.Errorf("no plugins registered for %s: %w", t, ErrPluginNotFound) } +// GetByID returns the plugin of the given type and ID +func (ps *Set) GetByID(t Type, id string) (*Plugin, error) { + typSet, ok := ps.byTypeAndID[t] + if !ok || len(typSet) == 0 { + return nil, fmt.Errorf("no plugins registered for %s: %w", t, ErrPluginNotFound) + } + p, ok := typSet[id] + if !ok { + return nil, fmt.Errorf("no plugins registered for %s %q: %w", t, id, ErrPluginNotFound) + } + return p, nil +} + // GetAll returns all initialized plugins func (ps *Set) GetAll() []*Plugin { return ps.ordered diff --git a/services/server/server.go b/services/server/server.go index 864deae56885..3b7f65526085 100644 --- a/services/server/server.go +++ b/services/server/server.go @@ -34,6 +34,18 @@ import ( "sync/atomic" "time" + "github.com/containerd/log" + "github.com/containerd/ttrpc" + "github.com/docker/go-metrics" + grpc_middleware "github.com/grpc-ecosystem/go-grpc-middleware" + grpc_prometheus "github.com/grpc-ecosystem/go-grpc-prometheus" + v1 "github.com/opencontainers/image-spec/specs-go/v1" + "go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc" + "google.golang.org/grpc" + "google.golang.org/grpc/backoff" + "google.golang.org/grpc/credentials" + "google.golang.org/grpc/credentials/insecure" + csapi "github.com/containerd/containerd/api/services/content/v1" diffapi "github.com/containerd/containerd/api/services/diff/v1" sbapi "github.com/containerd/containerd/api/services/sandbox/v1" @@ -52,19 +64,9 @@ import ( "github.com/containerd/containerd/plugins" sbproxy "github.com/containerd/containerd/sandbox/proxy" srvconfig "github.com/containerd/containerd/services/server/config" + "github.com/containerd/containerd/services/warning" ssproxy "github.com/containerd/containerd/snapshots/proxy" "github.com/containerd/containerd/sys" - "github.com/containerd/log" - "github.com/containerd/ttrpc" - "github.com/docker/go-metrics" - grpc_middleware "github.com/grpc-ecosystem/go-grpc-middleware" - grpc_prometheus "github.com/grpc-ecosystem/go-grpc-prometheus" - v1 "github.com/opencontainers/image-spec/specs-go/v1" - "go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc" - "google.golang.org/grpc" - "google.golang.org/grpc/backoff" - "google.golang.org/grpc/credentials" - "google.golang.org/grpc/credentials/insecure" ) // CreateTopLevelDirectories creates the top-level root and state directories. @@ -330,9 +332,33 @@ func New(ctx context.Context, config *srvconfig.Config) (*Server, error) { return nil, err } } + + recordConfigDeprecations(ctx, config, initialized) return s, nil } +// recordConfigDeprecations attempts to record use of any deprecated config field. Failures are logged and ignored. +func recordConfigDeprecations(ctx context.Context, config *srvconfig.Config, set *plugin.Set) { + // record any detected deprecations without blocking server startup + plugin, err := set.GetByID(plugins.WarningPlugin, plugins.DeprecationsPlugin) + if err != nil { + log.G(ctx).WithError(err).Warn("failed to load warning service to record deprecations") + return + } + instance, err := plugin.Instance() + if err != nil { + log.G(ctx).WithError(err).Warn("failed to load warning service to record deprecations") + return + } + warn, ok := instance.(warning.Service) + if !ok { + log.G(ctx).WithError(err).Warn("failed to load warning service to record deprecations, unexpected plugin type") + return + } + + _ = warn // TODO(samuelkarp): placeholder for future use +} + // Server is the containerd main daemon type Server struct { grpcServer *grpc.Server @@ -433,7 +459,7 @@ func (s *Server) Wait() { // of all plugins. func LoadPlugins(ctx context.Context, config *srvconfig.Config) ([]plugin.Registration, error) { // load all plugins into containerd - path := config.PluginDir //nolint: staticcheck + path := config.PluginDir // nolint: staticcheck if path == "" { path = filepath.Join(config.Root, "plugins") } From 079383dbec05fb07e506b31ff68c1589b6fba0ba Mon Sep 17 00:00:00 2001 From: Samuel Karp Date: Tue, 17 Oct 2023 23:36:43 -0700 Subject: [PATCH 7/8] dynamic: record deprecation for dynamic plugins Signed-off-by: Samuel Karp --- plugin/dynamic/dynamic.go | 2 +- plugin/dynamic/dynamic_supported.go | 17 ++++++++++------- plugin/dynamic/dynamic_unsupported.go | 4 ++-- services/server/server.go | 13 +++++++++---- services/warning/service.go | 10 ---------- 5 files changed, 22 insertions(+), 24 deletions(-) diff --git a/plugin/dynamic/dynamic.go b/plugin/dynamic/dynamic.go index 30b4423a13b7..653b757400ba 100644 --- a/plugin/dynamic/dynamic.go +++ b/plugin/dynamic/dynamic.go @@ -23,7 +23,7 @@ import "fmt" // Load is currently only implemented on non-static, non-gccgo builds for amd64 // and arm64, and plugins must be built with the exact same version of Go as // containerd itself. -func Load(path string) (err error) { +func Load(path string) (loaded int, err error) { defer func() { if v := recover(); v != nil { rerr, ok := v.(error) diff --git a/plugin/dynamic/dynamic_supported.go b/plugin/dynamic/dynamic_supported.go index eff7e597f40a..0308ac9b5e7e 100644 --- a/plugin/dynamic/dynamic_supported.go +++ b/plugin/dynamic/dynamic_supported.go @@ -25,12 +25,13 @@ import ( "runtime" ) -// loadPlugins loads all plugins for the OS and Arch -// that containerd is built for inside the provided path -func loadPlugins(path string) error { +// loadPlugins loads all plugins for the OS and Arch that containerd is built +// for inside the provided path and returns the count of successfully-loaded +// plugins +func loadPlugins(path string) (int, error) { abs, err := filepath.Abs(path) if err != nil { - return err + return 0, err } pattern := filepath.Join(abs, fmt.Sprintf( "*-%s-%s.%s", @@ -40,14 +41,16 @@ func loadPlugins(path string) error { )) libs, err := filepath.Glob(pattern) if err != nil { - return err + return 0, err } + loaded := 0 for _, lib := range libs { if _, err := plugin.Open(lib); err != nil { - return err + return loaded, err } + loaded++ } - return nil + return loaded, nil } // getLibExt returns a platform specific lib extension for diff --git a/plugin/dynamic/dynamic_unsupported.go b/plugin/dynamic/dynamic_unsupported.go index ccef3d37f18c..556569407c04 100644 --- a/plugin/dynamic/dynamic_unsupported.go +++ b/plugin/dynamic/dynamic_unsupported.go @@ -23,6 +23,6 @@ package dynamic // - with gccgo: gccgo has no plugin support golang/go#36403 // - on static builds; https://github.com/containerd/containerd/commit/0d682e24a1ba8e93e5e54a73d64f7d256f87492f // - on architectures other than amd64 and arm64 (other architectures need to be tested) -func loadPlugins(path string) error { - return nil +func loadPlugins(path string) (int, error) { + return 0, nil } diff --git a/services/server/server.go b/services/server/server.go index 3b7f65526085..75919a622555 100644 --- a/services/server/server.go +++ b/services/server/server.go @@ -55,6 +55,7 @@ import ( "github.com/containerd/containerd/defaults" "github.com/containerd/containerd/diff" diffproxy "github.com/containerd/containerd/diff/proxy" + "github.com/containerd/containerd/pkg/deprecation" "github.com/containerd/containerd/pkg/dialer" "github.com/containerd/containerd/pkg/timeout" "github.com/containerd/containerd/platforms" @@ -356,7 +357,9 @@ func recordConfigDeprecations(ctx context.Context, config *srvconfig.Config, set return } - _ = warn // TODO(samuelkarp): placeholder for future use + if config.PluginDir != "" { //nolint:staticcheck + warn.Emit(ctx, deprecation.GoPluginLibrary) + } } // Server is the containerd main daemon @@ -459,13 +462,15 @@ func (s *Server) Wait() { // of all plugins. func LoadPlugins(ctx context.Context, config *srvconfig.Config) ([]plugin.Registration, error) { // load all plugins into containerd - path := config.PluginDir // nolint: staticcheck + path := config.PluginDir //nolint:staticcheck if path == "" { path = filepath.Join(config.Root, "plugins") } - log.G(ctx).Warning("`go_plugin` is deprecated, please use `external plugins` instead") - if err := dynamic.Load(path); err != nil { + if count, err := dynamic.Load(path); err != nil { return nil, err + } else if count > 0 || config.PluginDir != "" { //nolint:staticcheck + config.PluginDir = path //nolint:staticcheck + log.G(ctx).Warningf("loaded %d dynamic plugins. `go_plugin` is deprecated, please use `external plugins` instead", count) } // load additional plugins that don't automatically register themselves registry.Register(&plugin.Registration{ diff --git a/services/warning/service.go b/services/warning/service.go index dc35bc423a94..f5bb1949899f 100644 --- a/services/warning/service.go +++ b/services/warning/service.go @@ -52,16 +52,6 @@ type Warning struct { var _ Service = (*service)(nil) -func init() { - registry.Register(&plugin.Registration{ - Type: plugins.InternalPlugin, - ID: "warning", - InitFn: func(ic *plugin.InitContext) (interface{}, error) { - return &service{warnings: make(map[deprecation.Warning]time.Time)}, nil - }, - }) -} - type service struct { warnings map[deprecation.Warning]time.Time m sync.RWMutex From 3fff8b4f622e47d05f8acc52dbe8e897792ac547 Mon Sep 17 00:00:00 2001 From: Samuel Karp Date: Tue, 17 Oct 2023 11:20:31 -0700 Subject: [PATCH 8/8] ctr: new deprecations command Signed-off-by: Samuel Karp --- cmd/ctr/app/main.go | 9 +- cmd/ctr/commands/deprecations/deprecations.go | 113 ++++++++++++++++++ 2 files changed, 119 insertions(+), 3 deletions(-) create mode 100644 cmd/ctr/commands/deprecations/deprecations.go diff --git a/cmd/ctr/app/main.go b/cmd/ctr/app/main.go index 0a740dd1ba9c..6def240474be 100644 --- a/cmd/ctr/app/main.go +++ b/cmd/ctr/app/main.go @@ -20,8 +20,13 @@ import ( "fmt" "io" + "github.com/containerd/log" + "github.com/urfave/cli" + "google.golang.org/grpc/grpclog" + "github.com/containerd/containerd/cmd/ctr/commands/containers" "github.com/containerd/containerd/cmd/ctr/commands/content" + "github.com/containerd/containerd/cmd/ctr/commands/deprecations" "github.com/containerd/containerd/cmd/ctr/commands/events" "github.com/containerd/containerd/cmd/ctr/commands/images" "github.com/containerd/containerd/cmd/ctr/commands/info" @@ -39,9 +44,6 @@ import ( "github.com/containerd/containerd/defaults" "github.com/containerd/containerd/namespaces" "github.com/containerd/containerd/version" - "github.com/containerd/log" - "github.com/urfave/cli" - "google.golang.org/grpc/grpclog" ) var extraCmds = []cli.Command{} @@ -118,6 +120,7 @@ containerd CLI ociCmd.Command, sandboxes.Command, info.Command, + deprecations.Command, }, extraCmds...) app.Before = func(context *cli.Context) error { if context.GlobalBool("debug") { diff --git a/cmd/ctr/commands/deprecations/deprecations.go b/cmd/ctr/commands/deprecations/deprecations.go new file mode 100644 index 000000000000..bd35349261ec --- /dev/null +++ b/cmd/ctr/commands/deprecations/deprecations.go @@ -0,0 +1,113 @@ +/* + 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 deprecations + +import ( + "fmt" + "os" + "text/tabwriter" + "time" + + "github.com/urfave/cli" + + api "github.com/containerd/containerd/api/services/introspection/v1" + "github.com/containerd/containerd/cmd/ctr/commands" + "github.com/containerd/containerd/protobuf" + ptypes "github.com/containerd/containerd/protobuf/types" +) + +// Command is the parent for all commands under "deprecations" +var Command = cli.Command{ + Name: "deprecations", + Subcommands: []cli.Command{ + listCommand, + }, +} +var listCommand = cli.Command{ + Name: "list", + Usage: "Print warnings for deprecations", + Flags: []cli.Flag{ + cli.StringFlag{ + Name: "format", + Usage: "output format to use (Examples: 'default', 'json')", + }, + }, + Action: func(context *cli.Context) error { + client, ctx, cancel, err := commands.NewClient(context) + if err != nil { + return err + } + defer cancel() + + resp, err := client.IntrospectionService().Server(ctx, &ptypes.Empty{}) + if err != nil { + return err + } + wrn := warnings(resp) + if len(wrn) > 0 { + switch context.String("format") { + case "json": + commands.PrintAsJSON(warnings(resp)) + return nil + default: + w := tabwriter.NewWriter(os.Stdout, 4, 8, 4, ' ', 0) + fmt.Fprintln(w, "ID\tLAST OCCURRENCE\tMESSAGE\t") + for _, dw := range wrn { + if _, err := fmt.Fprintf(w, "%s\t%s\t%s\n", + dw.ID, + dw.LastOccurrence.Format(time.RFC3339Nano), + dw.Message, + ); err != nil { + return err + } + } + return w.Flush() + } + + } + return nil + }, +} + +type deprecationWarning struct { + ID string `json:"id"` + Message string `json:"message"` + LastOccurrence time.Time `json:"lastOccurrence"` +} + +func warnings(in *api.ServerResponse) []deprecationWarning { + var warnings []deprecationWarning + for _, dw := range in.Deprecations { + wrn := deprecationWarningFromPB(dw) + if wrn == nil { + continue + } + warnings = append(warnings, *wrn) + } + return warnings +} +func deprecationWarningFromPB(in *api.DeprecationWarning) *deprecationWarning { + if in == nil { + return nil + } + lo := protobuf.FromTimestamp(in.LastOccurrence) + return &deprecationWarning{ + ID: in.ID, + Message: in.Message, + LastOccurrence: lo, + } +}