Use netlink instead of shelling out to weave ps
This commit is contained in:
1 parent
f37eb4b77d
commit
65c48707f6
10 files changed
+183
-64
No files matched your search
@@ -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
|
||||
@@ -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
|
||||
})
|
||||
}
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
@@ -18,6 +18,7 @@ func init() {
|
||||
"add-datapath-interface": addDatapathInterface,
|
||||
"create-plugin-network": createPluginNetwork,
|
||||
"remove-plugin-network": removePluginNetwork,
|
||||
"container-addrs": containerAddrs,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
@@ -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
|
||||
}
|
||||
|
||||
|
||||
+1
Submodule vendor/github.com/vishvananda/netns added at f0b8d0aad3.
@@ -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
|
||||
$COMMAND "$CONTAINER_ID" "$CONTAINER_MAC" "$CONTAINER_IPS"
|
||||
fi
|
||||
fi
|
||||
|
||||
util_op container-addrs $PROCFS $BRIDGE "$@" | while read CONTAINER_ID CONTAINER_MAC CONTAINER_IPS; do
|
||||
$COMMAND "$CONTAINER_ID" "$CONTAINER_MAC" "$CONTAINER_IPS"
|
||||
done
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user