Compare commits

..

16 Commits

Author SHA1 Message Date
5c3c171642 Merge pull request #239 from steveeJ/master
MAINTAINERS: remove @zachgersh, add @dcbw
2016-06-02 09:00:07 -07:00
4a292cd451 Merge pull request #218 from steveeJ/roadmap
Add ROADMAP document
2016-06-02 16:51:57 +01:00
f82af22b10 ROADMAP: initial version 2016-06-02 17:50:14 +02:00
4f9faf60bb MAINTAINERS: remove @zachgersh, add @dcbw
Thank you Zach for all the great work done on CNI, farewell!
At the same time we are happy to welcome Dan amongst us who has already
contributed lots of valuable work!
2016-06-02 01:15:24 +02:00
f44f4cf953 Merge pull request #219 from squaremo/more-contrib
docs: details on PR acceptance policy
2016-06-01 16:03:17 +02:00
ddc0ca4791 docs: details on PR acceptance policy 2016-06-01 12:23:21 +01:00
e90d8c12b1 Merge pull request #228 from jieyu/add_mesos
Added Mesos to CNI users.
2016-05-30 11:13:34 +01:00
ffff8ac2fd Merge pull request #231 from steveeJ/ns-verifiy-errors
pkg/ns: introduce error types to indicate NS verification
2016-05-27 15:57:40 +02:00
35f3a090b2 pkg/ns: introduce error types indicate NS verification 2016-05-27 13:50:16 +02:00
131ecc4055 Merge pull request #230 from steveeJ/netns-optional-on-del
plugins: don't require CNI_NETNS for DEL command
2016-05-27 13:49:05 +02:00
d582c9ce8f skel/test: add case for empty NETNS 2016-05-27 12:26:42 +02:00
72337159c1 plugins: don't require CNI_NETNS for DEL command
This will allow to free up the IPAM allocations when the caller doesn't
have access to the network namespace anymore, e.g. due to a reboot.
2016-05-27 10:57:39 +02:00
7f90f9d559 pkg/skel: allow arg requriements specified by CMD 2016-05-27 10:56:24 +02:00
d6674e0f49 README: add Mesos as CNI users 2016-05-26 09:42:10 -07:00
6f63d9d707 Merge pull request #227 from steveeJ/ns-verify
pkg/ns: consider PROCFS during NS verification
2016-05-26 13:22:29 +02:00
3bab8a2805 pkg/ns: consider PROCFS during NS verification
This is an attempt to bring compatibility with Kernel <3.19, where NSFS
where PROCFS was used for network namespaces.
2016-05-26 12:42:50 +02:00
12 changed files with 196 additions and 43 deletions

View File

@ -1,11 +1,11 @@
# How to Contribute # How to Contribute
cni is [Apache 2.0 licensed](LICENSE) and accepts contributions via GitHub CNI is [Apache 2.0 licensed](LICENSE) and accepts contributions via GitHub
pull requests. This document outlines some of the conventions on development pull requests. This document outlines some of the conventions on development
workflow, commit message formatting, contact points and other resources to make workflow, commit message formatting, contact points and other resources to make
it easier to get your contribution accepted. it easier to get your contribution accepted.
We welcome improvements to documentation as well as to code. We gratefully welcome improvements to documentation as well as to code.
# Certificate of Origin # Certificate of Origin
@ -41,7 +41,19 @@ This is a rough outline of how to prepare a contribution:
- Make sure any new code files have a license header. - Make sure any new code files have a license header.
- Submit a pull request to the original repository. - Submit a pull request to the original repository.
Thanks for your contributions! # Acceptance policy
These things will make a PR more likely to be accepted:
* a well-described requirement
* tests for new code
* tests for old code!
* new code follows the conventions in old code
* a good commit message (see below)
In general, we will merge a PR once two maintainers have endorsed it.
Trivial changes (e.g., corrections to spelling) may get waved through.
For substantial changes, more people may become involved, and you might get asked to resubmit the PR or divide the changes into more than one PR.
### Format of the Commit Message ### Format of the Commit Message

View File

