Add CRD Controller for Network
[ovn4nfv-k8s-plugin.git] / internal / pkg / ovn / utils.go
1 package ovn
2
3 import (
4         "bytes"
5         "fmt"
6         kexec "k8s.io/utils/exec"
7         "os"
8         "strings"
9         "time"
10 )
11
12 const (
13         ovsCommandTimeout = 15
14         ovnNbctlCommand   = "ovn-nbctl"
15 )
16
17 // Exec runs various OVN and OVS utilities
18 type execHelper struct {
19         exec      kexec.Interface
20         nbctlPath string
21         hostIP    string
22         hostPort  string
23 }
24
25 var runner *execHelper
26
27 // SetupOvnUtils does internal OVN initialization
28 var SetupOvnUtils = func() error {
29         runner.hostIP = os.Getenv("HOST_IP")
30         // OVN Host Port
31         runner.hostPort = "6641"
32         log.Info("Host Port", "IP", runner.hostIP, "Port", runner.hostPort)
33
34         // Setup Distributed Router
35         err := setupDistributedRouter(ovn4nfvRouterName)
36         if err != nil {
37                 log.Error(err, "Failed to initialize OVN Distributed Router")
38                 return err
39         }
40         return nil
41 }
42
43 // SetExec validates executable paths and saves the given exec interface
44 // to be used for running various OVS and OVN utilites
45 func SetExec(exec kexec.Interface) error {
46         var err error
47
48         runner = &execHelper{exec: exec}
49         runner.nbctlPath, err = exec.LookPath(ovnNbctlCommand)
50         if err != nil {
51                 return err
52         }
53         return nil
54 }
55
56 // Run the ovn-ctl command and retry if "Connection refused"
57 // poll waitng for service to become available
58 func runOVNretry(cmdPath string, args ...string) (*bytes.Buffer, *bytes.Buffer, error) {
59
60         retriesLeft := 200
61         for {
62                 stdout, stderr, err := run(cmdPath, args...)
63                 if err == nil {
64                         return stdout, stderr, err
65                 }
66                 // Connection refused
67                 // Master may not be up so keep trying
68                 if strings.Contains(stderr.String(), "Connection refused") {
69                         if retriesLeft == 0 {
70                                 return stdout, stderr, err
71                         }
72                         retriesLeft--
73                         time.Sleep(2 * time.Second)
74                 } else {
75                         // Some other problem for caller to handle
76                         return stdout, stderr, err
77                 }
78         }
79 }
80
81 func run(cmdPath string, args ...string) (*bytes.Buffer, *bytes.Buffer, error) {
82         stdout := &bytes.Buffer{}
83         stderr := &bytes.Buffer{}
84         cmd := runner.exec.Command(cmdPath, args...)
85         cmd.SetStdout(stdout)
86         cmd.SetStderr(stderr)
87         log.V(1).Info("exec:", "cmdPath", cmdPath, "args", strings.Join(args, " "))
88         err := cmd.Run()
89         if err != nil {
90                 log.Error(err, "Error:", "cmdPath", cmdPath, "args", strings.Join(args, " "), "stdout", stdout, "stderr", stderr)
91         } else {
92                 log.V(1).Info("output:", "stdout", stdout)
93         }
94         return stdout, stderr, err
95 }
96
97 // RunOVNNbctlWithTimeout runs command via ovn-nbctl with a specific timeout
98 func RunOVNNbctlWithTimeout(timeout int, args ...string) (string, string, error) {
99         var cmdArgs []string
100         if len(runner.hostIP) > 0 {
101                 cmdArgs = []string{
102                         fmt.Sprintf("--db=tcp:%s:%s", runner.hostIP, runner.hostPort),
103                 }
104         }
105         cmdArgs = append(cmdArgs, fmt.Sprintf("--timeout=%d", timeout))
106         cmdArgs = append(cmdArgs, args...)
107         stdout, stderr, err := runOVNretry(runner.nbctlPath, cmdArgs...)
108         return strings.Trim(strings.TrimSpace(stdout.String()), "\""), stderr.String(), err
109 }
110
111 // RunOVNNbctl runs a command via ovn-nbctl.
112 func RunOVNNbctl(args ...string) (string, string, error) {
113         return RunOVNNbctlWithTimeout(ovsCommandTimeout, args...)
114 }