Skip to content

Commit

Permalink
Implement STATUS
Browse files Browse the repository at this point in the history
This commit implements the STATUS CNI verb, updating the go-cni
Status() function to call STATUS on all plugins for each network.
It returns without error only if all STATUS calls return without error.

Signed-off-by: Michael Zappa <[email protected]>
Signed-off-by: Archit Kulkarni <[email protected]>
Co-authored-by: Michael Zappa <[email protected]>
  • Loading branch information
2 people authored and architkulkarni committed Oct 14, 2024
1 parent 6603d5b commit d79d5df
Show file tree
Hide file tree
Showing 10 changed files with 218 additions and 202 deletions.
8 changes: 4 additions & 4 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ jobs:
steps:
- uses: actions/setup-go@v3
with:
go-version: 1.20.x
go-version: 1.21.x

- name: Set env
shell: bash
Expand Down Expand Up @@ -44,7 +44,7 @@ jobs:

strategy:
matrix:
go-version: [1.19.x, 1.20.x]
go-version: ["1.21.8", "1.22.1"]
os: [ubuntu-22.04]

steps:
Expand All @@ -64,7 +64,7 @@ jobs:
- uses: golangci/golangci-lint-action@v3
with:
version: v1.51.1
version: v1.56.1
working-directory: src/github.com/containerd/go-cni

tests:
Expand All @@ -74,7 +74,7 @@ jobs:

strategy:
matrix:
go-version: [1.19.x, 1.20.x]
go-version: ["1.21.8", "1.22.1"]

steps:
- uses: actions/checkout@v3
Expand Down
23 changes: 22 additions & 1 deletion cni.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ type CNI interface {
Status() error
// GetConfig returns a copy of the CNI plugin configurations as parsed by CNI
GetConfig() *ConfigResult
// Status executes the status verb of the cni plugin
StatusDetail(context.Context) ([]*NetworkStatus, error)
}

