diff --git a/plugins/ipam/host-local/backend/disk/backend.go b/plugins/ipam/host-local/backend/disk/backend.go index ab4ddb4e..14dd40d6 100644 --- a/plugins/ipam/host-local/backend/disk/backend.go +++ b/plugins/ipam/host-local/backend/disk/backend.go @@ -31,8 +31,11 @@ type Store struct { dataDir string } -func New(network string) (*Store, error) { - dir := filepath.Join(defaultDataDir, network) +func New(network, dataDir string) (*Store, error) { + if dataDir == "" { + dataDir = defaultDataDir + } + dir := filepath.Join(dataDir, network) if err := os.MkdirAll(dir, 0644); err != nil { return nil, err } diff --git a/plugins/ipam/host-local/config.go b/plugins/ipam/host-local/config.go index faef3360..7c01a8cd 100644 --- a/plugins/ipam/host-local/config.go +++ b/plugins/ipam/host-local/config.go @@ -31,6 +31,7 @@ type IPAMConfig struct { Subnet types.IPNet `json:"subnet"` Gateway net.IP `json:"gateway"` Routes []types.Route `json:"routes"` + DataDir string `json:"dataDir"` Args *IPAMArgs `json:"-"` } diff --git a/plugins/ipam/host-local/host_local_test.go b/plugins/ipam/host-local/host_local_test.go new file mode 100644 index 00000000..41dba71c --- /dev/null +++ b/plugins/ipam/host-local/host_local_test.go @@ -0,0 +1,92 @@ +// Copyright 2016 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 ( + "fmt" + "io/ioutil" + "net" + "os" + "path/filepath" + + "github.com/containernetworking/cni/pkg/skel" + "github.com/containernetworking/cni/pkg/testutils" + "github.com/containernetworking/cni/pkg/types" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("host-local Operations", func() { + It("allocates and releases an address with ADD/DEL", func() { + const ifname string = "eth0" + const nspath string = "/some/where" + + tmpDir, err := ioutil.TempDir("", "host_local_artifacts") + Expect(err).NotTo(HaveOccurred()) + defer os.RemoveAll(tmpDir) + + conf := fmt.Sprintf(`{ + "cniVersion": "0.2.0", + "name": "mynet", + "type": "ipvlan", + "master": "foo0", + "ipam": { + "type": "host-local", + "subnet": "10.1.2.0/24", + "dataDir": "%s" + } +}`, tmpDir) + + args := &skel.CmdArgs{ + ContainerID: "dummy", + Netns: nspath, + IfName: ifname, + StdinData: []byte(conf), + } + + // Allocate the IP + result, err := testutils.CmdAddWithResult(nspath, ifname, func() error { + return cmdAdd(args) + }) + Expect(err).NotTo(HaveOccurred()) + + expectedAddress, err := types.ParseCIDR("10.1.2.2/24") + Expect(err).NotTo(HaveOccurred()) + expectedAddress.IP = expectedAddress.IP.To16() + Expect(result.IP4.IP).To(Equal(*expectedAddress)) + + Expect(result.IP4.Gateway).To(Equal(net.ParseIP("10.1.2.1"))) + + ipFilePath := filepath.Join(tmpDir, "mynet", "10.1.2.2") + contents, err := ioutil.ReadFile(ipFilePath) + Expect(err).NotTo(HaveOccurred()) + Expect(string(contents)).To(Equal("dummy")) + + lastFilePath := filepath.Join(tmpDir, "mynet", "last_reserved_ip") + contents, err = ioutil.ReadFile(lastFilePath) + Expect(err).NotTo(HaveOccurred()) + Expect(string(contents)).To(Equal("10.1.2.2")) + + // Release the IP + err = testutils.CmdDelWithResult(nspath, ifname, func() error { + return cmdDel(args) + }) + Expect(err).NotTo(HaveOccurred()) + + _, err = os.Stat(ipFilePath) + Expect(err).To(HaveOccurred()) + }) +}) diff --git a/plugins/ipam/host-local/main.go b/plugins/ipam/host-local/main.go index 0e1b0639..19a31802 100644 --- a/plugins/ipam/host-local/main.go +++ b/plugins/ipam/host-local/main.go @@ -32,7 +32,7 @@ func cmdAdd(args *skel.CmdArgs) error { return err } - store, err := disk.New(ipamConf.Name) + store, err := disk.New(ipamConf.Name, ipamConf.DataDir) if err != nil { return err } @@ -60,7 +60,7 @@ func cmdDel(args *skel.CmdArgs) error { return err } - store, err := disk.New(ipamConf.Name) + store, err := disk.New(ipamConf.Name, ipamConf.DataDir) if err != nil { return err }