Skip to content

Commit 9547d26

Browse files
committed
Add v2 server config support with plugin URIs
Closes #3210 Signed-off-by: Michael Crosby <[email protected]>
1 parent 42f4bb9 commit 9547d26

10 files changed

Lines changed: 147 additions & 33 deletions

File tree

.travis.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,11 @@ script:
7474
- go build -i .
7575
- make check
7676
- if [ "$GOOS" = "linux" ]; then make check-protos check-api-descriptors; fi
77+
- |
78+
sudo mkdir -p /etc/containerd
79+
sudo bash -c "cat > /etc/containerd/config.toml <<EOF
80+
version = 1
81+
EOF"
7782
- make build
7883
- make binaries
7984
- if [ "$TRAVIS_GOOS" = "linux" ]; then sudo make install ; fi
@@ -86,6 +91,7 @@ script:
8691
if [ "$TRAVIS_GOOS" = "linux" ]; then
8792
sudo mkdir -p /etc/containerd
8893
sudo bash -c "cat > /etc/containerd/config.toml <<EOF
94+
version = 1
8995
[plugins.cri.containerd.default_runtime]
9096
runtime_type = \"${TEST_RUNTIME}\"
9197
EOF"

client_test.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -390,6 +390,10 @@ func createShimDebugConfig() string {
390390
os.Exit(1)
391391
}
392392
defer f.Close()
393+
if _, err := f.WriteString("version = 1\n"); err != nil {
394+
fmt.Fprintf(os.Stderr, "Failed to write to config file %s: %s\n", f.Name(), err)
395+
os.Exit(1)
396+
}
393397

394398
if _, err := f.WriteString("[plugins.linux]\n\tshim_debug = true\n"); err != nil {
395399
fmt.Fprintf(os.Stderr, "Failed to write to config file %s: %s\n", f.Name(), err)

cmd/containerd/command/config.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ var configCommand = cli.Command{
6060
if p.Config == nil {
6161
continue
6262
}
63-
config.Plugins[p.ID] = p.Config
63+
config.Plugins[p.URI()] = p.Config
6464
}
6565
}
6666
_, err = config.WriteTo(os.Stdout)

