pkg/ns: refactored so that builds succeed on non-linux platforms
authorAithal <aithal@amazon.com>
Sat, 18 Feb 2017 01:04:53 +0000 (17:04 -0800)
committerAithal <aithal@amazon.com>
Mon, 20 Feb 2017 18:00:55 +0000 (10:00 -0800)
moved functions that depend on linux packages (sys/unix) into a separate file
and added nop methods with a build tag for non-linux platforms in a new file.

pkg/ns/ns.go
pkg/ns/ns_linux.go [new file with mode: 0644]
pkg/ns/ns_unspecified.go [new file with mode: 0644]

index 220dd69..428fb77 100644 (file)
 package ns
 
 import (
-       "crypto/rand"
+       "errors"
        "fmt"
        "os"
-       "path"
        "runtime"
        "sync"
        "syscall"
-
-       "golang.org/x/sys/unix"
 )
 
 type NetNS interface {
@@ -65,12 +62,8 @@ type netNS struct {
 // netNS implements the NetNS interface
 var _ NetNS = &netNS{}
 
-func getCurrentThreadNetNSPath() string {
-       // /proc/self/ns/net returns the namespace of the main thread, not
-       // of whatever thread this goroutine is running on.  Make sure we
-       // use the thread's net namespace since the thread is switching around
-       return fmt.Sprintf("/proc/%d/task/%d/ns/net", os.Getpid(), unix.Gettid())
-}
+// NotImplementedError is used to indicate that a method is not implemented for the given platform
+var NotImplementedError = errors.New("Not Implemented")
 
 // Returns an object representing the current OS thread's network namespace
 func GetCurrentNS() (NetNS, error) {
@@ -125,82 +118,6 @@ func GetNS(nspath string) (NetNS, error) {
        return &netNS{file: fd}, nil
 }
 
-// Creates a new persistent network namespace and returns an object
-// representing that namespace, without switching to it
-func NewNS() (NetNS, error) {
-       const nsRunDir = "/var/run/netns"
-
-       b := make([]byte, 16)
-       _, err := rand.Reader.Read(b)
-       if err != nil {
-               return nil, fmt.Errorf("failed to generate random netns name: %v", err)
-       }
-
-       err = os.MkdirAll(nsRunDir, 0755)
-       if err != nil {
-               return nil, err
-       }
-
-       // create an empty file at the mount point
-       nsName := fmt.Sprintf("cni-%x-%x-%x-%x-%x", b[0:4], b[4:6], b[6:8], b[8:10], b[10:])
-       nsPath := path.Join(nsRunDir, nsName)
-       mountPointFd, err := os.Create(nsPath)
-       if err != nil {
-               return nil, err
-       }
-       mountPointFd.Close()
-
-       // Ensure the mount point is cleaned up on errors; if the namespace
-       // was successfully mounted this will have no effect because the file
-       // is in-use
-       defer os.RemoveAll(nsPath)
-
-       var wg sync.WaitGroup
-       wg.Add(1)
-
-       // do namespace work in a dedicated goroutine, so that we can safely
-       // Lock/Unlock OSThread without upsetting the lock/unlock state of
-       // the caller of this function
-       var fd *os.File
-       go (func() {
-               defer wg.Done()
-               runtime.LockOSThread()
-
-               var origNS NetNS
-               origNS, err = GetNS(getCurrentThreadNetNSPath())
-               if err != nil {
-                       return
-               }
-               defer origNS.Close()
-
-               // create a new netns on the current thread
-               err = unix.Unshare(unix.CLONE_NEWNET)
-               if err != nil {
-                       return
-               }
-               defer origNS.Set()
-
-               // bind mount the new netns from the current thread onto the mount point
-               err = unix.Mount(getCurrentThreadNetNSPath(), nsPath, "none", unix.MS_BIND, "")
-               if err != nil {
-                       return
-               }
-
-               fd, err = os.Open(nsPath)
-               if err != nil {
-                       return
-               }
-       })()
-       wg.Wait()
-
-       if err != nil {
-               unix.Unmount(nsPath, unix.MNT_DETACH)
-               return nil, fmt.Errorf("failed to create namespace: %v", err)
-       }
-
-       return &netNS{file: fd, mounted: true}, nil
-}
-
 func (ns *netNS) Path() string {
        return ns.file.Name()
 }
@@ -216,29 +133,6 @@ func (ns *netNS) errorIfClosed() error {
        return nil
 }
 
-func (ns *netNS) Close() error {
-       if err := ns.errorIfClosed(); err != nil {
-               return err
-       }
-
-       if err := ns.file.Close(); err != nil {
-               return fmt.Errorf("Failed to close %q: %v", ns.file.Name(), err)
-       }
-       ns.closed = true
-
-       if ns.mounted {
-               if err := unix.Unmount(ns.file.Name(), unix.MNT_DETACH); err != nil {
-                       return fmt.Errorf("Failed to unmount namespace %s: %v", ns.file.Name(), err)
-               }
-               if err := os.RemoveAll(ns.file.Name()); err != nil {
-                       return fmt.Errorf("Failed to clean up namespace %s: %v", ns.file.Name(), err)
-               }
-               ns.mounted = false
-       }
-
-       return nil
-}
-
 func (ns *netNS) Do(toRun func(NetNS) error) error {
        if err := ns.errorIfClosed(); err != nil {
                return err
@@ -281,18 +175,6 @@ func (ns *netNS) Do(toRun func(NetNS) error) error {
        return innerError
 }
 
-func (ns *netNS) Set() error {
-       if err := ns.errorIfClosed(); err != nil {
-               return err
-       }
-
-       if _, _, err := unix.Syscall(unix.SYS_SETNS, ns.Fd(), uintptr(unix.CLONE_NEWNET), 0); err != 0 {
-               return fmt.Errorf("Error switching to ns %v: %v", ns.file.Name(), err)
-       }
-
-       return nil
-}
-
 // WithNetNSPath executes the passed closure under the given network
 // namespace, restoring the original namespace afterwards.
 func WithNetNSPath(nspath string, toRun func(NetNS) error) error {
diff --git a/pkg/ns/ns_linux.go b/pkg/ns/ns_linux.go
new file mode 100644 (file)
index 0000000..0746f15
--- /dev/null
@@ -0,0 +1,144 @@
+// Copyright 2015-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 ns
+
+import (
+       "crypto/rand"
+       "fmt"
+       "os"
+       "path"
+       "runtime"
+       "sync"
+
+       "golang.org/x/sys/unix"
+)
+
+func getCurrentThreadNetNSPath() string {
+       // /proc/self/ns/net returns the namespace of the main thread, not
+       // of whatever thread this goroutine is running on.  Make sure we
+       // use the thread's net namespace since the thread is switching around
+       return fmt.Sprintf("/proc/%d/task/%d/ns/net", os.Getpid(), unix.Gettid())
+}
+
+// Creates a new persistent network namespace and returns an object
+// representing that namespace, without switching to it
+func NewNS() (NetNS, error) {
+       const nsRunDir = "/var/run/netns"
+
+       b := make([]byte, 16)
+       _, err := rand.Reader.Read(b)
+       if err != nil {
+               return nil, fmt.Errorf("failed to generate random netns name: %v", err)
+       }
+
+       err = os.MkdirAll(nsRunDir, 0755)
+       if err != nil {
+               return nil, err
+       }
+
+       // create an empty file at the mount point
+       nsName := fmt.Sprintf("cni-%x-%x-%x-%x-%x", b[0:4], b[4:6], b[6:8], b[8:10], b[10:])
+       nsPath := path.Join(nsRunDir, nsName)
+       mountPointFd, err := os.Create(nsPath)
+       if err != nil {
+               return nil, err
+       }
+       mountPointFd.Close()
+
+       // Ensure the mount point is cleaned up on errors; if the namespace
+       // was successfully mounted this will have no effect because the file
+       // is in-use
+       defer os.RemoveAll(nsPath)
+
+       var wg sync.WaitGroup
+       wg.Add(1)
+
+       // do namespace work in a dedicated goroutine, so that we can safely
+       // Lock/Unlock OSThread without upsetting the lock/unlock state of
+       // the caller of this function
+       var fd *os.File
+       go (func() {
+               defer wg.Done()
+               runtime.LockOSThread()
+
+               var origNS NetNS
+               origNS, err = GetNS(getCurrentThreadNetNSPath())
+               if err != nil {
+                       return
+               }
+               defer origNS.Close()
+
+               // create a new netns on the current thread
+               err = unix.Unshare(unix.CLONE_NEWNET)
+               if err != nil {
+                       return
+               }
+               defer origNS.Set()
+
+               // bind mount the new netns from the current thread onto the mount point
+               err = unix.Mount(getCurrentThreadNetNSPath(), nsPath, "none", unix.MS_BIND, "")
+               if err != nil {
+                       return
+               }
+
+               fd, err = os.Open(nsPath)
+               if err != nil {
+                       return
+               }
+       })()
+       wg.Wait()
+
+       if err != nil {
+               unix.Unmount(nsPath, unix.MNT_DETACH)
+               return nil, fmt.Errorf("failed to create namespace: %v", err)
+       }
+
+       return &netNS{file: fd, mounted: true}, nil
+}
+
+func (ns *netNS) Close() error {
+       if err := ns.errorIfClosed(); err != nil {
+               return err
+       }
+
+       if err := ns.file.Close(); err != nil {
+               return fmt.Errorf("Failed to close %q: %v", ns.file.Name(), err)
+       }
+       ns.closed = true
+
+       if ns.mounted {
+               if err := unix.Unmount(ns.file.Name(), unix.MNT_DETACH); err != nil {
+                       return fmt.Errorf("Failed to unmount namespace %s: %v", ns.file.Name(), err)
+               }
+               if err := os.RemoveAll(ns.file.Name()); err != nil {
+                       return fmt.Errorf("Failed to clean up namespace %s: %v", ns.file.Name(), err)
+               }
+               ns.mounted = false
+       }
+
+       return nil
+}
+
+func (ns *netNS) Set() error {
+       if err := ns.errorIfClosed(); err != nil {
+               return err
+       }
+
+       if _, _, err := unix.Syscall(unix.SYS_SETNS, ns.Fd(), uintptr(unix.CLONE_NEWNET), 0); err != 0 {
+               return fmt.Errorf("Error switching to ns %v: %v", ns.file.Name(), err)
+       }
+
+       return nil
+}
diff --git a/pkg/ns/ns_unspecified.go b/pkg/ns/ns_unspecified.go
new file mode 100644 (file)
index 0000000..da8b179
--- /dev/null
@@ -0,0 +1,33 @@
+// Copyright 2015-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.
+
+// +build !linux
+
+package ns
+
+func getCurrentThreadNetNSPath() string {
+       return ""
+}
+
+func NewNS() (NetNS, error) {
+       return nil, NotImplementedError
+}
+
+func (ns *netNS) Close() error {
+       return NotImplementedError
+}
+
+func (ns *netNS) Set() error {
+       return NotImplementedError
+}