aboutsummaryrefslogtreecommitdiffstats
path: root/internal/pkg/ovn/utils.go
blob: 2478ac24bd77b76906aea7bddb84898c4609092a (plain)
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
package ovn

import (
	"bytes"
	"fmt"
	kexec "k8s.io/utils/exec"
	"os"
	"strings"
	"time"
)

const (
	ovsCommandTimeout = 15
	ovnNbctlCommand   = "ovn-nbctl"
)

// Exec runs various OVN and OVS utilities
type execHelper struct {
	exec      kexec.Interface
	nbctlPath string
	hostIP    string
	hostPort  string
}

var runner *execHelper

// SetupOvnUtils does internal OVN initialization
var SetupOvnUtils = func() error {
	runner.hostIP = os.Getenv("HOST_IP")
	// OVN Host Port
	runner.hostPort = "6641"
	log.Info("Host Port", "IP", runner.hostIP, "Port", runner.hostPort)

	// Setup Distributed Router
	err := setupDistributedRouter(ovn4nfvRouterName)
	if err != nil {
		log.Error(err, "Failed to initialize OVN Distributed Router")
		return err
	}
	return nil
}

// 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.nbctlPath, err = exec.LookPath(ovnNbctlCommand)
	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)
	log.Info("exec:", "cmdPath", cmdPath, "args", strings.Join(args, " "))
	err := cmd.Run()
	if err != nil {
		log.Error(err, "exec:", "cmdPath", cmdPath, "args", strings.Join(args, " "))
	}
	return stdout, stderr, err
}

// RunOVNSbctlWithTimeout runs command via ovn-nbctl with a specific timeout
func RunOVNNbctlWithTimeout(timeout int, args ...string) (string, string, error) {
	var cmdArgs []string
	if len(runner.hostIP) > 0 {
		cmdArgs = []string{
			fmt.Sprintf("--db=tcp:%s:%s", runner.hostIP, runner.hostPort),
		}
	}
	cmdArgs = append(cmdArgs, fmt.Sprintf("--timeout=%d", timeout))
	cmdArgs = append(cmdArgs, args...)
	stdout, stderr, err := runOVNretry(runner.nbctlPath, cmdArgs...)
	return strings.Trim(strings.TrimSpace(stdout.String()), "\""), stderr.String(), err
}

// RunOVNNbctl runs a command via ovn-nbctl.
func RunOVNNbctl(args ...string) (string, string, error) {
	return RunOVNNbctlWithTimeout(ovsCommandTimeout, args...)
}