cmd/containerd/command/config_linux.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,9 @@ import (
2323

2424
func defaultConfig() *srvconfig.Config {
2525
return &srvconfig.Config{
26-
Root: defaults.DefaultRootDir,
27-
State: defaults.DefaultStateDir,
26+
Version: 2,
27+
Root: defaults.DefaultRootDir,
28+
State: defaults.DefaultStateDir,
2829
GRPC: srvconfig.GRPCConfig{
2930
Address: defaults.DefaultAddress,
3031
MaxRecvMsgSize: defaults.DefaultMaxRecvMsgSize,

cmd/containerd/command/config_unsupported.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,9 @@ import (
2525

2626
func defaultConfig() *srvconfig.Config {
2727
return &srvconfig.Config{
28-
Root: defaults.DefaultRootDir,
29-
State: defaults.DefaultStateDir,
28+
Version: 2,
29+
Root: defaults.DefaultRootDir,
30+
State: defaults.DefaultStateDir,
3031
GRPC: srvconfig.GRPCConfig{
3132
Address: defaults.DefaultAddress,
3233
},

cmd/containerd/command/config_windows.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,9 @@ import (
2323

2424
func defaultConfig() *srvconfig.Config {
2525
return &srvconfig.Config{
26-
Root: defaults.DefaultRootDir,
27-
State: defaults.DefaultStateDir,
26+
Version: 2,
27+
Root: defaults.DefaultRootDir,
28+
State: defaults.DefaultStateDir,
2829
GRPC: srvconfig.GRPCConfig{
2930
Address: defaults.DefaultAddress,
3031
MaxRecvMsgSize: defaults.DefaultMaxRecvMsgSize,

daemon_config_linux_test.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@ func TestDaemonRuntimeRoot(t *testing.T) {
127127
}
128128
}()
129129
configTOML := `
130+
version = 1
130131
[plugins]
131132
[plugins.cri]
132133
stream_server_port = "0"
@@ -221,6 +222,7 @@ func TestDaemonCustomCgroup(t *testing.T) {
221222

222223
customCgroup := fmt.Sprintf("%d", time.Now().Nanosecond())
223224
configTOML := `
225+
version = 1
224226
[cgroup]
225227
path = "` + customCgroup + `"`
226228

plugin/plugin.go

Lines changed: 35 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,8 @@ var (
3030
ErrNoType = errors.New("plugin: no type")
3131
// ErrNoPluginID is returned when no id is specified
3232
ErrNoPluginID = errors.New("plugin: no id")
33-
33+
// ErrIDRegistered is returned when a duplicate id is already registered
34+
ErrIDRegistered = errors.New("plugin: id already registered")
3435
// ErrSkipPlugin is used when a plugin is not initialized and should not be loaded,
3536
// this allows the plugin loader differentiate between a plugin which is configured
3637
// not to load and one that fails to load.
@@ -100,6 +101,8 @@ type Registration struct {
100101
// context are passed in. The init function may modify the registration to
101102
// add exports, capabilities and platform support declarations.
102103
InitFn func(*InitContext) (interface{}, error)
104+
// Disable the plugin from loading
105+
Disable bool
103106
}
104107

105108
// Init the registered plugin
@@ -157,12 +160,16 @@ func Load(path string) (err error) {
157160
func Register(r *Registration) {
158161
register.Lock()
159162
defer register.Unlock()
163+
160164
if r.Type == "" {
161165
panic(ErrNoType)
162166
}
163167
if r.ID == "" {
164168
panic(ErrNoPluginID)
165169
}
170+
if err := checkUnique(r); err != nil {
171+
panic(err)
172+
}
166173

167174
var last bool
168175
for _, requires := range r.Requires {
@@ -177,24 +184,36 @@ func Register(r *Registration) {
177184
register.r = append(register.r, r)
178185
}
179186

187+
func checkUnique(r *Registration) error {
188+
for _, registered := range register.r {
189+
if r.URI() == registered.URI() {
190+
return errors.Wrap(ErrIDRegistered, r.URI())
191+
}
192+
}
193+
return nil
194+
}
195+
196+
// DisableFilter filters out disabled plugins
197+
type DisableFilter func(r *Registration) bool
198+
180199
// Graph returns an ordered list of registered plugins for initialization.
181200
// Plugins in disableList specified by id will be disabled.
182-
func Graph(disableList []string) (ordered []*Registration) {
201+
func Graph(filter DisableFilter) (ordered []*Registration) {
183202
register.RLock()
184203
defer register.RUnlock()
185-
for _, d := range disableList {
186-
for i, r := range register.r {
187-
if r.ID == d {
188-
register.r = append(register.r[:i], register.r[i+1:]...)
189-
break
190-
}
204+
205+
for _, r := range register.r {
206+
if filter(r) {
207+
r.Disable = true
191208
}
192209
}
193210

194211
added := map[*Registration]bool{}
195212
for _, r := range register.r {
196-
197-
children(r.ID, r.Requires, added, &ordered)
213+
if r.Disable {
214+
continue
215+
}
216+
children(r, added, &ordered)
198217
if !added[r] {
199218
ordered = append(ordered, r)
200219
added[r] = true
@@ -203,11 +222,13 @@ func Graph(disableList []string) (ordered []*Registration) {
203222
return ordered
204223
}
205224

206-
func children(id string, types []Type, added map[*Registration]bool, ordered *[]*Registration) {
207-
for _, t := range types {
225+
func children(reg *Registration, added map[*Registration]bool, ordered *[]*Registration) {
226+
for _, t := range reg.Requires {
208227
for _, r := range register.r {
209-
if r.ID != id && (t == "*" || r.Type == t) {
210-
children(r.ID, r.Requires, added, ordered)
228+
if !r.Disable &&
229+
r.URI() != reg.URI() &&
230+
(t == "*" || r.Type == t) {
231+
children(r, added, ordered)
211232
if !added[r] {
212233
*ordered = append(*ordered, r)
213234
added[r] = true

services/server/config/config.go

Lines changed: 74 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,18 @@
1717
package config
1818

1919
import (
20+
"strings"
21+
2022
"github.com/BurntSushi/toml"
2123
"github.com/containerd/containerd/errdefs"
24+
"github.com/containerd/containerd/plugin"
2225
"github.com/pkg/errors"
2326
)
2427

2528
// Config provides containerd configuration data for the server
2629
type Config struct {
30+
// Version of the config file
31+
Version int `toml:"version"`
2732
// Root is the path to a directory where containerd will store persistent data
2833
Root string `toml:"root"`
2934
// State is the path to a directory where containerd will store transient data
@@ -54,6 +59,42 @@ type Config struct {
5459
md toml.MetaData
5560
}
5661

62+
// GetVersion returns the config file's version
63+
func (c *Config) GetVersion() int {
64+
if c.Version == 0 {
65+
return 1
66+
}
67+
return c.Version
68+
}
69+
70+
// ValidateV2 validates the config for a v2 file
71+
func (c *Config) ValidateV2() error {
72+
if c.GetVersion() != 2 {
73+
return nil
74+
}
75+
for _, p := range c.DisabledPlugins {
76+
if len(strings.Split(p, ".")) < 4 {
77+
return errors.Errorf("invalid disabled plugin URI %q expect io.containerd.x.vx", p)
78+
}
79+
}
80+
for _, p := range c.RequiredPlugins {
81+
if len(strings.Split(p, ".")) < 4 {
82+
return errors.Errorf("invalid required plugin URI %q expect io.containerd.x.vx", p)
83+
}
84+
}
85+
for p := range c.Plugins {
86+
if len(strings.Split(p, ".")) < 4 {
87+
return errors.Errorf("invalid plugin key URI %q expect io.containerd.x.vx", p)
88+
}
89+
}
90+
for p := range c.ProxyPlugins {
91+
if len(strings.Split(p, ".")) < 4 {
92+
return errors.Errorf("invalid proxy plugin key URI %q expect io.containerd.x.vx", p)
93+
}
94+
}
95+
return nil
96+
}
97+
5798
// GRPCConfig provides GRPC configuration for the socket
5899
type GRPCConfig struct {
59100
Address string `toml:"address"`
@@ -130,15 +171,19 @@ func (bc *BoltConfig) Validate() error {
130171
}
131172

132173
// Decode unmarshals a plugin specific configuration by plugin id
133-
func (c *Config) Decode(id string, v interface{}) (interface{}, error) {
174+
func (c *Config) Decode(p *plugin.Registration) (interface{}, error) {
175+
id := p.URI()
176+
if c.GetVersion() == 1 {
177+
id = p.ID
178+
}
134179
data, ok := c.Plugins[id]
135180
if !ok {
136-
return v, nil
181+
return p.Config, nil
137182
}
138-
if err := c.md.PrimitiveDecode(data, v); err != nil {
183+
if err := c.md.PrimitiveDecode(data, p.Config); err != nil {
139184
return nil, err
140185
}
141-
return v, nil
186+
return p.Config, nil
142187
}
143188

144189
// LoadConfig loads the containerd server config from the provided path
@@ -151,5 +196,29 @@ func LoadConfig(path string, v *Config) error {
151196
return err
152197
}
153198
v.md = md
154-
return nil
199+
return v.ValidateV2()
200+
}
201+
202+
// V1DisabledFilter matches based on ID
203+
func V1DisabledFilter(list []string) plugin.DisableFilter {
204+
set := make(map[string]struct{}, len(list))
205+
for _, l := range list {
206+
set[l] = struct{}{}
207+
}
208+
return func(r *plugin.Registration) bool {
209+
_, ok := set[r.ID]
210+
return ok
211+
}
212+
}
213+
214+
// V2DisabledFilter matches based on URI
215+
func V2DisabledFilter(list []string) plugin.DisableFilter {
216+
set := make(map[string]struct{}, len(list))
217+
for _, l := range list {
218+
set[l] = struct{}{}
219+
}
220+
return func(r *plugin.Registration) bool {
221+
_, ok := set[r.URI()]
222+
return ok
223+
}
155224
}

services/server/server.go

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,10 @@ func New(ctx context.Context, config *srvconfig.Config) (*Server, error) {
126126
}
127127
for _, p := range plugins {
128128
id := p.URI()
129+
reqID := id
130+
if config.GetVersion() == 1 {
131+
reqID = p.ID
132+
}
129133
log.G(ctx).WithField("type", p.Type).Infof("loading plugin %q...", id)
130134

131135
initContext := plugin.NewContext(
@@ -140,11 +144,11 @@ func New(ctx context.Context, config *srvconfig.Config) (*Server, error) {
140144

141145
// load the plugin specific configuration if it is provided
142146
if p.Config != nil {
143-
pluginConfig, err := config.Decode(p.ID, p.Config)
147+
pc, err := config.Decode(p)
144148
if err != nil {
145149
return nil, err
146150
}
147-
initContext.Config = pluginConfig
151+
initContext.Config = pc
148152
}
149153
result := p.Init(initContext)
150154
if err := initialized.Add(result); err != nil {
@@ -158,12 +162,13 @@ func New(ctx context.Context, config *srvconfig.Config) (*Server, error) {
158162
} else {
159163
log.G(ctx).WithError(err).Warnf("failed to load plugin %s", id)
160164
}
161-
if _, ok := required[p.ID]; ok {
165+
if _, ok := required[reqID]; ok {
162166
return nil, errors.Wrapf(err, "load required plugin %s", id)
163167
}
164168
continue
165169
}
166-
delete(required, p.ID)
170+
171+
delete(required, reqID)
167172
// check for grpc services that should be registered with the server
168173
if src, ok := instance.(plugin.Service); ok {
169174
grpcServices = append(grpcServices, src)
@@ -266,7 +271,7 @@ func (s *Server) Stop() {
266271
p := s.plugins[i]
267272
instance, err := p.Instance()
268273
if err != nil {
269-
log.L.WithError(err).WithField("id", p.Registration.ID).
274+
log.L.WithError(err).WithField("id", p.Registration.URI()).
270275
Errorf("could not get plugin instance")
271276
continue
272277
}
@@ -275,7 +280,7 @@ func (s *Server) Stop() {
275280
continue
276281
}
277282
if err := closer.Close(); err != nil {
278-
log.L.WithError(err).WithField("id", p.Registration.ID).
283+
log.L.WithError(err).WithField("id", p.Registration.URI()).
279284
Errorf("failed to close plugin")
280285
}
281286
}
@@ -415,8 +420,12 @@ func LoadPlugins(ctx context.Context, config *srvconfig.Config) ([]*plugin.Regis
415420

416421
}
417422

423+
filter := srvconfig.V2DisabledFilter
424+
if config.GetVersion() == 1 {
425+
filter = srvconfig.V1DisabledFilter
426+
}
418427
// return the ordered graph for plugins
419-
return plugin.Graph(config.DisabledPlugins), nil
428+
return plugin.Graph(filter(config.DisabledPlugins)), nil
420429
}
421430

422431
type proxyClients struct {

0 commit comments

Comments
 (0)