aboutsummaryrefslogtreecommitdiffstats
path: root/internal/pkg/ovn/utils.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/pkg/ovn/utils.go')
-rw-r--r--internal/pkg/ovn/utils.go120
1 files changed, 120 insertions, 0 deletions
diff --git a/internal/pkg/ovn/utils.go b/internal/pkg/ovn/utils.go
new file mode 100644
index 0000000..1700bf8
--- /dev/null
+++ b/internal/pkg/ovn/utils.go
@@ -0,0 +1,120 @@
+package ovn
+
+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
+}
+
+// RunOVSVsctl runs a command via ovs-vsctl.
+func RunOVSVsctlUnix(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
+}