Skip to content

Commit 8b45eb8

Browse files
committed
Implement helper for extracting OVS-managed bridges from an iface list
The helper makes use of the 'ovs-vsctl' command to get a list of OVS-managed bridges and use this information to filter a provided list of interfaces.
1 parent fc61197 commit 8b45eb8

File tree

2 files changed

+111
-0
lines changed

2 files changed

+111
-0
lines changed

container/broker/broker.go

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
package broker
55

66
import (
7+
"os/exec"
78
"strings"
89

910
"github.com/juju/collections/set"
@@ -25,6 +26,9 @@ import (
2526

2627
var logger = loggo.GetLogger("juju.container.broker")
2728

29+
// Overridden by tests
30+
var getCommandOutput = func(cmd *exec.Cmd) ([]byte, error) { return cmd.Output() }
31+
2832
//go:generate go run github.com/golang/mock/mockgen -package mocks -destination mocks/apicalls_mock.go github.com/juju/juju/container/broker APICalls
2933
type APICalls interface {
3034
ContainerConfig() (params.ContainerConfig, error)
@@ -261,3 +265,33 @@ func proxyConfigurationFromContainerCfg(cfg params.ContainerConfig) instancecfg.
261265
SnapStoreProxyURL: cfg.SnapStoreProxyURL,
262266
}
263267
}
268+
269+
// ovsManagedBridges returns a filtered version of ifaceList that only contains
270+
// bridge interfaces managed by openvswitch.
271+
func ovsManagedBridges(ifaceList corenetwork.InterfaceInfos) (corenetwork.InterfaceInfos, error) {
272+
if _, err := exec.LookPath("ovs-vsctl"); err != nil {
273+
// ovs tools not installed; nothing to do
274+
if execErr, isExecErr := err.(*exec.Error); isExecErr && execErr.Unwrap() == exec.ErrNotFound {
275+
return nil, nil
276+
}
277+
278+
return nil, errors.Annotate(err, "ovsManagedBridges: looking for ovs-vsctl")
279+
}
280+
281+
// Query list of ovs-managed device names
282+
res, err := getCommandOutput(exec.Command("ovs-vsctl", "list-br"))
283+
if err != nil {
284+
return nil, errors.Annotate(err, "querying ovs-managed bridges via ovs-vsctl")
285+
}
286+
287+
ovsBridges := set.NewStrings()
288+
for _, iface := range strings.Split(string(res), "\n") {
289+
if iface = strings.TrimSpace(iface); iface != "" {
290+
ovsBridges.Add(iface)
291+
}
292+
}
293+
294+
return ifaceList.Filter(func(iface corenetwork.InterfaceInfo) bool {
295+
return ovsBridges.Contains(iface.InterfaceName)
296+
}), nil
297+
}
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
// Copyright 2020 Canonical Ltd.
2+
// Licensed under the AGPLv3, see LICENCE file for details.
3+
4+
package broker
5+
6+
import (
7+
"os/exec"
8+
9+
"github.com/juju/testing"
10+
jc "github.com/juju/testing/checkers"
11+
gc "gopkg.in/check.v1"
12+
13+
"github.com/juju/juju/core/network"
14+
)
15+
16+
type brokerSuite struct {
17+
testing.IsolationSuite
18+
}
19+
20+
var _ = gc.Suite(&brokerSuite{})
21+
22+
func (s *brokerSuite) SetUpSuite(c *gc.C) {
23+
s.IsolationSuite.SetUpSuite(c)
24+
}
25+
26+
func (s *brokerSuite) SetUpTest(c *gc.C) {
27+
s.IsolationSuite.SetUpTest(c)
28+
}
29+
30+
func (s *brokerSuite) TestExistingOVSManagedBridges(c *gc.C) {
31+
// Patch output for "ovs-vsctl list-br" and make sure exec.LookPath can
32+
// detect it in the path
33+
testing.PatchExecutableAsEchoArgs(c, s, "ovs-vsctl", 0)
34+
s.PatchValue(&getCommandOutput, func(cmd *exec.Cmd) ([]byte, error) {
35+
c.Assert(cmd.Args, gc.DeepEquals, []string{"ovs-vsctl", "list-br"}, gc.Commentf("expected ovs-vsctl to be invoked with 'list-br' as an argument"))
36+
return []byte("ovsbr1" + "\n"), nil
37+
})
38+
39+
ifaces := network.InterfaceInfos{
40+
{InterfaceName: "eth0"},
41+
{InterfaceName: "eth1"},
42+
{InterfaceName: "lxdbr0"},
43+
{InterfaceName: "ovsbr1"},
44+
}
45+
46+
ovsIfaces, err := ovsManagedBridges(ifaces)
47+
c.Assert(err, jc.ErrorIsNil)
48+
c.Assert(ovsIfaces, gc.HasLen, 1, gc.Commentf("expected ovs-managed bridge list to contain a single entry"))
49+
c.Assert(ovsIfaces[0].InterfaceName, gc.Equals, "ovsbr1", gc.Commentf("expected ovs-managed bridge list to contain iface 'ovsbr1'"))
50+
}
51+
52+
func (s *brokerSuite) TestNonExistingOVSManagedBridges(c *gc.C) {
53+
// Patch output for "ovs-vsctl list-br" and make sure exec.LookPath can
54+
// detect it in the path
55+
testing.PatchExecutableAsEchoArgs(c, s, "ovs-vsctl", 0)
56+
s.PatchValue(&getCommandOutput, func(cmd *exec.Cmd) ([]byte, error) {
57+
c.Assert(cmd.Args, gc.DeepEquals, []string{"ovs-vsctl", "list-br"}, gc.Commentf("expected ovs-vsctl to be invoked with 'list-br' as an argument"))
58+
return []byte("\n"), nil
59+
})
60+
61+
ifaces := network.InterfaceInfos{
62+
{InterfaceName: "eth0"},
63+
{InterfaceName: "eth1"},
64+
{InterfaceName: "lxdbr0"},
65+
}
66+
67+
ovsIfaces, err := ovsManagedBridges(ifaces)
68+
c.Assert(err, jc.ErrorIsNil)
69+
c.Assert(ovsIfaces, gc.HasLen, 0, gc.Commentf("expected ovs-managed bridge list to be empty"))
70+
}
71+
72+
func (s *brokerSuite) TestMissingOVSTools(c *gc.C) {
73+
ifaces := network.InterfaceInfos{{InterfaceName: "eth0"}}
74+
ovsIfaces, err := ovsManagedBridges(ifaces)
75+
c.Assert(err, jc.ErrorIsNil)
76+
c.Assert(ovsIfaces, gc.HasLen, 0, gc.Commentf("expected ovs-managed bridge list to be empty"))
77+
}

0 commit comments

Comments
 (0)