Skip to content

Commit 4e16af7

Browse files
committed
adaptation: implement wrapper for old plugins.
Add a backward compatibility wrapper for old plugins which do not support the full set of dedicated lifecycle events yet. Fall back to relaying StateChange events to them. Record deprecation warnings for each unimplemented new plugin interface where we need to fall back and funnel calls through the old StateChange RPC call. Signed-off-by: Krisztian Litkey <krisztian.litkey@intel.com>
1 parent 299a3ee commit 4e16af7

5 files changed

Lines changed: 289 additions & 14 deletions

File tree

pkg/adaptation/adaptation.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ type Adaptation struct {
7676
syncLock sync.RWMutex
7777
wasmService *api.PluginPlugin
7878
metrics Metrics
79+
deprecation DeprecationRecorder
7980
}
8081

8182
var (
@@ -158,6 +159,15 @@ func WithDefaultValidator(cfg *validator.DefaultValidatorConfig) Option {
158159
}
159160
}
160161

162+
// WithDeprecationRecorder sets up functions to record usage of deprecated
163+
// NRI interfaces or features.
164+
func WithDeprecationRecorder(d DeprecationRecorder) Option {
165+
return func(r *Adaptation) error {
166+
r.deprecation = d
167+
return nil
168+
}
169+
}
170+
161171
// New creates a new NRI Runtime.
162172
func New(name, version string, syncFn SyncFn, updateFn UpdateFn, opts ...Option) (*Adaptation, error) {
163173
var err error

pkg/adaptation/api.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ type (
109109
SecurityProfile = api.SecurityProfile
110110
User = api.User
111111

112+
Event = api.Event
112113
EventMask = api.EventMask
113114
)
114115

pkg/adaptation/deprecations.go

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/*
2+
Copyright The containerd Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package adaptation
18+
19+
import (
20+
"context"
21+
"fmt"
22+
)
23+
24+
// DeprecationRecorder is the interface for recording NRI deprecation warnings.
25+
type DeprecationRecorder interface {
26+
// PluginWarning records a warning for a plugin.
27+
PluginWarning(ctx context.Context, d Deprecation, plugin, details string)
28+
}
29+
30+
// Deprecation is the type for NRI deprecations.
31+
type Deprecation int
32+
33+
const (
34+
// DeprecatedStateChange indicates that a plugin does not implement per
35+
// request RPC calls, using the deprecated StateChange instead.
36+
DeprecatedStateChange Deprecation = iota + 1
37+
)
38+
39+
func (d Deprecation) String() string {
40+
switch d {
41+
case DeprecatedStateChange:
42+
return "deprecated StateChange"
43+
default:
44+
return fmt.Sprintf("unknown deprecation (%d)", d)
45+
}
46+
}

pkg/adaptation/plugin.go

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -629,6 +629,7 @@ func (p *plugin) runPodSandbox(ctx context.Context, req *RunPodSandboxRequest) (
629629
}
630630
return nil, err
631631
}
632+
p.warnDeprecatedEvent(ctx, event)
632633

633634
return rpl, nil
634635
}
@@ -681,6 +682,7 @@ func (p *plugin) postUpdatePodSandbox(ctx context.Context, req *PostUpdatePodSan
681682
}
682683
return nil, err
683684
}
685+
p.warnDeprecatedEvent(ctx, event)
684686

685687
return &PostUpdatePodSandboxResponse{}, nil
686688
}
@@ -707,6 +709,7 @@ func (p *plugin) stopPodSandbox(ctx context.Context, req *StopPodSandboxRequest)
707709
}
708710
return nil, err
709711
}
712+
p.warnDeprecatedEvent(ctx, event)
710713

711714
return &StopPodSandboxResponse{}, nil
712715
}
@@ -733,6 +736,7 @@ func (p *plugin) removePodSandbox(ctx context.Context, req *RemovePodSandboxRequ
733736
}
734737
return nil, err
735738
}
739+
p.warnDeprecatedEvent(ctx, event)
736740

737741
return &RemovePodSandboxResponse{}, nil
738742
}
@@ -788,6 +792,7 @@ func (p *plugin) postCreateContainer(ctx context.Context, req *PostCreateContain
788792
}
789793
return nil, err
790794
}
795+
p.warnDeprecatedEvent(ctx, event)
791796

792797
return &PostCreateContainerResponse{}, nil
793798
}
@@ -814,6 +819,7 @@ func (p *plugin) startContainer(ctx context.Context, req *StartContainerRequest)
814819
}
815820
return nil, err
816821
}
822+
p.warnDeprecatedEvent(ctx, event)
817823

818824
return &StartContainerResponse{}, nil
819825
}
@@ -840,6 +846,7 @@ func (p *plugin) postStartContainer(ctx context.Context, req *PostStartContainer
840846
}
841847
return nil, err
842848
}
849+
p.warnDeprecatedEvent(ctx, event)
843850

844851
return &PostStartContainerResponse{}, nil
845852
}
@@ -895,6 +902,7 @@ func (p *plugin) postUpdateContainer(ctx context.Context, req *PostUpdateContain
895902
}
896903
return nil, err
897904
}
905+
p.warnDeprecatedEvent(ctx, event)
898906

899907
return &PostUpdateContainerResponse{}, nil
900908
}
@@ -950,6 +958,7 @@ func (p *plugin) removeContainer(ctx context.Context, req *RemoveContainerReques
950958
}
951959
return nil, err
952960
}
961+
p.warnDeprecatedEvent(ctx, event)
953962

954963
return &RemoveContainerResponse{}, nil
955964
}
@@ -990,6 +999,25 @@ func (p *plugin) recordAdjustments(op string, adjust *ContainerAdjustment, updat
990999
p.r.metrics.RecordPluginAdjustments(p.name(), op, adjust, updates, evicts)
9911000
}
9921001

1002+
// Warn about a plugins using deprecated StateChange for event handling.
1003+
func (p *plugin) warnDeprecatedEvent(ctx context.Context, event Event) {
1004+
if !p.impl.deprecated[event] || p.impl.warned[event] {
1005+
return
1006+
}
1007+
1008+
if p.r.deprecation != nil {
1009+
p.r.deprecation.PluginWarning(ctx, DeprecatedStateChange, p.name(),
1010+
fmt.Sprintf("does not implement a dedicated %s RPC call", event.PrettyName()))
1011+
} else {
1012+
log.Warnf(ctx, "plugin %s uses deprecated StateChange instead of a dedicated %s RPC call",
1013+
p.name(), event.PrettyName())
1014+
log.Warnf(ctx, "please update %s with a newer version of NRI for future compatibility",
1015+
p.name())
1016+
}
1017+
1018+
p.impl.warned[event] = true
1019+
}
1020+
9931021
// isFatalError returns true if the error is fatal and the plugin connection should be closed.
9941022
func isFatalError(err error) bool {
9951023
switch {
@@ -1001,8 +1029,6 @@ func isFatalError(err error) bool {
10011029
return true
10021030
case errors.Is(err, context.DeadlineExceeded):
10031031
return true
1004-
case status.Code(err) == codes.Unimplemented:
1005-
return true
10061032
}
10071033
return false
10081034
}

0 commit comments

Comments
 (0)