Skip to content

Commit

Permalink
Enumerate docker network namespaces a different way (#11)
Browse files Browse the repository at this point in the history
Should solve many of the issues where free-ips were not located correctly in Docker. Also cleans up some of the nl/desc logic repetition.
  • Loading branch information
theatrus authored Dec 21, 2017
1 parent cdf4576 commit dbdced3
Show file tree
Hide file tree
Showing 4 changed files with 85 additions and 75 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
vendor/
vendor.orig/

cni-ipvlan-vpc-k8s-*
/cni-ipvlan-vpc-k8s-*
*.tar.gz

# Test binary, build with `go test -c`
Expand Down
2 changes: 1 addition & 1 deletion Gopkg.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

99 changes: 26 additions & 73 deletions nl/desc.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,10 @@ import (
"io/ioutil"
"net"
"os"
"path/filepath"

"github.com/containernetworking/plugins/pkg/ns"
"github.com/vishvananda/netlink"
"github.com/vishvananda/netns"

"github.com/docker/docker/api/types"
"github.com/docker/docker/client"
"golang.org/x/net/context"
)

// BoundIP contains an IPNet / Label pair
Expand Down Expand Up @@ -46,44 +43,33 @@ func getIpsOnHandle(handle *netlink.Handle) ([]BoundIP, error) {
return foundIps, nil
}

// With a heavy heart and deep internal sadness, we support Docker
func runningDockerContainers() (containerIds []string, err error) {
cli, err := client.NewEnvClient()
if err != nil {
return nil, err
}

containers, err := cli.ContainerList(context.Background(), types.ContainerListOptions{})
if err != nil {
return nil, err
}

for _, container := range containers {
containerIds = append(containerIds, container.ID)
}
return containerIds, nil
}

// GetIPs returns IPs allocated to interfaces, in all namespaces
// TODO: Remove addresses on control plane interfaces, filters
func GetIPs() ([]BoundIP, error) {

originNs, err := netns.Get()
if err != nil {
return nil, err
}
defer originNs.Close()
var namespaces []string

files, err := ioutil.ReadDir("/var/run/netns/")
if err != nil {
_, err = fmt.Fprintln(os.Stderr, "Couldn't enumerate named namespaces")
if err != nil {
// Ignore this error
}
files = []os.FileInfo{}
} else {
for _, file := range files {
namespaces = append(namespaces,
filepath.Join("/var/run/netns", file.Name()))
}
}

// First get all the IPs on the first handle
// Check for running docker containers
containers, err := runningDockerContainers()
if err == nil {
dockerNamespaces := dockerNetworkNamespaces(containers)
namespaces = append(namespaces, dockerNamespaces...)
}

// First get all the IPs in the main namespace
handle, err := netlink.NewHandle()
if err != nil {
return nil, err
Expand All @@ -93,55 +79,22 @@ func GetIPs() ([]BoundIP, error) {
return nil, err
}

// Enter each _named_ namesapce, get handles
for _, f := range files {
nsHandle, err := netns.GetFromName(f.Name())
if err != nil {
return nil, err
}
handle, err = netlink.NewHandleAt(nsHandle)
if err != nil {
return nil, err
}

newIps, err := getIpsOnHandle(handle)
if err != nil {
return nil, err
}
foundIps = append(foundIps, newIps...)

handle.Delete()
err = nsHandle.Close()
if err != nil {
panic(err)
}
}
// Enter each namesapce, get handles
for _, nsPath := range namespaces {
err := ns.WithNetNSPath(nsPath, func(_ ns.NetNS) error {

// Check for running docker containers
containers, err := runningDockerContainers()
if err == nil {
// Enter each docker container, get handles
for _, f := range containers {
nsHandle, err := netns.GetFromDocker(f)
handle, err = netlink.NewHandle()
if err != nil {
return nil, err
}
handle, err = netlink.NewHandleAt(nsHandle)
if err != nil {
return nil, err
return err
}
defer handle.Delete()

newIps, err := getIpsOnHandle(handle)
if err != nil {
return nil, err
}
foundIps = append(foundIps, newIps...)

handle.Delete()
err = nsHandle.Close()
if err != nil {
panic(err)
}
return err
})
if err != nil {
fmt.Fprintf(os.Stderr, "Enumerating namespace failure %v", err)
}
}

Expand Down
57 changes: 57 additions & 0 deletions nl/docker.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package nl

import (
"fmt"

"github.com/docker/docker/api/types"
"github.com/docker/docker/client"
"golang.org/x/net/context"
)

// With a heavy heart and deep internal sadness, we support Docker
func runningDockerContainers() (containerIDs []string, err error) {
cli, err := client.NewEnvClient()
if err != nil {
return nil, err
}
defer cli.Close()

containers, err := cli.ContainerList(context.Background(), types.ContainerListOptions{})
if err != nil {
return nil, err
}

for _, container := range containers {
containerIDs = append(containerIDs, container.ID)
}
return containerIDs, nil
}

func dockerNetworkNamespace(containerID string) (string, error) {
cli, err := client.NewEnvClient()
if err != nil {
return "", err
}
defer cli.Close()
r, err := cli.ContainerInspect(context.Background(), containerID)
if err != nil {
return "", nil
}

if r.State.Pid == 0 {
// Container has exited
return "", fmt.Errorf("Container has exited %v", containerID)
}
return fmt.Sprintf("/proc/%v/ns/net", r.State.Pid), nil
}

// Retrieve all namespaces from all running docker containers
func dockerNetworkNamespaces(containerIDs []string) (namespaces []string) {
for _, containerID := range containerIDs {
cid, err := dockerNetworkNamespace(containerID)
if err == nil && len(cid) > 0 {
namespaces = append(namespaces, cid)
}
}
return
}

0 comments on commit dbdced3

Please sign in to comment.