// TuningConf represents the network tuning configuration.
type TuningConf struct {
types.NetConf
- SysCtl map[string]string `json:"sysctl"`
+ SysCtl map[string]string `json:"sysctl"`
+ RawPrevResult map[string]interface{} `json:"prevResult,omitempty"`
+ PrevResult *current.Result `json:"-"`
+}
+
+func parseConf(data []byte) (*TuningConf, error) {
+ conf := TuningConf{}
+ if err := json.Unmarshal(data, &conf); err != nil {
+ return nil, fmt.Errorf("failed to load netconf: %v", err)
+ }
+
+ // Parse previous result.
+ if conf.RawPrevResult != nil {
+ resultBytes, err := json.Marshal(conf.RawPrevResult)
+ if err != nil {
+ return nil, fmt.Errorf("could not serialize prevResult: %v", err)
+ }
+ res, err := version.NewResult(conf.CNIVersion, resultBytes)
+ if err != nil {
+ return nil, fmt.Errorf("could not parse prevResult: %v", err)
+ }
+ conf.RawPrevResult = nil
+ conf.PrevResult, err = current.NewResultFromResult(res)
+ if err != nil {
+ return nil, fmt.Errorf("could not convert result to current version: %v", err)
+ }
+ }
+
+ return &conf, nil
}
func cmdAdd(args *skel.CmdArgs) error {
- tuningConf := TuningConf{}
- if err := json.Unmarshal(args.StdinData, &tuningConf); err != nil {
- return fmt.Errorf("failed to load netconf: %v", err)
+ tuningConf, err := parseConf(args.StdinData)
+ if err != nil {
+ return err
}
// The directory /proc/sys/net is per network namespace. Enter in the
// network namespace before writing on it.
- err := ns.WithNetNSPath(args.Netns, func(_ ns.NetNS) error {
+ err = ns.WithNetNSPath(args.Netns, func(_ ns.NetNS) error {
for key, value := range tuningConf.SysCtl {
fileName := filepath.Join("/proc/sys", strings.Replace(key, ".", "/", -1))
fileName = filepath.Clean(fileName)
return err
}
- result := current.Result{}
- return result.Print()
+ return types.PrintResult(tuningConf.PrevResult, tuningConf.CNIVersion)
}
func cmdDel(args *skel.CmdArgs) error {
--- /dev/null
+// Copyright 2017 CNI authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package main
+
+import (
+ . "github.com/onsi/ginkgo"
+ . "github.com/onsi/gomega"
+
+ "testing"
+)
+
+func TestTuning(t *testing.T) {
+ RegisterFailHandler(Fail)
+ RunSpecs(t, "tuning Suite")
+}
--- /dev/null
+// Copyright 2017 CNI authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package main
+
+import (
+ "github.com/containernetworking/cni/pkg/skel"
+ "github.com/containernetworking/cni/pkg/types/current"
+ "github.com/containernetworking/plugins/pkg/ns"
+ "github.com/containernetworking/plugins/pkg/testutils"
+
+ "github.com/vishvananda/netlink"
+
+ . "github.com/onsi/ginkgo"
+ . "github.com/onsi/gomega"
+)
+
+var _ = Describe("tuning plugin", func() {
+ var originalNS ns.NetNS
+ const IFNAME string = "dummy0"
+
+ BeforeEach(func() {
+ // Create a new NetNS so we don't modify the host
+ var err error
+ originalNS, err = ns.NewNS()
+ Expect(err).NotTo(HaveOccurred())
+
+ err = originalNS.Do(func(ns.NetNS) error {
+ defer GinkgoRecover()
+
+ err = netlink.LinkAdd(&netlink.Dummy{
+ LinkAttrs: netlink.LinkAttrs{
+ Name: IFNAME,
+ },
+ })
+ Expect(err).NotTo(HaveOccurred())
+ _, err = netlink.LinkByName(IFNAME)
+ Expect(err).NotTo(HaveOccurred())
+ return nil
+ })
+ Expect(err).NotTo(HaveOccurred())
+ })
+
+ AfterEach(func() {
+ Expect(originalNS.Close()).To(Succeed())
+ })
+
+ It("passes prevResult through unchanged", func() {
+ conf := []byte(`{
+ "name": "test",
+ "type": "tuning",
+ "cniVersion": "0.3.1",
+ "sysctl": {
+ "net.ipv4.conf.all.log_martians": "1"
+ },
+ "prevResult": {
+ "interfaces": [
+ {"name": "dummy0", "sandbox":"netns"}
+ ],
+ "ips": [
+ {
+ "version": "4",
+ "address": "10.0.0.2/24",
+ "gateway": "10.0.0.1",
+ "interface": 0
+ }
+ ]
+ }
+}`)
+
+ targetNs, err := ns.NewNS()
+ Expect(err).NotTo(HaveOccurred())
+ defer targetNs.Close()
+
+ args := &skel.CmdArgs{
+ ContainerID: "dummy",
+ Netns: targetNs.Path(),
+ IfName: IFNAME,
+ StdinData: conf,
+ }
+
+ err = originalNS.Do(func(ns.NetNS) error {
+ defer GinkgoRecover()
+
+ r, _, err := testutils.CmdAddWithResult(targetNs.Path(), IFNAME, []byte(conf), func() error {
+ return cmdAdd(args)
+ })
+ Expect(err).NotTo(HaveOccurred())
+
+ result, err := current.GetResult(r)
+ Expect(err).NotTo(HaveOccurred())
+
+ Expect(len(result.Interfaces)).To(Equal(1))
+ Expect(result.Interfaces[0].Name).To(Equal(IFNAME))
+ Expect(len(result.IPs)).To(Equal(1))
+ Expect(result.IPs[0].Address.String()).To(Equal("10.0.0.2/24"))
+ return nil
+ })
+ Expect(err).NotTo(HaveOccurred())
+ })
+})