@ -1,5 +1,5 @@
Dan Williams <dcbw@redhat.com> (@dcbw)
Gabe Rosenhouse <grosenhouse@pivotal.io> (@rosenhouse) Gabe Rosenhouse <grosenhouse@pivotal.io> (@rosenhouse)
Michael Bridgen <michael@weave.works> (@squaremo) Michael Bridgen <michael@weave.works> (@squaremo)
Stefan Junker <stefan.junker@coreos.com> (@steveeJ) Stefan Junker <stefan.junker@coreos.com> (@steveeJ)
Tom Denham <tom.denham@metaswitch.com> (@tomdee) Tom Denham <tom.denham@metaswitch.com> (@tomdee)
Zach Gershman <zachgersh@gmail.com> (@zachgersh)

View File

@ -30,6 +30,7 @@ To avoid duplication, we think it is prudent to define a common interface betwee
- [Weave - a multi-host Docker network](https://github.com/weaveworks/weave) - [Weave - a multi-host Docker network](https://github.com/weaveworks/weave)
- [Project Calico - a layer 3 virtual network](https://github.com/projectcalico/calico-cni) - [Project Calico - a layer 3 virtual network](https://github.com/projectcalico/calico-cni)
- [Contiv Networking - policy networking for various use cases](https://github.com/contiv/netplugin) - [Contiv Networking - policy networking for various use cases](https://github.com/contiv/netplugin)
- [Mesos - a distributed systems kernel](https://github.com/apache/mesos/blob/master/docs/cni.md)
## Contributing to CNI ## Contributing to CNI

33
ROADMAP.md Normal file
View File

@ -0,0 +1,33 @@
# CNI Roadmap
This document defines a high level roadmap for CNI development.
The list below is not complete, and we advise to get the current project state from the [milestones defined in GitHub](https://github.com/containernetworking/cni/milestones).
## CNI Milestones
### [v0.2.0](https://github.com/containernetworking/cni/milestones/v0.2.0)
* Signed release binaries
* Introduction of a testing strategy/framework
### [v0.3.0](https://github.com/containernetworking/cni/milestones/v0.3.0)
* Further increase test coverage
* Simpler default route handling in bridge plugin
* Clarify project description, documentation and contribution guidelines
### [v0.4.0](https://github.com/containernetworking/cni/milestones/v0.4.0)
* Further increase test coverage
* Simpler bridging of host interface
* Improve IPAM allocator predictability
* Allow in- and output of arbitrary K/V pairs for plugins
### [v1.0.0](https://github.com/containernetworking/cni/milestones/v1.0.0)
- Plugin composition functionality
- IPv6 support
- Stable SPEC
- Strategy and tooling for backwards compatibility
- Complete test coverage
- Integrate build artefact generation with CI

View File

@ -20,6 +20,7 @@ import (
"os" "os"
"path" "path"
"runtime" "runtime"
"strings"
"sync" "sync"
"syscall" "syscall"
@ -74,38 +75,66 @@ func GetCurrentNS() (NetNS, error) {
return GetNS(getCurrentThreadNetNSPath()) return GetNS(getCurrentThreadNetNSPath())
} }
// Returns an object representing the namespace referred to by @path const (
func GetNS(nspath string) (NetNS, error) { // https://github.com/torvalds/linux/blob/master/include/uapi/linux/magic.h
fd, err := os.Open(nspath) NSFS_MAGIC = 0x6e736673
if err != nil { PROCFS_MAGIC = 0x9fa0
return nil, fmt.Errorf("Failed to open %v: %v", nspath, err) )
type NSPathNotExistErr struct{ msg string }
func (e NSPathNotExistErr) Error() string { return e.msg }
type NSPathNotNSErr struct{ msg string }
func (e NSPathNotNSErr) Error() string { return e.msg }
func IsNSorErr(nspath string) error {
stat := syscall.Statfs_t{}
if err := syscall.Statfs(nspath, &stat); err != nil {
if os.IsNotExist(err) {
err = NSPathNotExistErr{msg: fmt.Sprintf("failed to Statfs %q: %v", nspath, err)}
} else {
err = fmt.Errorf("failed to Statfs %q: %v", nspath, err)
}
return err
} }
isNSFS, err := IsNSFS(nspath) switch stat.Type {
case PROCFS_MAGIC:
// Kernel < 3.19
validPathContent := "ns/"
validName := strings.Contains(nspath, validPathContent)
if !validName {
return NSPathNotNSErr{msg: fmt.Sprintf("path %q doesn't contain %q", nspath, validPathContent)}
}
return nil
case NSFS_MAGIC:
// Kernel >= 3.19
return nil
default:
return NSPathNotNSErr{msg: fmt.Sprintf("unknown FS magic on %q: %x", nspath, stat.Type)}
}
}
// Returns an object representing the namespace referred to by @path
func GetNS(nspath string) (NetNS, error) {
err := IsNSorErr(nspath)
if err != nil { if err != nil {
fd.Close()
return nil, err return nil, err
} }
if !isNSFS {
fd.Close() fd, err := os.Open(nspath)
return nil, fmt.Errorf("%v is not of type NSFS", nspath) if err != nil {
return nil, err
} }
return &netNS{file: fd}, nil return &netNS{file: fd}, nil
} }
// Returns whether or not the nspath argument points to a network namespace
func IsNSFS(nspath string) (bool, error) {
const NSFS_MAGIC = 0x6e736673
stat := syscall.Statfs_t{}
if err := syscall.Statfs(nspath, &stat); err != nil {
return false, fmt.Errorf("failed to Statfs %q: %v", nspath, err)
}
return stat.Type == NSFS_MAGIC, nil
}
// Creates a new persistent network namespace and returns an object // Creates a new persistent network namespace and returns an object
// representing that namespace, without switching to it // representing that namespace, without switching to it
func NewNS() (NetNS, error) { func NewNS() (NetNS, error) {

View File

@ -180,7 +180,9 @@ var _ = Describe("Linux namespace operations", func() {
defer os.Remove(nspath) defer os.Remove(nspath)
_, err = ns.GetNS(nspath) _, err = ns.GetNS(nspath)
Expect(err).To(MatchError(fmt.Sprintf("%v is not of type NSFS", nspath))) Expect(err).To(HaveOccurred())
Expect(err).To(BeAssignableToTypeOf(ns.NSPathNotNSErr{}))
Expect(err).NotTo(BeAssignableToTypeOf(ns.NSPathNotExistErr{}))
}) })
}) })
@ -212,12 +214,11 @@ var _ = Describe("Linux namespace operations", func() {
}) })
}) })
Describe("IsNSFS", func() { Describe("IsNSorErr", func() {
It("should detect a namespace", func() { It("should detect a namespace", func() {
createdNetNS, err := ns.NewNS() createdNetNS, err := ns.NewNS()
isNSFS, err := ns.IsNSFS(createdNetNS.Path()) err = ns.IsNSorErr(createdNetNS.Path())
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
Expect(isNSFS).To(Equal(true))
}) })
It("should refuse other paths", func() { It("should refuse other paths", func() {
@ -228,9 +229,17 @@ var _ = Describe("Linux namespace operations", func() {
nspath := tempFile.Name() nspath := tempFile.Name()
defer os.Remove(nspath) defer os.Remove(nspath)
isNSFS, err := ns.IsNSFS(nspath) err = ns.IsNSorErr(nspath)
Expect(err).NotTo(HaveOccurred()) Expect(err).To(HaveOccurred())
Expect(isNSFS).To(Equal(false)) Expect(err).To(BeAssignableToTypeOf(ns.NSPathNotNSErr{}))
Expect(err).NotTo(BeAssignableToTypeOf(ns.NSPathNotExistErr{}))
})
It("should error on non-existing paths", func() {
err := ns.IsNSorErr("/tmp/IDoNotExist")
Expect(err).To(HaveOccurred())
Expect(err).To(BeAssignableToTypeOf(ns.NSPathNotExistErr{}))
Expect(err).NotTo(BeAssignableToTypeOf(ns.NSPathNotNSErr{}))
}) })
}) })
}) })

