From 545b30e8cc4c71058b91269128323ff5111517f0 Mon Sep 17 00:00:00 2001 From: Michael Zappa Date: Fri, 5 Apr 2024 11:41:26 -0600 Subject: [PATCH] status should ensure plugins and conf are present Signed-off-by: Michael Zappa --- .github/workflows/ci.yml | 2 +- cni.go | 21 +++++++++++++++++++++ cni_test.go | 19 ++++++++++--------- errors.go | 14 ++++++++------ testutils.go | 14 +++++++++++++- 5 files changed, 53 insertions(+), 17 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 086343e..67db40e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -64,7 +64,7 @@ jobs: - uses: golangci/golangci-lint-action@v3 with: - version: v1.51.1 + version: v1.57.2 working-directory: src/github.com/containerd/go-cni tests: diff --git a/cni.go b/cni.go index b10af47..102ebb3 100644 --- a/cni.go +++ b/cni.go @@ -20,6 +20,7 @@ import ( "context" "fmt" "os" + "path/filepath" "strings" "sync" @@ -140,6 +141,19 @@ func (c *libcni) Status() error { if len(c.networks) < c.networkCount { return ErrCNINotInitialized } + + for _, dir := range c.pluginDirs { + for _, nets := range c.networks { + for _, plug := range nets.config.Plugins { + plugin := plug.Network.Type + + if !FileExistsInDir(dir, plugin) { + return ErrCNIPluginNotFound + } + } + } + } + return nil } @@ -310,3 +324,10 @@ func (c *libcni) GetConfig() *ConfigResult { func (c *libcni) reset() { c.networks = nil } + +// FileExistsInDir checks if a file exists in a specific directory +func FileExistsInDir(directory, filename string) bool { + filePath := filepath.Join(directory, filename) + _, err := os.Stat(filePath) + return !os.IsExist(err) +} diff --git a/cni_test.go b/cni_test.go index c2b0b2f..2042664 100644 --- a/cni_test.go +++ b/cni_test.go @@ -39,6 +39,7 @@ func TestLibCNIType020(t *testing.T) { // Create a fake cni config directory and file cniDir, confDir := makeFakeCNIConfig(t) defer tearDownCNIConfig(t, cniDir) + l.pluginDirs = []string{cniDir} l.pluginConfDir = confDir // Set the minimum network count as 2 for this test l.networkCount = 2 @@ -99,7 +100,7 @@ func TestLibCNIType020(t *testing.T) { assert.NotNil(t, c.Prefix) assert.Equal(t, "eth", c.Prefix) assert.NotNil(t, c.PluginDirs) - assert.Equal(t, DefaultCNIDir, c.PluginDirs[0]) + assert.Equal(t, cniDir, c.PluginDirs[0]) assert.NotNil(t, c.PluginConfDir) assert.Equal(t, confDir, c.PluginConfDir) assert.NotNil(t, c.Networks) @@ -289,32 +290,32 @@ type MockCNI struct { mock.Mock } -func (m *MockCNI) AddNetwork(ctx context.Context, net *cnilibrary.NetworkConfig, rt *cnilibrary.RuntimeConf) (types.Result, error) { +func (m *MockCNI) AddNetwork(_ context.Context, net *cnilibrary.NetworkConfig, rt *cnilibrary.RuntimeConf) (types.Result, error) { args := m.Called(net, rt) return args.Get(0).(types.Result), args.Error(1) } -func (m *MockCNI) DelNetwork(ctx context.Context, net *cnilibrary.NetworkConfig, rt *cnilibrary.RuntimeConf) error { +func (m *MockCNI) DelNetwork(_ context.Context, net *cnilibrary.NetworkConfig, rt *cnilibrary.RuntimeConf) error { args := m.Called(net, rt) return args.Error(0) } -func (m *MockCNI) DelNetworkList(ctx context.Context, net *cnilibrary.NetworkConfigList, rt *cnilibrary.RuntimeConf) error { +func (m *MockCNI) DelNetworkList(_ context.Context, net *cnilibrary.NetworkConfigList, rt *cnilibrary.RuntimeConf) error { args := m.Called(net, rt) return args.Error(0) } -func (m *MockCNI) AddNetworkList(ctx context.Context, net *cnilibrary.NetworkConfigList, rt *cnilibrary.RuntimeConf) (types.Result, error) { +func (m *MockCNI) AddNetworkList(_ context.Context, net *cnilibrary.NetworkConfigList, rt *cnilibrary.RuntimeConf) (types.Result, error) { args := m.Called(net, rt) return args.Get(0).(types.Result), args.Error(1) } -func (m *MockCNI) CheckNetworkList(ctx context.Context, net *cnilibrary.NetworkConfigList, rt *cnilibrary.RuntimeConf) error { +func (m *MockCNI) CheckNetworkList(_ context.Context, net *cnilibrary.NetworkConfigList, rt *cnilibrary.RuntimeConf) error { args := m.Called(net, rt) return args.Error(0) } -func (m *MockCNI) CheckNetwork(ctx context.Context, net *cnilibrary.NetworkConfig, rt *cnilibrary.RuntimeConf) error { +func (m *MockCNI) CheckNetwork(_ context.Context, net *cnilibrary.NetworkConfig, rt *cnilibrary.RuntimeConf) error { args := m.Called(net, rt) return args.Error(0) } @@ -329,12 +330,12 @@ func (m *MockCNI) GetNetworkCachedResult(net *cnilibrary.NetworkConfig, rt *cnil return args.Get(0).(types.Result), args.Error(1) } -func (m *MockCNI) ValidateNetworkList(ctx context.Context, net *cnilibrary.NetworkConfigList) ([]string, error) { +func (m *MockCNI) ValidateNetworkList(_ context.Context, net *cnilibrary.NetworkConfigList) ([]string, error) { args := m.Called(net) return args.Get(0).([]string), args.Error(1) } -func (m *MockCNI) ValidateNetwork(ctx context.Context, net *cnilibrary.NetworkConfig) ([]string, error) { +func (m *MockCNI) ValidateNetwork(_ context.Context, net *cnilibrary.NetworkConfig) ([]string, error) { args := m.Called(net) return args.Get(0).([]string), args.Error(1) } diff --git a/errors.go b/errors.go index 9c670fe..31b557a 100644 --- a/errors.go +++ b/errors.go @@ -21,12 +21,14 @@ import ( ) var ( - ErrCNINotInitialized = errors.New("cni plugin not initialized") - ErrInvalidConfig = errors.New("invalid cni config") - ErrNotFound = errors.New("not found") - ErrRead = errors.New("failed to read config file") - ErrInvalidResult = errors.New("invalid result") - ErrLoad = errors.New("failed to load cni config") + ErrCNINotInitialized = errors.New("cni plugin not initialized") + ErrInvalidConfig = errors.New("invalid cni config") + ErrNotFound = errors.New("not found") + ErrRead = errors.New("failed to read config file") + ErrInvalidResult = errors.New("invalid result") + ErrLoad = errors.New("failed to load cni config") + ErrCNIPluginNotFound = errors.New("cni plugin not found") + ErrCNIPluginDirNotFound = errors.New("cni plugin directory not found") ) // IsCNINotInitialized returns true if the error is due to cni config not being initialized diff --git a/testutils.go b/testutils.go index 0807e20..32b28c8 100644 --- a/testutils.go +++ b/testutils.go @@ -43,6 +43,12 @@ func makeFakeCNIConfig(t *testing.T) (string, string) { t.Fatalf("Failed to create network config dir: %v", err) } + cniPluginDir := path.Join(cniDir, "bin") + err = os.MkdirAll(cniPluginDir, 0777) + if err != nil { + t.Fatalf("Failed to create plugin dir: %v", err) + } + networkConfig1 := path.Join(cniConfDir, "mocknetwork1.conf") f1, err := os.Create(networkConfig1) if err != nil { @@ -54,6 +60,12 @@ func makeFakeCNIConfig(t *testing.T) (string, string) { t.Fatalf("Failed to create network config %v: %v", f2, err) } + file, err := os.Create(path.Join(cniPluginDir, "fakecni")) + if err != nil { + t.Fatalf("Error creating file: %v", err) + } + defer file.Close() + cfg1 := fmt.Sprintf(`{ "name": "%s", "type": "%s", "capabilities": {"portMappings": true} }`, "plugin1", "fakecni") _, err = f1.WriteString(cfg1) if err != nil { @@ -66,7 +78,7 @@ func makeFakeCNIConfig(t *testing.T) (string, string) { t.Fatalf("Failed to write network config file %v: %v", f2, err) } f2.Close() - return cniDir, cniConfDir + return cniPluginDir, cniConfDir } func tearDownCNIConfig(t *testing.T, confDir string) {