Skip to content

Commit 642f1ce

Browse files
authored
Merge pull request #123 from MikeZappa87/issue/supportstatus
Support CNI STATUS Verb
2 parents 9fbd439 + 208eca9 commit 642f1ce

File tree

3 files changed

+155
-38
lines changed

3 files changed

+155
-38
lines changed

cni.go

+33-6
Original file line numberDiff line numberDiff line change
@@ -135,11 +135,20 @@ func (c *libcni) Load(opts ...Opt) error {
135135

136136
// Status returns the status of CNI initialization.
137137
func (c *libcni) Status() error {
138+
if err := c.ready(); err != nil {
139+
return err
140+
}
138141
c.RLock()
139142
defer c.RUnlock()
140-
if len(c.networks) < c.networkCount {
141-
return ErrCNINotInitialized
143+
// STATUS is only called for CNI Version 1.1.0 or greater. It is ignored for previous versions.
144+
for _, v := range c.networks {
145+
err := c.cniConfig.GetStatusNetworkList(context.Background(), v.config)
146+
147+
if err != nil {
148+
return err
149+
}
142150
}
151+
143152
return nil
144153
}
145154

@@ -153,9 +162,11 @@ func (c *libcni) Networks() []*Network {
153162

154163
// Setup setups the network in the namespace and returns a Result
155164
func (c *libcni) Setup(ctx context.Context, id string, path string, opts ...NamespaceOpts) (*Result, error) {
156-
if err := c.Status(); err != nil {
165+
if err := c.ready(); err != nil {
157166
return nil, err
158167
}
168+
c.RLock()
169+
defer c.RUnlock()
159170
ns, err := newNamespace(id, path, opts...)
160171
if err != nil {
161172
return nil, err
@@ -169,9 +180,11 @@ func (c *libcni) Setup(ctx context.Context, id string, path string, opts ...Name
169180

170181
// SetupSerially setups the network in the namespace and returns a Result
171182
func (c *libcni) SetupSerially(ctx context.Context, id string, path string, opts ...NamespaceOpts) (*Result, error) {
172-
if err := c.Status(); err != nil {
183+
if err := c.ready(); err != nil {
173184
return nil, err
174185
}
186+
c.RLock()
187+
defer c.RUnlock()
175188
ns, err := newNamespace(id, path, opts...)
176189
if err != nil {
177190
return nil, err
@@ -232,9 +245,11 @@ func (c *libcni) attachNetworks(ctx context.Context, ns *Namespace) ([]*types100
232245

233246
// Remove removes the network config from the namespace
234247
func (c *libcni) Remove(ctx context.Context, id string, path string, opts ...NamespaceOpts) error {
235-
if err := c.Status(); err != nil {
248+
if err := c.ready(); err != nil {
236249
return err
237250
}
251+
c.RLock()
252+
defer c.RUnlock()
238253
ns, err := newNamespace(id, path, opts...)
239254
if err != nil {
240255
return err
@@ -260,9 +275,11 @@ func (c *libcni) Remove(ctx context.Context, id string, path string, opts ...Nam
260275

261276
// Check checks if the network is still in desired state
262277
func (c *libcni) Check(ctx context.Context, id string, path string, opts ...NamespaceOpts) error {
263-
if err := c.Status(); err != nil {
278+
if err := c.ready(); err != nil {
264279
return err
265280
}
281+
c.RLock()
282+
defer c.RUnlock()
266283
ns, err := newNamespace(id, path, opts...)
267284
if err != nil {
268285
return err
@@ -310,3 +327,13 @@ func (c *libcni) GetConfig() *ConfigResult {
310327
func (c *libcni) reset() {
311328
c.networks = nil
312329
}
330+
331+
func (c *libcni) ready() error {
332+
c.RLock()
333+
defer c.RUnlock()
334+
if len(c.networks) < c.networkCount {
335+
return ErrCNINotInitialized
336+
}
337+
338+
return nil
339+
}

cni_test.go

+61-32
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package cni
1818

1919
import (
2020
"context"
21+
"errors"
2122
"net"
2223
"testing"
2324

@@ -292,21 +293,19 @@ func TestLibCNIType120(t *testing.T) {
292293
// Get the default CNI config
293294
l := defaultCNIConfig()
294295
// Create a fake cni config directory and file
295-
cniDir, confDir := makeFakeCNIConfig(t)
296+
cniDir, confDir := buildFakeConfig(t)
296297
defer tearDownCNIConfig(t, cniDir)
297298
l.pluginConfDir = confDir
298299
// Set the minimum network count as 2 for this test
299300
l.networkCount = 2
300-
err := l.Load(WithAllConf)
301-
assert.NoError(t, err)
302-
303-
err = l.Status()
301+
err := l.Load(WithLoNetwork, WithDefaultConf)
304302
assert.NoError(t, err)
305303

306304
mockCNI := &MockCNI{}
305+
l.cniConfig = mockCNI
307306
l.networks[0].cni = mockCNI
308307
l.networks[1].cni = mockCNI
309-
ipv4, err := types.ParseCIDR("10.0.0.1/24")
308+
ipv4, err := types.ParseCIDR("10.88.0.1/16")
310309
assert.NoError(t, err)
311310
expectedRT := &cnilibrary.RuntimeConf{
312311
ContainerID: "container-id1",
@@ -315,59 +314,65 @@ func TestLibCNIType120(t *testing.T) {
315314
Args: [][2]string(nil),
316315
CapabilityArgs: map[string]interface{}{},
317316
}
318-
mockCNI.On("AddNetworkList", l.networks[0].config, expectedRT).Return(&types100.Result{
319-
CNIVersion: "1.1.0",
320-
Interfaces: []*types100.Interface{
317+
318+
loRT := &cnilibrary.RuntimeConf{
319+
ContainerID: "container-id1",
320+
NetNS: "/proc/12345/ns/net",
321+
IfName: "lo",
322+
Args: [][2]string(nil),
323+
CapabilityArgs: map[string]interface{}{},
324+
}
325+
326+
// mock for loopback
327+
mockCNI.On("GetStatusNetworkList", l.networks[0].config).Return(nil)
328+
mockCNI.On("AddNetworkList", l.networks[0].config, loRT).Return(&types040.Result{
329+
CNIVersion: "0.3.1",
330+
Interfaces: []*types040.Interface{
321331
{
322-
Name: "eth0",
332+
Name: "lo",
323333
},
324334
},
325-
IPs: []*types100.IPConfig{
335+
IPs: []*types040.IPConfig{
326336
{
327-
Interface: types100.Int(0),
328-
Address: *ipv4,
329-
Gateway: net.ParseIP("10.0.0.255"),
337+
Interface: types040.Int(0),
338+
Address: net.IPNet{
339+
IP: net.ParseIP("127.0.0.1"),
340+
},
330341
},
331342
},
332343
}, nil)
333-
mockCNI.On("DelNetworkList", l.networks[0].config, expectedRT).Return(nil)
334-
mockCNI.On("CheckNetworkList", l.networks[0].config, expectedRT).Return(nil)
335-
ipv4, err = types.ParseCIDR("10.0.0.2/24")
336-
assert.NoError(t, err)
337-
l.networks[1].cni = mockCNI
338-
expectedRT = &cnilibrary.RuntimeConf{
339-
ContainerID: "container-id1",
340-
NetNS: "/proc/12345/ns/net",
341-
IfName: "eth1",
342-
Args: [][2]string(nil),
343-
CapabilityArgs: map[string]interface{}{},
344-
}
344+
mockCNI.On("DelNetworkList", l.networks[0].config, loRT).Return(nil)
345+
mockCNI.On("CheckNetworkList", l.networks[0].config, loRT).Return(nil)
346+
347+
// mock for primary cni
348+
mockCNI.On("GetStatusNetworkList", l.networks[1].config).Return(nil)
345349
mockCNI.On("AddNetworkList", l.networks[1].config, expectedRT).Return(&types100.Result{
346350
CNIVersion: "1.1.0",
347351
Interfaces: []*types100.Interface{
348352
{
349-
Name: "eth1",
353+
Name: "eth0",
350354
},
351355
},
352356
IPs: []*types100.IPConfig{
353357
{
354358
Interface: types100.Int(0),
355359
Address: *ipv4,
356-
Gateway: net.ParseIP("10.0.0.2"),
360+
Gateway: net.ParseIP("10.88.0.1"),
357361
},
358362
},
359363
}, nil)
360364
mockCNI.On("DelNetworkList", l.networks[1].config, expectedRT).Return(nil)
361365
mockCNI.On("CheckNetworkList", l.networks[1].config, expectedRT).Return(nil)
362366
ctx := context.Background()
367+
368+
err = l.Status()
369+
assert.NoError(t, err)
370+
363371
r, err := l.Setup(ctx, "container-id1", "/proc/12345/ns/net")
364372
assert.NoError(t, err)
365373
assert.Contains(t, r.Interfaces, "eth0")
366374
assert.NotNil(t, r.Interfaces["eth0"].IPConfigs)
367-
assert.Equal(t, r.Interfaces["eth0"].IPConfigs[0].IP.String(), "10.0.0.1")
368-
assert.Contains(t, r.Interfaces, "eth1")
369-
assert.NotNil(t, r.Interfaces["eth1"].IPConfigs)
370-
assert.Equal(t, r.Interfaces["eth1"].IPConfigs[0].IP.String(), "10.0.0.2")
375+
assert.Equal(t, r.Interfaces["eth0"].IPConfigs[0].IP.String(), "10.88.0.1")
371376

372377
err = l.Check(ctx, "container-id1", "/proc/12345/ns/net")
373378
assert.NoError(t, err)
@@ -376,6 +381,30 @@ func TestLibCNIType120(t *testing.T) {
376381
assert.NoError(t, err)
377382
}
378383

384+
func TestLibCNIType120FailStatus(t *testing.T) {
385+
// Get the default CNI config
386+
l := defaultCNIConfig()
387+
// Create a fake cni config directory and file
388+
cniDir, confDir := buildFakeConfig(t)
389+
defer tearDownCNIConfig(t, cniDir)
390+
l.pluginConfDir = confDir
391+
// Set the minimum network count as 2 for this test
392+
l.networkCount = 2
393+
err := l.Load(WithLoNetwork, WithDefaultConf)
394+
assert.NoError(t, err)
395+
396+
mockCNI := &MockCNI{}
397+
l.cniConfig = mockCNI
398+
l.networks[0].cni = mockCNI
399+
l.networks[1].cni = mockCNI
400+
401+
mockCNI.On("GetStatusNetworkList", l.networks[0].config).Return(nil)
402+
mockCNI.On("GetStatusNetworkList", l.networks[1].config).Return(errors.New("no ip addresses"))
403+
l.cniConfig = mockCNI
404+
err = l.Status()
405+
assert.Error(t, err)
406+
}
407+
379408
type MockCNI struct {
380409
mock.Mock
381410
}

testutils.go

+61
Original file line numberDiff line numberDiff line change
@@ -75,3 +75,64 @@ func tearDownCNIConfig(t *testing.T, confDir string) {
7575
t.Fatalf("Failed to cleanup CNI configs: %v", err)
7676
}
7777
}
78+
79+
func buildFakeConfig(t *testing.T) (string, string) {
80+
conf := `
81+
{
82+
"cniVersion": "1.1.0",
83+
"name": "containerd-net",
84+
"plugins": [
85+
{
86+
"type": "bridge",
87+
"bridge": "cni0",
88+
"isGateway": true,
89+
"ipMasq": true,
90+
"promiscMode": true,
91+
"ipam": {
92+
"type": "host-ipam",
93+
"ranges": [
94+
[{
95+
"subnet": "10.88.0.0/16"
96+
}],
97+
[{
98+
"subnet": "2001:4860:4860::/64"
99+
}]
100+
],
101+
"routes": [
102+
{ "dst": "0.0.0.0/0" },
103+
{ "dst": "::/0" }
104+
]
105+
}
106+
},
107+
{
108+
"type": "portmap",
109+
"capabilities": {"portMappings": true}
110+
}
111+
]
112+
}`
113+
114+
cniDir, err := makeTmpDir("fakecni")
115+
if err != nil {
116+
t.Fatalf("Failed to create plugin config dir: %v", err)
117+
}
118+
119+
cniConfDir := path.Join(cniDir, "net.d")
120+
err = os.MkdirAll(cniConfDir, 0777)
121+
if err != nil {
122+
t.Fatalf("Failed to create network config dir: %v", err)
123+
}
124+
125+
networkConfig1 := path.Join(cniConfDir, "mocknetwork1.conflist")
126+
f1, err := os.Create(networkConfig1)
127+
if err != nil {
128+
t.Fatalf("Failed to create network config %v: %v", f1, err)
129+
}
130+
131+
_, err = f1.WriteString(conf)
132+
if err != nil {
133+
t.Fatalf("Failed to write network config file %v: %v", f1, err)
134+
}
135+
f1.Close()
136+
137+
return cniDir, cniConfDir
138+
}

0 commit comments

Comments
 (0)