View File

@ -36,28 +36,72 @@ type CmdArgs struct {
StdinData []byte StdinData []byte
} }
type reqForCmdEntry map[string]bool
// PluginMain is the "main" for a plugin. It accepts // PluginMain is the "main" for a plugin. It accepts
// two callback functions for add and del commands. // two callback functions for add and del commands.
func PluginMain(cmdAdd, cmdDel func(_ *CmdArgs) error) { func PluginMain(cmdAdd, cmdDel func(_ *CmdArgs) error) {
var cmd, contID, netns, ifName, args, path string var cmd, contID, netns, ifName, args, path string
vars := []struct { vars := []struct {
name string name string
val *string val *string
req bool reqForCmd reqForCmdEntry
}{ }{
{"CNI_COMMAND", &cmd, true}, {
{"CNI_CONTAINERID", &contID, false}, "CNI_COMMAND",
{"CNI_NETNS", &netns, true}, &cmd,
{"CNI_IFNAME", &ifName, true}, reqForCmdEntry{
{"CNI_ARGS", &args, false}, "ADD": true,
{"CNI_PATH", &path, true}, "DEL": true,
},
},
{
"CNI_CONTAINERID",
&contID,
reqForCmdEntry{
"ADD": false,
"DEL": false,
},
},
{
"CNI_NETNS",
&netns,
reqForCmdEntry{
"ADD": true,
"DEL": false,
},
},
{
"CNI_IFNAME",
&ifName,
reqForCmdEntry{
"ADD": true,
"DEL": true,
},
},
{
"CNI_ARGS",
&args,
reqForCmdEntry{
"ADD": false,
"DEL": false,
},
},
{
"CNI_PATH",
&path,
reqForCmdEntry{
"ADD": true,
"DEL": true,
},
},
} }
argsMissing := false argsMissing := false
for _, v := range vars { for _, v := range vars {
*v.val = os.Getenv(v.name) *v.val = os.Getenv(v.name)
if v.req && *v.val == "" { if v.reqForCmd[cmd] && *v.val == "" {
log.Printf("%v env variable missing", v.name) log.Printf("%v env variable missing", v.name)
argsMissing = true argsMissing = true
} }

View File

@ -71,5 +71,14 @@ var _ = Describe("Skel", func() {
// Expect(err).NotTo(HaveOccurred()) // Expect(err).NotTo(HaveOccurred())
// PluginMain(fErr, nil) // PluginMain(fErr, nil)
// }) // })
It("should not fail with DEL and no NETNS and noop callback", func() {
err := os.Setenv("CNI_COMMAND", "DEL")
Expect(err).NotTo(HaveOccurred())
err = os.Unsetenv("CNI_NETNS")
Expect(err).NotTo(HaveOccurred())
PluginMain(nil, fNoop)
})
}) })
}) })

