Skip to content

Commit e330355

Browse files
authored
write empty json object to empty cni statefile if exists (#933)
* write empty json object to empty cni statefile if exists * update tests, address review comments
1 parent 0bab55c commit e330355

File tree

4 files changed

+98
-0
lines changed

4 files changed

+98
-0
lines changed

cns/cnireconciler/podinfoprovider_test.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,14 @@ func TestNewCNIPodInfoProvider(t *testing.T) {
3636
},
3737
wantErr: false,
3838
},
39+
{
40+
name: "empty CNI response",
41+
exec: newCNIStateFakeExec(
42+
`{}`,
43+
),
44+
want: map[string]cns.PodInfo{},
45+
wantErr: false,
46+
},
3947
}
4048
for _, tt := range tests {
4149
t.Run(tt.name, func(t *testing.T) {

cns/cnireconciler/statefile.go

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
package cnireconciler
2+
3+
import (
4+
"encoding/json"
5+
"errors"
6+
"os"
7+
8+
"github.com/Azure/azure-container-networking/cns/logger"
9+
)
10+
11+
// WriteObjectToCNIStatefile checks for a file at the CNI statefile path,
12+
// and checks if it is empty. If it is empty, writes an empty JSON object to
13+
// it so older CNI can execute. Does nothing and returns no error if the
14+
// file does not exist.
15+
//
16+
// This is a hack to get older CNI to run when CNS has mounted the statefile
17+
// path, but the statefile wasn't written by CNI yet. Kubelet will stub an
18+
// empty file on the host filesystem, crashing older CNI because it doesn't know
19+
// how to handle empty statefiles.
20+
func WriteObjectToCNIStatefile() error {
21+
filename := "/var/run/azure-vnet.json"
22+
return writeObjectToFile(filename)
23+
}
24+
25+
func writeObjectToFile(filename string) error {
26+
fi, err := os.Stat(filename)
27+
if err != nil {
28+
if errors.Is(err, os.ErrNotExist) {
29+
return nil
30+
}
31+
return err
32+
}
33+
34+
if fi.Size() != 0 {
35+
return nil
36+
}
37+
38+
logger.Printf("Writing {} to CNI statefile")
39+
b, _ := json.Marshal(map[string]string{})
40+
return os.WriteFile(filename, b, os.FileMode(0666))
41+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
package cnireconciler
2+
3+
import (
4+
"os"
5+
"path"
6+
"testing"
7+
8+
"github.com/Azure/azure-container-networking/cns/logger"
9+
"github.com/stretchr/testify/assert"
10+
"github.com/stretchr/testify/require"
11+
)
12+
13+
func TestWriteObjectToFile(t *testing.T) {
14+
name := "testdata/test"
15+
err := os.MkdirAll(path.Dir(name), 0666)
16+
require.NoError(t, err)
17+
18+
_, err = os.Stat(name)
19+
require.ErrorIs(t, err, os.ErrNotExist)
20+
21+
// create empty file
22+
_, err = os.Create(name)
23+
require.NoError(t, err)
24+
defer os.Remove(name)
25+
26+
// check it's empty
27+
fi, _ := os.Stat(name)
28+
assert.Equal(t, fi.Size(), int64(0))
29+
30+
// populate
31+
require.NoError(t, writeObjectToFile(name))
32+
33+
// read
34+
b, err := os.ReadFile(name)
35+
require.NoError(t, err)
36+
assert.Equal(t, string(b), "{}")
37+
}
38+
39+
func init() {
40+
logger.InitLogger("testlogs", 0, 0, "./")
41+
}

cns/service/main.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121
"github.com/Azure/azure-container-networking/cnm/ipam"
2222
"github.com/Azure/azure-container-networking/cnm/network"
2323
"github.com/Azure/azure-container-networking/cns"
24+
"github.com/Azure/azure-container-networking/cns/cnireconciler"
2425
cni "github.com/Azure/azure-container-networking/cns/cnireconciler"
2526
"github.com/Azure/azure-container-networking/cns/cnsclient"
2627
"github.com/Azure/azure-container-networking/cns/common"
@@ -521,6 +522,13 @@ func main() {
521522
// Initialze state in if CNS is running in CRD mode
522523
// State must be initialized before we start HTTPRestService
523524
if config.ChannelMode == cns.CRD {
525+
// Check the CNI statefile mount, and if the file is empty
526+
// stub an empty JSON object
527+
if err := cnireconciler.WriteObjectToCNIStatefile(); err != nil {
528+
logger.Errorf("Failed to write empty object to CNI state: %v", err)
529+
return
530+
}
531+
524532
// We might be configured to reinitialize state from the CNI instead of the apiserver.
525533
// If so, we should check that the the CNI is new enough to support the state commands,
526534
// otherwise we fall back to the existing behavior.

0 commit comments

Comments
 (0)