diff --git a/cmd/containerd/builtins/builtins.go b/cmd/containerd/builtins/builtins.go index a5232abcc..0a0e09d7f 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 2f25f8c51..4524a7e90 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 000000000..dc35bc423 --- /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 +}