View File

@ -289,6 +289,10 @@ func cmdDel(args *skel.CmdArgs) error {
return err return err
} }
if args.Netns == "" {
return nil
}
var ipn *net.IPNet var ipn *net.IPNet
err = ns.WithNetNSPath(args.Netns, func(_ ns.NetNS) error { err = ns.WithNetNSPath(args.Netns, func(_ ns.NetNS) error {
var err error var err error

View File

@ -152,6 +152,10 @@ func cmdDel(args *skel.CmdArgs) error {
return err return err
} }
if args.Netns == "" {
return nil
}
return ns.WithNetNSPath(args.Netns, func(_ ns.NetNS) error { return ns.WithNetNSPath(args.Netns, func(_ ns.NetNS) error {
return ip.DelLinkByName(args.IfName) return ip.DelLinkByName(args.IfName)
}) })

View File

@ -170,6 +170,10 @@ func cmdDel(args *skel.CmdArgs) error {
return err return err
} }
if args.Netns == "" {
return nil
}
return ns.WithNetNSPath(args.Netns, func(_ ns.NetNS) error { return ns.WithNetNSPath(args.Netns, func(_ ns.NetNS) error {
return ip.DelLinkByName(args.IfName) return ip.DelLinkByName(args.IfName)
}) })

View File

@ -199,6 +199,10 @@ func cmdDel(args *skel.CmdArgs) error {
return err return err
} }
if args.Netns == "" {
return nil
}
var ipn *net.IPNet var ipn *net.IPNet
err := ns.WithNetNSPath(args.Netns, func(_ ns.NetNS) error { err := ns.WithNetNSPath(args.Netns, func(_ ns.NetNS) error {
var err error var err error