diff options
author | 2018-11-10 09:56:52 -0800 | |
---|---|---|
committer | 2018-11-20 01:50:58 -0800 | |
commit | 5026d1d89b05eac5e004279b742df6745a73d93a (patch) | |
tree | 8f9aed1e476706e008b746debda6d616bd0ac7a5 /cmd | |
parent | 9506ae48eb545d502cc3685a99862740d28e7afb (diff) |
Seed code for the Plugin
The code includes ovn4nfvk8s Plugin & CNI. It implements multiple OVN
interfaces for Pods and assumes Multus (or similar CNI) calls its CNI
not as first CNI.
Change-Id: I524c1d18752eb6dbc8d34addd3b60d5bbaa06ff4
Signed-off-by: Ritu Sood <ritu.sood@intel.com>
Signed-off-by: Victor Morales <victor.morales@intel.com>
Diffstat (limited to 'cmd')
-rw-r--r-- | cmd/ovn4nfvk8s-cni/.gitkeep | 0 | ||||
-rw-r--r-- | cmd/ovn4nfvk8s-cni/app/helper_linux.go | 160 | ||||
-rw-r--r-- | cmd/ovn4nfvk8s-cni/ovn4nfvk8s-cni.go | 290 | ||||
-rw-r--r-- | cmd/ovn4nfvk8s-cni/ovn4nfvk8s-cni_test.go | 56 | ||||
-rw-r--r-- | cmd/ovn4nfvk8s/.gitkeep | 0 | ||||
-rw-r--r-- | cmd/ovn4nfvk8s/ovn4nfvk8s.go | 132 |
6 files changed, 638 insertions, 0 deletions
diff --git a/cmd/ovn4nfvk8s-cni/.gitkeep b/cmd/ovn4nfvk8s-cni/.gitkeep deleted file mode 100644 index e69de29..0000000 --- a/cmd/ovn4nfvk8s-cni/.gitkeep +++ /dev/null diff --git a/cmd/ovn4nfvk8s-cni/app/helper_linux.go b/cmd/ovn4nfvk8s-cni/app/helper_linux.go new file mode 100644 index 0000000..1a98a61 --- /dev/null +++ b/cmd/ovn4nfvk8s-cni/app/helper_linux.go @@ -0,0 +1,160 @@ +// +build linux + +package app + +import ( + "fmt" + "net" + "os/exec" + "regexp" + "strings" + + "github.com/sirupsen/logrus" + + "github.com/containernetworking/cni/pkg/skel" + "github.com/containernetworking/cni/pkg/types/current" + "github.com/containernetworking/plugins/pkg/ip" + "github.com/containernetworking/plugins/pkg/ns" + "github.com/vishvananda/netlink" +) + +func renameLink(curName, newName string) error { + link, err := netlink.LinkByName(curName) + if err != nil { + return err + } + + if err := netlink.LinkSetDown(link); err != nil { + return err + } + if err := netlink.LinkSetName(link, newName); err != nil { + return err + } + if err := netlink.LinkSetUp(link); err != nil { + return err + } + + return nil +} + +func setupInterface(netns ns.NetNS, containerID, ifName, macAddress, ipAddress, gatewayIP, defaultGateway string, mtu int) (*current.Interface, *current.Interface, error) { + hostIface := ¤t.Interface{} + contIface := ¤t.Interface{} + + var oldHostVethName string + err := netns.Do(func(hostNS ns.NetNS) error { + // create the veth pair in the container and move host end into host netns + hostVeth, containerVeth, err := ip.SetupVeth(ifName, mtu, hostNS) + if err != nil { + return fmt.Errorf("failed to setup veth %s: %v", ifName, err) + //return err + } + hostIface.Mac = hostVeth.HardwareAddr.String() + contIface.Name = containerVeth.Name + + link, err := netlink.LinkByName(contIface.Name) + if err != nil { + return fmt.Errorf("failed to lookup %s: %v", contIface.Name, err) + } + + hwAddr, err := net.ParseMAC(macAddress) + if err != nil { + return fmt.Errorf("failed to parse mac address for %s: %v", contIface.Name, err) + } + err = netlink.LinkSetHardwareAddr(link, hwAddr) + if err != nil { + return fmt.Errorf("failed to add mac address %s to %s: %v", macAddress, contIface.Name, err) + } + contIface.Mac = macAddress + contIface.Sandbox = netns.Path() + + addr, err := netlink.ParseAddr(ipAddress) + if err != nil { + return err + } + err = netlink.AddrAdd(link, addr) + if err != nil { + return fmt.Errorf("failed to add IP addr %s to %s: %v", ipAddress, contIface.Name, err) + } + + if defaultGateway == "true" { + gw := net.ParseIP(gatewayIP) + if gw == nil { + return fmt.Errorf("parse ip of gateway failed") + } + err = ip.AddRoute(nil, gw, link) + if err != nil { + logrus.Errorf("ip.AddRoute failed %v gw %v link %v", err, gw, link) + return err + } + } + oldHostVethName = hostVeth.Name + + return nil + }) + if err != nil { + return nil, nil, err + } + + // rename the host end of veth pair + re := regexp.MustCompile("(\\d+)\\D*\\z") + index := re.FindAllString(ifName, -1) + hostIface.Name = containerID[:14] + index[0] + if err := renameLink(oldHostVethName, hostIface.Name); err != nil { + return nil, nil, fmt.Errorf("failed to rename %s to %s: %v", oldHostVethName, hostIface.Name, err) + } + + return hostIface, contIface, nil +} + +// ConfigureInterface sets up the container interface +var ConfigureInterface = func(args *skel.CmdArgs, namespace, podName, macAddress, ipAddress, gatewayIP, interfaceName, defaultGateway string, mtu int) ([]*current.Interface, error) { + netns, err := ns.GetNS(args.Netns) + if err != nil { + return nil, fmt.Errorf("failed to open netns %q: %v", args.Netns, err) + } + defer netns.Close() + hostIface, contIface, err := setupInterface(netns, args.ContainerID, interfaceName, macAddress, ipAddress, gatewayIP, defaultGateway, mtu) + if err != nil { + return nil, err + } + var ifaceID string + if interfaceName != "" { + ifaceID = fmt.Sprintf("%s_%s_%s", namespace, podName, interfaceName) + } else { + ifaceID = fmt.Sprintf("%s_%s", namespace, podName) + } + + ovsArgs := []string{ + "add-port", "br-int", hostIface.Name, "--", "set", + "interface", hostIface.Name, + fmt.Sprintf("external_ids:attached_mac=%s", macAddress), + fmt.Sprintf("external_ids:iface-id=%s", ifaceID), + fmt.Sprintf("external_ids:ip_address=%s", ipAddress), + fmt.Sprintf("external_ids:sandbox=%s", args.ContainerID), + } + + var out []byte + out, err = exec.Command("ovs-vsctl", ovsArgs...).CombinedOutput() + if err != nil { + return nil, fmt.Errorf("failure in plugging pod interface: %v\n %q", err, string(out)) + } + + return []*current.Interface{hostIface, contIface}, nil +} + +// PlatformSpecificCleanup deletes the OVS port +func PlatformSpecificCleanup(ifaceName string) (bool, error) { + done := false + ovsArgs := []string{ + "del-port", "br-int", ifaceName, + } + out, err := exec.Command("ovs-vsctl", ovsArgs...).CombinedOutput() + if err != nil && !strings.Contains(string(out), "no port named") { + // DEL should be idempotent; don't return an error just log it + logrus.Warningf("failed to delete OVS port %s: %v\n %q", ifaceName, err, string(out)) + done = true + } + + return done, nil +} diff --git a/cmd/ovn4nfvk8s-cni/ovn4nfvk8s-cni.go b/cmd/ovn4nfvk8s-cni/ovn4nfvk8s-cni.go new file mode 100644 index 0000000..923363b --- /dev/null +++ b/cmd/ovn4nfvk8s-cni/ovn4nfvk8s-cni.go @@ -0,0 +1,290 @@ +// +build linux + +package main + +import ( + "encoding/json" + "fmt" + "net" + "os" + "strconv" + "strings" + "time" + + "github.com/sirupsen/logrus" + "github.com/urfave/cli" + + "github.com/containernetworking/cni/pkg/skel" + "github.com/containernetworking/cni/pkg/types" + "github.com/containernetworking/cni/pkg/types/current" + "github.com/containernetworking/cni/pkg/version" + "k8s.io/apimachinery/pkg/util/wait" + + kexec "k8s.io/utils/exec" + "ovn4nfv-k8s-plugin/internal/pkg/kube" + + "ovn4nfv-k8s-plugin/cmd/ovn4nfvk8s-cni/app" + "ovn4nfv-k8s-plugin/internal/pkg/config" +) + +func argString2Map(args string) (map[string]string, error) { + argsMap := make(map[string]string) + + pairs := strings.Split(args, ";") + for _, pair := range pairs { + kv := strings.Split(pair, "=") + if len(kv) != 2 { + return nil, fmt.Errorf("ARGS: invalid pair %q", pair) + } + keyString := kv[0] + valueString := kv[1] + argsMap[keyString] = valueString + } + + return argsMap, nil +} + +func parseOvnNetworkObject(ovnnetwork string) ([]map[string]string, error) { + var ovnNet []map[string]string + + if ovnnetwork == "" { + return nil, fmt.Errorf("parseOvnNetworkObject:error") + } + + if err := json.Unmarshal([]byte(ovnnetwork), &ovnNet); err != nil { + return nil, fmt.Errorf("parseOvnNetworkObject: failed to load ovn network err: %v | ovn network: %v", err, ovnnetwork) + } + + return ovnNet, nil +} + +func mergeWithResult(srcObj, dstObj types.Result) (types.Result, error) { + + if dstObj == nil { + return srcObj, nil + } + src, err := current.NewResultFromResult(srcObj) + if err != nil { + return nil, fmt.Errorf("Couldn't convert old result to current version: %v", err) + } + dst, err := current.NewResultFromResult(dstObj) + if err != nil { + return nil, fmt.Errorf("Couldn't convert old result to current version: %v", err) + } + + ifacesLength := len(dst.Interfaces) + + for _, iface := range src.Interfaces { + dst.Interfaces = append(dst.Interfaces, iface) + } + for _, ip := range src.IPs { + if ip.Interface != nil && *(ip.Interface) != -1 { + ip.Interface = current.Int(*(ip.Interface) + ifacesLength) + } + dst.IPs = append(dst.IPs, ip) + } + for _, route := range src.Routes { + dst.Routes = append(dst.Routes, route) + } + + for _, ns := range src.DNS.Nameservers { + dst.DNS.Nameservers = append(dst.DNS.Nameservers, ns) + } + for _, s := range src.DNS.Search { + dst.DNS.Search = append(dst.DNS.Search, s) + } + for _, opt := range src.DNS.Options { + dst.DNS.Options = append(dst.DNS.Options, opt) + } + // TODO: what about DNS.domain? + return dst, nil +} + +func prettyPrint(i interface{}) string { + s, _ := json.MarshalIndent(i, "", "\t") + return string(s) +} + +func addMultipleInterfaces(args *skel.CmdArgs, ovnAnnotation, namespace, podName string) types.Result { + logrus.Infof("ovn4nfvk8s-cni: addMultipleInterfaces ") + + var ovnAnnotatedMap []map[string]string + ovnAnnotatedMap, err := parseOvnNetworkObject(ovnAnnotation) + if err != nil { + logrus.Errorf("addLogicalPort : Error Parsing Ovn Network List %v", ovnAnnotatedMap) + return nil + } + if namespace == "" || podName == "" { + logrus.Errorf("required CNI variable missing") + return nil + } + var interfacesArray []*current.Interface + var index int + var result *current.Result + var dstResult types.Result + for _, ovnNet := range ovnAnnotatedMap { + ipAddress := ovnNet["ip_address"] + macAddress := ovnNet["mac_address"] + gatewayIP := ovnNet["gateway_ip"] + defaultGateway := ovnNet["defaultGateway"] + + if ipAddress == "" || macAddress == "" || gatewayIP == "" { + logrus.Errorf("failed in pod annotation key extract") + return nil + } + + index++ + interfaceName := ovnNet["interface"] + if interfaceName == "" { + logrus.Errorf("addMultipleInterfaces: interface can't be null") + return nil + } + logrus.Debugf("addMultipleInterfaces: ipAddress %v %v", ipAddress, interfaceName) + interfacesArray, err = app.ConfigureInterface(args, namespace, podName, macAddress, ipAddress, gatewayIP, interfaceName, defaultGateway, config.Default.MTU) + if err != nil { + logrus.Errorf("Failed to configure interface in pod: %v", err) + return nil + } + addr, addrNet, err := net.ParseCIDR(ipAddress) + if err != nil { + logrus.Errorf("failed to parse IP address %q: %v", ipAddress, err) + return nil + } + ipVersion := "6" + if addr.To4() != nil { + ipVersion = "4" + } + var routes types.Route + if defaultGateway == "true" { + defaultAddr, defaultAddrNet, _ := net.ParseCIDR("0.0.0.0/0") + routes = types.Route{Dst: net.IPNet{IP: defaultAddr, Mask: defaultAddrNet.Mask}, GW: net.ParseIP(gatewayIP)} + + result = ¤t.Result{ + Interfaces: interfacesArray, + IPs: []*current.IPConfig{ + { + Version: ipVersion, + Interface: current.Int(1), + Address: net.IPNet{IP: addr, Mask: addrNet.Mask}, + Gateway: net.ParseIP(gatewayIP), + }, + }, + Routes: []*types.Route{&routes}, + } + } else { + result = ¤t.Result{ + Interfaces: interfacesArray, + IPs: []*current.IPConfig{ + { + Version: ipVersion, + Interface: current.Int(1), + Address: net.IPNet{IP: addr, Mask: addrNet.Mask}, + Gateway: net.ParseIP(gatewayIP), + }, + }, + } + + } + // Build the result structure to pass back to the runtime + dstResult, err = mergeWithResult(types.Result(result), dstResult) + if err != nil { + logrus.Errorf("Failed to merge results: %v", err) + return nil + } + } + logrus.Infof("addMultipleInterfaces: %s", prettyPrint(dstResult)) + return dstResult +} + +func cmdAdd(args *skel.CmdArgs) error { + logrus.Infof("ovn4nfvk8s-cni: cmdAdd ") + conf := &types.NetConf{} + if err := json.Unmarshal(args.StdinData, conf); err != nil { + return fmt.Errorf("failed to load netconf: %v", err) + } + + argsMap, err := argString2Map(args.Args) + if err != nil { + return err + } + + namespace := argsMap["K8S_POD_NAMESPACE"] + podName := argsMap["K8S_POD_NAME"] + if namespace == "" || podName == "" { + return fmt.Errorf("required CNI variable missing") + } + + clientset, err := config.NewClientset(&config.Kubernetes) + if err != nil { + return fmt.Errorf("Could not create clientset for kubernetes: %v", err) + } + kubecli := &kube.Kube{KClient: clientset} + + // Get the IP address and MAC address from the API server. + var annotationBackoff = wait.Backoff{Duration: 1 * time.Second, Steps: 14, Factor: 1.5, Jitter: 0.1} + var annotation map[string]string + if err := wait.ExponentialBackoff(annotationBackoff, func() (bool, error) { + annotation, err = kubecli.GetAnnotationsOnPod(namespace, podName) + if err != nil { + // TODO: check if err is non recoverable + logrus.Warningf("Error while obtaining pod annotations - %v", err) + return false, nil + } + if _, ok := annotation["ovnIfaceList"]; ok { + return true, nil + } + return false, nil + }); err != nil { + return fmt.Errorf("failed to get pod annotation - %v", err) + } + logrus.Infof("ovn4nfvk8s-cni: Annotation Found ") + ovnAnnotation, ok := annotation["ovnIfaceList"] + if !ok { + return fmt.Errorf("Error while obtaining pod annotations") + } + result := addMultipleInterfaces(args, ovnAnnotation, namespace, podName) + return result.Print() +} + +func cmdDel(args *skel.CmdArgs) error { + logrus.Infof("ovn4nfvk8s-cni: cmdDel ") + for i := 0; i < 10; i++ { + ifaceName := args.ContainerID[:14] + strconv.Itoa(i) + done, err := app.PlatformSpecificCleanup(ifaceName) + if err != nil { + logrus.Errorf("Teardown error: %v", err) + } + if done { + break + } + } + return nil +} + +func main() { + logrus.Infof("ovn4nfvk8s-cni CNI Invoked by Multus") + c := cli.NewApp() + c.Name = "ovn4nfvk8s-cni" + c.Usage = "a CNI plugin to set up or tear down a additional interfaces with OVN" + c.Version = "0.0.2" + c.Flags = config.Flags + + exec := kexec.New() + c.Action = func(ctx *cli.Context) error { + if _, err := config.InitConfig(ctx, exec, nil); err != nil { + return err + } + + skel.PluginMain(cmdAdd, cmdDel, version.All) + return nil + } + + if err := c.Run(os.Args); err != nil { + // Print the error to stdout in conformance with the CNI spec + e, ok := err.(*types.Error) + if !ok { + e = &types.Error{Code: 100, Msg: err.Error()} + } + e.Print() + } +} diff --git a/cmd/ovn4nfvk8s-cni/ovn4nfvk8s-cni_test.go b/cmd/ovn4nfvk8s-cni/ovn4nfvk8s-cni_test.go new file mode 100644 index 0000000..d5b7b6b --- /dev/null +++ b/cmd/ovn4nfvk8s-cni/ovn4nfvk8s-cni_test.go @@ -0,0 +1,56 @@ +// +build linux + +package main + +import ( + "github.com/containernetworking/cni/pkg/skel" + "github.com/containernetworking/cni/pkg/types/current" + "ovn4nfv-k8s-plugin/cmd/ovn4nfvk8s-cni/app" + "testing" +) + +func TestAddMultipleInterfaces(t *testing.T) { + oldConfigureInterface := app.ConfigureInterface + // as we are exiting, revert ConfigureInterface back at end of function + defer func() { app.ConfigureInterface = oldConfigureInterface }() + app.ConfigureInterface = func(args *skel.CmdArgs, namespace, podName, macAddress, ipAddress, gatewayIP, interfaceName, defaultGateway string, mtu int) ([]*current.Interface, error) { + return []*current.Interface{ + { + Name: "pod", + Mac: "0a:00:00:00:00:0c", + Sandbox: "102103104", + }}, nil + } + args := &skel.CmdArgs{"102103104", "default", "eth0", "", "", nil} + + ovnAnnotation := "[{\"ip_address\":\"172.16.24.2/24\", \"mac_address\":\"0a:00:00:00:00:0c\", \"gateway_ip\": \"172.16.24.1\",\"interface\":\"net0\"}] " + result := addMultipleInterfaces(args, ovnAnnotation, "default", "pod") + if result == nil { + t.Errorf("Failed addMultipleInterfaces %+v", ovnAnnotation) + } + ovnAnnotation = "[{\"ip_address\":\"172.16.24.2/24\", \"mac_address\":\"0a:00:00:00:00:0c\", \"gateway_ip\": \"172.16.24.1\",\"defaultGateway\":\"true\",\"interface\":\"net0\"}] " + result = addMultipleInterfaces(args, ovnAnnotation, "default", "pod") + if result == nil { + t.Errorf("Failed addMultipleInterfaces %+v", ovnAnnotation) + } + ovnAnnotation = "[{\"ip_address\":\"172.16.24.2/24\", \"mac_address\":\"0a:00:00:00:00:0c\", \"gateway_ip\": \"172.16.24.1\"}] " + result = addMultipleInterfaces(args, ovnAnnotation, "default", "pod") + if result != nil { + t.Errorf("Failed addMultipleInterfaces %+v", ovnAnnotation) + } + ovnAnnotation = "[{\"mac_address\":\"0a:00:00:00:00:0c\", \"gateway_ip\": \"172.16.24.1\",\"interface\":\"net0\"}] " + result = addMultipleInterfaces(args, ovnAnnotation, "default", "pod") + if result != nil { + t.Errorf("Failed addMultipleInterfaces %+v", ovnAnnotation) + } + ovnAnnotation = "[{\"ip_address\":\"172.16.24.2/24\", \"mac_address\":\"0a:00:00:00:00:0c\", \"gateway_ip\": \"172.16.24.1\",\"interface\":\"net0\"}, {\"ip_address\":\"172.16.25.2/24\", \"mac_address\":\"0a:00:00:00:00:0d\", \"gateway_ip\": \"172.16.25.1\",\"interface\":\"net1\"}]" + result = addMultipleInterfaces(args, ovnAnnotation, "default", "pod") + if result == nil { + t.Errorf("Failed addMultipleInterfaces %+v", ovnAnnotation) + } + ovnAnnotation = "[{\"ip_address\":\"172.16.24.2/24\", \"mac_address\":\"0a:00:00:00:00:0c\", \"gateway_ip\": \"172.16.24.1\",\"interface\":\"net0\", \"defaultGateway\":\"true\"}, {\"ip_address\":\"172.16.25.2/24\", \"mac_address\":\"0a:00:00:00:00:0d\", \"gateway_ip\": \"172.16.25.1\",\"interface\":\"net1\"}]" + result = addMultipleInterfaces(args, ovnAnnotation, "default", "pod") + if result == nil { + t.Errorf("Failed addMultipleInterfaces %+v", ovnAnnotation) + } +} diff --git a/cmd/ovn4nfvk8s/.gitkeep b/cmd/ovn4nfvk8s/.gitkeep deleted file mode 100644 index e69de29..0000000 --- a/cmd/ovn4nfvk8s/.gitkeep +++ /dev/null diff --git a/cmd/ovn4nfvk8s/ovn4nfvk8s.go b/cmd/ovn4nfvk8s/ovn4nfvk8s.go new file mode 100644 index 0000000..d097558 --- /dev/null +++ b/cmd/ovn4nfvk8s/ovn4nfvk8s.go @@ -0,0 +1,132 @@ +package main + +import ( + "fmt" + "io/ioutil" + "os" + "os/signal" + "syscall" + + "github.com/sirupsen/logrus" + "github.com/urfave/cli" + + kexec "k8s.io/utils/exec" + + "ovn4nfv-k8s-plugin/internal/pkg/config" + "ovn4nfv-k8s-plugin/internal/pkg/factory" + "ovn4nfv-k8s-plugin/internal/pkg/ovn" + "ovn4nfv-k8s-plugin/internal/pkg/util" +) + +func main() { + c := cli.NewApp() + c.Name = "ovn4nfvk8s" + c.Usage = "run ovn4nfvk8s to start pod watchers" + c.Version = config.Version + c.Flags = append([]cli.Flag{ + // Daemon file + cli.StringFlag{ + Name: "pidfile", + Usage: "Name of file that will hold the ovn4nfvk8s pid (optional)", + }, + }, config.Flags...) + c.Action = func(c *cli.Context) error { + return runOvnKube(c) + } + + if err := c.Run(os.Args); err != nil { + logrus.Fatal(err) + } +} + +func delPidfile(pidfile string) { + if pidfile != "" { + if _, err := os.Stat(pidfile); err == nil { + if err := os.Remove(pidfile); err != nil { + logrus.Errorf("%s delete failed: %v", pidfile, err) + } + } + } +} + +func runOvnKube(ctx *cli.Context) error { + fmt.Println("ovn4nfvk8s started") + exec := kexec.New() + _, err := config.InitConfig(ctx, exec, nil) + if err != nil { + return err + } + pidfile := ctx.String("pidfile") + + c := make(chan os.Signal, 2) + signal.Notify(c, os.Interrupt, syscall.SIGTERM) + go func() { + <-c + delPidfile(pidfile) + os.Exit(1) + }() + + defer delPidfile(pidfile) + + if pidfile != "" { + // need to test if already there + _, err := os.Stat(pidfile) + + // Create if it doesn't exist, else exit with error + if os.IsNotExist(err) { + if err := ioutil.WriteFile(pidfile, []byte(fmt.Sprintf("%d", os.Getpid())), 0644); err != nil { + logrus.Errorf("failed to write pidfile %s (%v). Ignoring..", pidfile, err) + } + } else { + // get the pid and see if it exists + pid, err := ioutil.ReadFile(pidfile) + if err != nil { + logrus.Errorf("pidfile %s exists but can't be read", pidfile) + return err + } + _, err1 := os.Stat("/proc/" + string(pid[:]) + "/cmdline") + if os.IsNotExist(err1) { + // Left over pid from dead process + if err := ioutil.WriteFile(pidfile, []byte(fmt.Sprintf("%d", os.Getpid())), 0644); err != nil { + logrus.Errorf("failed to write pidfile %s (%v). Ignoring..", pidfile, err) + } + } else { + logrus.Errorf("pidfile %s exists and ovn4nfvk8s is running", pidfile) + os.Exit(1) + } + } + } + + if err = util.SetExec(exec); err != nil { + logrus.Errorf("Failed to initialize exec helper: %v", err) + return err + } + + clientset, err := config.NewClientset(&config.Kubernetes) + if err != nil { + panic(err.Error()) + } + + // Create distributed router and gateway for the deployment + err = ovn.SetupMaster("ovn4nfv-master") + if err != nil { + logrus.Errorf(err.Error()) + panic(err.Error()) + } + // create factory and start the ovn controller + stopChan := make(chan struct{}) + factory, err := factory.NewWatchFactory(clientset, stopChan) + if err != nil { + panic(err.Error) + } + + ovnController := ovn.NewOvnController(clientset, factory) + if err := ovnController.Run(); err != nil { + logrus.Errorf(err.Error()) + panic(err.Error()) + } + // run forever + select {} + + return nil +} |