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...)
}
|