type ConfigResult struct {
Expand Down Expand Up @@ -133,7 +135,6 @@ func (c *libcni) Load(opts ...Opt) error {
return nil
}

// Status returns the status of CNI initialization.
func (c *libcni) Status() error {
c.RLock()
defer c.RUnlock()
Expand Down Expand Up @@ -310,3 +311,23 @@ func (c *libcni) GetConfig() *ConfigResult {
func (c *libcni) reset() {
c.networks = nil
}

// StatusDetail returns a slice of network statuses
func (c *libcni) StatusDetail(ctx context.Context) ([]*NetworkStatus, error) {
err := c.Status()

if err != nil {
return nil, err
}

var networks []*NetworkStatus

for _, network := range c.Networks() {
networks = append(networks, &NetworkStatus{
Network: network,
Status: network.Status(ctx),
})
}

return networks, nil
}
128 changes: 120 additions & 8 deletions cni_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import (
types020 "github.com/containernetworking/cni/pkg/types/020"
types040 "github.com/containernetworking/cni/pkg/types/040"
types100 "github.com/containernetworking/cni/pkg/types/100"
"github.com/containernetworking/cni/pkg/version"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
)
Expand Down Expand Up @@ -285,36 +286,127 @@ func TestLibCNIType100(t *testing.T) {
assert.NoError(t, err)
}

// TestLibCNIType120 tests the cni version 1.1.0 plugin
// config and parses the result into structured data
func TestLibCNIType120(t *testing.T) {
// Get the default CNI config
l := defaultCNIConfig()
// Create a fake cni config directory and file
cniDir, confDir := makeFakeCNIConfig(t)
defer tearDownCNIConfig(t, cniDir)
l.pluginConfDir = confDir
// Set the minimum network count as 2 for this test
l.networkCount = 2
err := l.Load(WithAllConf)
assert.NoError(t, err)

err = l.Status()
assert.NoError(t, err)

mockCNI := &MockCNI{}
l.networks[0].cni = mockCNI
l.networks[1].cni = mockCNI
ipv4, err := types.ParseCIDR("10.0.0.1/24")
assert.NoError(t, err)
expectedRT := &cnilibrary.RuntimeConf{
ContainerID: "container-id1",
NetNS: "/proc/12345/ns/net",
IfName: "eth0",
Args: [][2]string(nil),
CapabilityArgs: map[string]interface{}{},
}
mockCNI.On("AddNetworkList", l.networks[0].config, expectedRT).Return(&types100.Result{
CNIVersion: "1.1.0",
Interfaces: []*types100.Interface{
{
Name: "eth0",
},
},
IPs: []*types100.IPConfig{
{
Interface: types100.Int(0),
Address: *ipv4,
Gateway: net.ParseIP("10.0.0.255"),
},
},
}, nil)
mockCNI.On("DelNetworkList", l.networks[0].config, expectedRT).Return(nil)
mockCNI.On("CheckNetworkList", l.networks[0].config, expectedRT).Return(nil)
ipv4, err = types.ParseCIDR("10.0.0.2/24")
assert.NoError(t, err)
l.networks[1].cni = mockCNI
expectedRT = &cnilibrary.RuntimeConf{
ContainerID: "container-id1",
NetNS: "/proc/12345/ns/net",
IfName: "eth1",
Args: [][2]string(nil),
CapabilityArgs: map[string]interface{}{},
}
mockCNI.On("GetStatusNetworkList", l.networks[1].config).Return(nil)
mockCNI.On("AddNetworkList", l.networks[1].config, expectedRT).Return(&types100.Result{
CNIVersion: "1.1.0",
Interfaces: []*types100.Interface{
{
Name: "eth1",
},
},
IPs: []*types100.IPConfig{
{
Interface: types100.Int(0),
Address: *ipv4,
Gateway: net.ParseIP("10.0.0.2"),
},
},
}, nil)
mockCNI.On("DelNetworkList", l.networks[1].config, expectedRT).Return(nil)
mockCNI.On("CheckNetworkList", l.networks[1].config, expectedRT).Return(nil)
ctx := context.Background()
r, err := l.Setup(ctx, "container-id1", "/proc/12345/ns/net")
assert.NoError(t, err)
assert.Contains(t, r.Interfaces, "eth0")
assert.NotNil(t, r.Interfaces["eth0"].IPConfigs)
assert.Equal(t, r.Interfaces["eth0"].IPConfigs[0].IP.String(), "10.0.0.1")
assert.Contains(t, r.Interfaces, "eth1")
assert.NotNil(t, r.Interfaces["eth1"].IPConfigs)
assert.Equal(t, r.Interfaces["eth1"].IPConfigs[0].IP.String(), "10.0.0.2")

err = l.Check(ctx, "container-id1", "/proc/12345/ns/net")
assert.NoError(t, err)

err = l.Remove(ctx, "container-id1", "/proc/12345/ns/net")
assert.NoError(t, err)
}

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)
}
Expand All @@ -329,12 +421,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)
}
Expand All @@ -348,3 +440,23 @@ func (m *MockCNI) GetNetworkListCachedResult(net *cnilibrary.NetworkConfigList,
args := m.Called(net, rt)
return args.Get(0).(types.Result), args.Error(1)
}

func (m *MockCNI) GCNetworkList(_ context.Context, net *cnilibrary.NetworkConfigList, gcargs *cnilibrary.GCArgs) error {
args := m.Called(net, gcargs)
return args.Error(0)
}

func (m *MockCNI) GetStatusNetworkList(_ context.Context, net *cnilibrary.NetworkConfigList) error {
args := m.Called(net)
return args.Error(0)
}

func (m *MockCNI) GetCachedAttachments(containerID string) ([]*cnilibrary.NetworkAttachment, error) {
args := m.Called(containerID)
return args.Get(0).([]*cnilibrary.NetworkAttachment), args.Error(1)
}

func (m *MockCNI) GetVersionInfo(_ context.Context, pluginType string) (version.PluginInfo, error) {
args := m.Called(pluginType)
return args.Get(0).(version.PluginInfo), args.Error(1)
}
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
module github.com/containerd/go-cni

go 1.19
go 1.21

require (
github.com/containernetworking/cni v1.1.2
github.com/containernetworking/cni v1.2.3
github.com/stretchr/testify v1.8.0
)

Expand Down
Loading

0 comments on commit d79d5df

Please sign in to comment.