1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
|
package util
import (
"bytes"
"fmt"
"strings"
"time"
"unicode"
"github.com/sirupsen/logrus"
kexec "k8s.io/utils/exec"
)
const (
ovsCommandTimeout = 15
ovsVsctlCommand = "ovs-vsctl"
ovsOfctlCommand = "ovs-ofctl"
ovnNbctlCommand = "ovn-nbctl"
ipCommand = "ip"
)
// Exec runs various OVN and OVS utilities
type execHelper struct {
exec kexec.Interface
ofctlPath string
vsctlPath string
nbctlPath string
ipPath string
}
var runner *execHelper
// SetExec validates executable paths and saves the given exec interface
// to be used for running various OVS and OVN utilites
func SetExec(exec kexec.Interface) error {
var err error
runner = &execHelper{exec: exec}
runner.ofctlPath, err = exec.LookPath(ovsOfctlCommand)
if err != nil {
return err
}
runner.vsctlPath, err = exec.LookPath(ovsVsctlCommand)
if err != nil {
return err
}
runner.nbctlPath, err = exec.LookPath(ovnNbctlCommand)
if err != nil {
return err
}
runner.ipPath, err = exec.LookPath(ipCommand)
if err != nil {
return err
}
return nil
}
// Run the ovn-ctl command and retry if "Connection refused"
// poll waitng for service to become available
func runOVNretry(cmdPath string, args ...string) (*bytes.Buffer, *bytes.Buffer, error) {
retriesLeft := 200
for {
stdout, stderr, err := run(cmdPath, args...)
if err == nil {
return stdout, stderr, err
}
// Connection refused
// Master may not be up so keep trying
if strings.Contains(stderr.String(), "Connection refused") {
if retriesLeft == 0 {
return stdout, stderr, err
}
retriesLeft--
time.Sleep(2 * time.Second)
} else {
// Some other problem for caller to handle
return stdout, stderr, err
}
}
}
func run(cmdPath string, args ...string) (*bytes.Buffer, *bytes.Buffer, error) {
stdout := &bytes.Buffer{}
stderr := &bytes.Buffer{}
cmd := runner.exec.Command(cmdPath, args...)
cmd.SetStdout(stdout)
cmd.SetStderr(stderr)
logrus.Debugf("exec: %s %s", cmdPath, strings.Join(args, " "))
err := cmd.Run()
if err != nil {
logrus.Debugf("exec: %s %s => %v", cmdPath, strings.Join(args, " "), err)
}
return stdout, stderr, err
}
// RunOVSOfctl runs a command via ovs-ofctl.
func RunOVSOfctl(args ...string) (string, string, error) {
stdout, stderr, err := run(runner.ofctlPath, args...)
return strings.Trim(stdout.String(), "\" \n"), stderr.String(), err
}
// RunOVSVsctl runs a command via ovs-vsctl.
func RunOVSVsctl(args ...string) (string, string, error) {
cmdArgs := []string{fmt.Sprintf("--timeout=%d", ovsCommandTimeout)}
cmdArgs = append(cmdArgs, args...)
stdout, stderr, err := run(runner.vsctlPath, cmdArgs...)
return strings.Trim(strings.TrimSpace(stdout.String()), "\""), stderr.String(), err
}
// RunOVNNbctlUnix runs command via ovn-nbctl, with ovn-nbctl using the unix
// domain sockets to connect to the ovsdb-server backing the OVN NB database.
func RunOVNNbctlUnix(args ...string) (string, string, error) {
cmdArgs := []string{fmt.Sprintf("--timeout=%d", ovsCommandTimeout)}
cmdArgs = append(cmdArgs, args...)
stdout, stderr, err := runOVNretry(runner.nbctlPath, cmdArgs...)
return strings.Trim(strings.TrimFunc(stdout.String(), unicode.IsSpace), "\""),
stderr.String(), err
}
// RunIP runs a command via the iproute2 "ip" utility
func RunIP(args ...string) (string, string, error) {
stdout, stderr, err := run(runner.ipPath, args...)
return strings.TrimSpace(stdout.String()), stderr.String(), err
}
|