host-local: Update host-local IPAM to support Windows

This commit is contained in:
Rakesh Kelkar
2017-10-06 19:00:19 -07:00
parent fbced0cccb
commit 47668f6d64
11 changed files with 496 additions and 155 deletions

View File

@ -22,6 +22,7 @@ import (
"strings"
"github.com/containernetworking/plugins/plugins/ipam/host-local/backend"
"runtime"
)
const lastIPFilePrefix = "last_reserved_ip."
@ -55,7 +56,8 @@ func New(network, dataDir string) (*Store, error) {
}
func (s *Store) Reserve(id string, ip net.IP, rangeID string) (bool, error) {
fname := filepath.Join(s.dataDir, ip.String())
fname := GetEscapedPath(s.dataDir, ip.String())
f, err := os.OpenFile(fname, os.O_RDWR|os.O_EXCL|os.O_CREATE, 0644)
if os.IsExist(err) {
return false, nil
@ -73,7 +75,7 @@ func (s *Store) Reserve(id string, ip net.IP, rangeID string) (bool, error) {
return false, err
}
// store the reserved ip in lastIPFile
ipfile := filepath.Join(s.dataDir, lastIPFilePrefix+rangeID)
ipfile := GetEscapedPath(s.dataDir, lastIPFilePrefix+rangeID)
err = ioutil.WriteFile(ipfile, []byte(ip.String()), 0644)
if err != nil {
return false, err
@ -83,7 +85,7 @@ func (s *Store) Reserve(id string, ip net.IP, rangeID string) (bool, error) {
// LastReservedIP returns the last reserved IP if exists
func (s *Store) LastReservedIP(rangeID string) (net.IP, error) {
ipfile := filepath.Join(s.dataDir, lastIPFilePrefix+rangeID)
ipfile := GetEscapedPath(s.dataDir, lastIPFilePrefix+rangeID)
data, err := ioutil.ReadFile(ipfile)
if err != nil {
return nil, err
@ -92,7 +94,7 @@ func (s *Store) LastReservedIP(rangeID string) (net.IP, error) {
}
func (s *Store) Release(ip net.IP) error {
return os.Remove(filepath.Join(s.dataDir, ip.String()))
return os.Remove(GetEscapedPath(s.dataDir, ip.String()))
}
// N.B. This function eats errors to be tolerant and
@ -115,3 +117,10 @@ func (s *Store) ReleaseByID(id string) error {
})
return err
}
func GetEscapedPath(dataDir string, fname string) string {
if runtime.GOOS == "windows" {
fname = strings.Replace(fname, ":", "_", -1)
}
return filepath.Join(dataDir, fname)
}

View File

@ -0,0 +1,27 @@
// 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 disk
import (
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"testing"
)
func TestLock(t *testing.T) {
RegisterFailHandler(Fail)
RunSpecs(t, "Disk Suite")
}

View File

@ -1,4 +1,3 @@
// +build !windows
// Copyright 2015 CNI authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
@ -16,18 +15,28 @@
package disk
import (
"github.com/alexflint/go-filemutex"
"os"
"syscall"
"path"
)
// FileLock wraps os.File to be used as a lock using flock
type FileLock struct {
f *os.File
f *filemutex.FileMutex
}
// NewFileLock opens file/dir at path and returns unlocked FileLock object
func NewFileLock(path string) (*FileLock, error) {
f, err := os.Open(path)
func NewFileLock(lockPath string) (*FileLock, error) {
fi, err := os.Stat(lockPath)
if err != nil {
return nil, err
}
if fi.IsDir() {
lockPath = path.Join(lockPath, "lock")
}
f, err := filemutex.New(lockPath)
if err != nil {
return nil, err
}
@ -35,17 +44,16 @@ func NewFileLock(path string) (*FileLock, error) {
return &FileLock{f}, nil
}
// Close closes underlying file
func (l *FileLock) Close() error {
return l.f.Close()
}
// Lock acquires an exclusive lock
func (l *FileLock) Lock() error {
return syscall.Flock(int(l.f.Fd()), syscall.LOCK_EX)
return l.f.Lock()
}
// Unlock releases the lock
func (l *FileLock) Unlock() error {
return syscall.Flock(int(l.f.Fd()), syscall.LOCK_UN)
return l.f.Unlock()
}

View File

@ -0,0 +1,63 @@
// 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 disk
import (
"io/ioutil"
"os"
"path/filepath"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
)
var _ = Describe("Lock Operations", func() {
It("locks a file path", func() {
dir, err := ioutil.TempDir("", "")
Expect(err).ToNot(HaveOccurred())
defer os.RemoveAll(dir)
// create a dummy file to lock
path := filepath.Join(dir, "x")
f, err := os.OpenFile(path, os.O_RDONLY|os.O_CREATE, 0666)
Expect(err).ToNot(HaveOccurred())
err = f.Close()
Expect(err).ToNot(HaveOccurred())
// now use it to lock
m, err := NewFileLock(path)
Expect(err).ToNot(HaveOccurred())
err = m.Lock()
Expect(err).ToNot(HaveOccurred())
err = m.Unlock()
Expect(err).ToNot(HaveOccurred())
})
It("locks a folder path", func() {
dir, err := ioutil.TempDir("", "")
Expect(err).ToNot(HaveOccurred())
defer os.RemoveAll(dir)
// use the folder to lock
m, err := NewFileLock(dir)
Expect(err).ToNot(HaveOccurred())
err = m.Lock()
Expect(err).ToNot(HaveOccurred())
err = m.Unlock()
Expect(err).ToNot(HaveOccurred())
})
})