Use netlink instead of shelling out to weave ps

This commit is contained in:
Adam Harrison committed 2016-02-04 12:51:18 +00:00
1 parent f37eb4b77d
commit 65c48707f6
10 files changed
+182 -63

No files matched your search

+3
View File
@@ -52,3 +52,6 @@
[submodule "vendor/github.com/weaveworks/mesh"]
path = vendor/github.com/weaveworks/mesh
url = https://github.com/weaveworks/mesh
[submodule "vendor/github.com/vishvananda/netns"]
path = vendor/github.com/vishvananda/netns
url = https://github.com/vishvananda/netns.git
+78
View File
@@ -1,6 +1,11 @@
package common
import (
"fmt"
"github.com/vishvananda/netlink"
"github.com/vishvananda/netns"
"net"
"runtime"
"strings"
)
@@ -18,3 +23,76 @@ func ErrorMessages(errors []error) string {
}
return strings.Join(result, "\n")
}
func WithNetNS(ns netns.NsHandle, work func() error) error {
runtime.LockOSThread()
defer runtime.UnlockOSThread()
oldNs, err := netns.Get()
if err == nil {
defer oldNs.Close()
err = netns.Set(ns)
if err == nil {
defer netns.Set(oldNs)
err = work()
}
}
return nil
}
type NetDev struct {
MAC net.HardwareAddr
CIDRs []*net.IPNet
}
// Search the network namespace of a process for interfaces matching a predicate
func FindNetDevs(procPath string, processID int, match func(string) bool) ([]NetDev, error) {
var netDevs []NetDev
ns, err := netns.GetFromPath(fmt.Sprintf("%s/%d/ns/net", procPath, processID))
if err != nil {
return nil, err
}
defer ns.Close()
err = WithNetNS(ns, func() error {
links, err := netlink.LinkList()
if err != nil {
return err
}
for _, link := range links {
if match(link.Attrs().Name) {
addrs, err := netlink.AddrList(link, netlink.FAMILY_V4)
if err != nil {
return err
}
netDev := NetDev{MAC: link.Attrs().HardwareAddr}
for _, addr := range addrs {
netDev.CIDRs = append(netDev.CIDRs, addr.IPNet)
}
netDevs = append(netDevs, netDev)
}
}
return nil
})
return netDevs, err
}
// Lookup the weave interface of a container
func GetWeaveNetDevs(procPath string, processID int) ([]NetDev, error) {
return FindNetDevs(procPath, processID, func(name string) bool {
return strings.HasPrefix(name, "ethwe")
})
}
// Get the weave bridge interface
func GetBridgeNetDev(procPath, bridgeName string) ([]NetDev, error) {
return FindNetDevs(procPath, 1, func(name string) bool {
return name == bridgeName
})
}
+6
View File
@@ -14,6 +14,7 @@ import (
var (
version = "(unreleased version)"
defaultDockerHost = "unix:///var/run/docker.sock"
defaultProcPath = "/proc"
)
func main() {
@@ -68,6 +69,11 @@ func main() {
c.DockerHost = dockerHost
}
c.ProcPath = defaultProcPath
if procPath := os.Getenv("PROCFS"); procPath != "" {
c.ProcPath = procPath
}
p, err := proxy.NewProxy(c)
if err != nil {
Log.Fatalf("Could not start proxy: %s", err)
+55
View File
@@ -0,0 +1,55 @@
package main
import (
"fmt"
"github.com/fsouza/go-dockerclient"
"github.com/weaveworks/weave/common"
)
func containerAddrs(args []string) error {
if len(args) < 2 {
cmdUsage("container-addrs", "<procPath> <bridgeName> [containerID ...]")
}
procPath := args[0]
bridgeName := args[1]
c, err := docker.NewVersionedClientFromEnv("1.18")
if err != nil {
return err
}
for _, containerID := range args[2:] {
netDevs, err := getNetDevs(procPath, bridgeName, c, containerID)
if err != nil {
if _, ok := err.(*docker.NoSuchContainer); ok {
continue
}
return err
}
for _, netDev := range netDevs {
fmt.Printf("%12s %s", containerID, netDev.MAC.String())
for _, cidr := range netDev.CIDRs {
prefixLength, _ := cidr.Mask.Size()
fmt.Printf(" %v/%v", cidr.IP, prefixLength)
}
fmt.Println()
}
}
return nil
}
func getNetDevs(procPath, bridgeName string, c *docker.Client, containerID string) ([]common.NetDev, error) {
if containerID == "weave:expose" {
return common.GetBridgeNetDev(procPath, bridgeName)
}
container, err := c.InspectContainer(containerID)
if err != nil {
return nil, err
}
return common.GetWeaveNetDevs(procPath, container.State.Pid)
}
+1
View File
@@ -18,6 +18,7 @@ func init() {
"add-datapath-interface": addDatapathInterface,
"create-plugin-network": createPluginNetwork,
"remove-plugin-network": removePluginNetwork,
"container-addrs": containerAddrs,
}
}
-31
View File
@@ -3,10 +3,8 @@ package proxy
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"net"
"net/http"
"os"
"os/exec"
@@ -128,35 +126,6 @@ func inspectContainerInPath(client *docker.Client, path string) (*docker.Contain
return container, err
}
func weaveContainerIPs(containerID string) (mac string, ips []net.IP, nets []*net.IPNet, err error) {
stdout, stderr, err := callWeave("ps", containerID)
if err != nil || len(stderr) > 0 {
err = errors.New(string(stderr))
return
}
if len(stdout) <= 0 {
return
}
fields := strings.Fields(string(stdout))
if len(fields) < 2 {
return
}
mac = fields[1]
var ip net.IP
var ipnet *net.IPNet
for _, cidr := range fields[2:] {
ip, ipnet, err = net.ParseCIDR(cidr)
if err != nil {
return
}
ips = append(ips, ip)
nets = append(nets, ipnet)
}
return
}
func addVolume(hostConfig jsonObject, source, target, mode string) error {
configBinds, err := hostConfig.StringArray("Binds")
if err != nil {
+20
View File
@@ -1,6 +1,7 @@
package proxy
import (
"encoding/json"
"fmt"
)
@@ -45,6 +46,25 @@ func (j jsonObject) String(key string) (string, error) {
return result, nil
}
func (j jsonObject) Int(key string) (int, error) {
iface, ok := j[key]
if !ok || iface == nil {
return 0, nil
}
result, ok := iface.(json.Number)
if !ok {
return 0, &UnmarshalWrongTypeError{key, "json.Number", iface}
}
i64, err := result.Int64()
if err != nil {
return 0, err
}
return int(i64), nil
}
func (j jsonObject) StringArray(key string) ([]string, error) {
iface, ok := j[key]
if !ok || iface == nil {
+16 -5
View File
@@ -62,6 +62,7 @@ type Config struct {
WithoutDNS bool
NoMulticastRoute bool
DockerHost string
ProcPath string
}
type wait struct {
@@ -590,11 +591,21 @@ func (proxy *Proxy) updateContainerNetworkSettings(container jsonObject) error {
return err
}
state, err := container.Object("State")
if err != nil {
return err
}
pid, err := state.Int("Pid")
if err != nil {
return err
}
if err := proxy.waitForStartByIdent(containerID); err != nil {
return err
}
mac, ips, nets, err := weaveContainerIPs(containerID)
if err != nil || len(ips) == 0 {
netDevs, err := GetWeaveNetDevs(proxy.ProcPath, pid)
if err != nil || len(netDevs) == 0 || len(netDevs[0].CIDRs) == 0 {
return err
}
@@ -602,9 +613,9 @@ func (proxy *Proxy) updateContainerNetworkSettings(container jsonObject) error {
if err != nil {
return err
}
networkSettings["MacAddress"] = mac
networkSettings["IPAddress"] = ips[0].String()
networkSettings["IPPrefixLen"], _ = nets[0].Mask.Size()
networkSettings["MacAddress"] = netDevs[0].MAC.String()
networkSettings["IPAddress"] = netDevs[0].CIDRs[0].IP.String()
networkSettings["IPPrefixLen"], _ = netDevs[0].CIDRs[0].Mask.Size()
return nil
}
+2 -27
View File
@@ -914,10 +914,6 @@ detach() {
netnsenter ip link del $CONTAINER_IFNAME type veth
}
container_ip_addr_show() {
! container_in_host_ns && netnsenter ip addr show
}
######################################################################
# functions for interacting with containers
######################################################################
@@ -1043,34 +1039,13 @@ wait_for_status() {
done
}
# Parse the output of `ip addr show`, outputing weave addresses of kind $1
addrs_from_ip_addr_show() {
while read first second rest ; do
if [ "$first" != "${first%:}" ] ; then
iname="${second%:}"
elif [ "$first" = "$1" -a \( "$iname" = "weave" -o "$iname" != "${iname#ethwe}" \) ] ; then
echo $second
fi
done
}
# Call $1 for all containers, passing container ID, all MACs and all IPs
with_container_addresses() {
COMMAND=$1
shift 1
for CONTAINER_ID in "$@" ; do
if [ "$CONTAINER_ID" = "weave:expose" ] ; then
ADDRS_CMD="ip addr show dev $BRIDGE"
else
ADDRS_CMD="with_container_netns $CONTAINER_ID container_ip_addr_show"
fi
if CONTAINER_ADDRS=$($ADDRS_CMD 2>/dev/null) ; then
CONTAINER_MAC=$(echo "$CONTAINER_ADDRS" | addrs_from_ip_addr_show 'link/ether')
CONTAINER_IPS=$(echo "$CONTAINER_ADDRS" | addrs_from_ip_addr_show 'inet')
if [ -n "$CONTAINER_MAC$CONTAINER_IPS" ] ; then
util_op container-addrs $PROCFS $BRIDGE "$@" | while read CONTAINER_ID CONTAINER_MAC CONTAINER_IPS; do
$COMMAND "$CONTAINER_ID" "$CONTAINER_MAC" "$CONTAINER_IPS"
fi
fi
done
}