Use controller runtime and operator sdk 23/68323/4
authorRitu Sood <ritu.sood@intel.com>
Wed, 7 Aug 2019 02:35:42 +0000 (19:35 -0700)
committerRitu Sood <ritu.sood@intel.com>
Thu, 15 Aug 2019 17:03:47 +0000 (10:03 -0700)
Changing the framework to use controller
runtime and operator sdk. This allows to
add CRD controllers for Network, Provider
Network etc in the same operator. Binary
renamed to nfn-operator (Network funtion
networking).

Change-Id: Ic25a3c3f5f1418fc0614f3aede48b41d9c1156cd
Signed-off-by: Ritu Sood <ritu.sood@intel.com>
22 files changed:
.gitignore
Makefile
build/Dockerfile [new file with mode: 0644]
build/bin/entrypoint [new file with mode: 0755]
build/bin/user_setup [new file with mode: 0755]
cmd/nfn-operator/nfn-operator.go [new file with mode: 0644]
cmd/ovn4nfvk8s-cni/ovn4nfvk8s-cni.go
cmd/ovn4nfvk8s/ovn4nfvk8s.go [deleted file]
deploy/operator.yaml [new file with mode: 0644]
deploy/operator_roles.yaml [new file with mode: 0644]
go.mod
go.sum
internal/pkg/factory/factory.go [deleted file]
internal/pkg/factory/factory_test.go [deleted file]
internal/pkg/kube/kube.go
internal/pkg/ovn/common.go
internal/pkg/ovn/ovn.go
internal/pkg/ovn/ovn_test.go
internal/pkg/ovn/utils.go
pkg/controller/add_pod.go [new file with mode: 0644]
pkg/controller/controller.go [new file with mode: 0644]
pkg/controller/pod/pod_controller.go [new file with mode: 0644]

index e881817..33defe4 100644 (file)
@@ -1,2 +1 @@
-ovn4nfvk8s*
 .tox/
index 8534dae..f8d7460 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -12,17 +12,18 @@ export GOPATH ...
 export GO111MODULE=on
 
 .PHONY: all 
-all: clean ovn4nfvk8s ovn4nfvk8s-cni
+all: clean nfn-operator  ovn4nfvk8s-cni
 
-ovn4nfvk8s:
-       @go build ./cmd/ovn4nfvk8s
+nfn-operator:
+       @go build -o build/bin/nfn-operator ./cmd/nfn-operator
 
 ovn4nfvk8s-cni:
-       @go build ./cmd/ovn4nfvk8s-cni
+       @go build -o build/bin/ovn4nfvk8s-cni ./cmd/ovn4nfvk8s-cni
 
 test:
        @go test -v ./...
 
 clean:
-       @rm -f ovn4nfvk8s*
+       @rm -f build/bin/ovn4nfvk8s*
+       @rm -f build/bin/nfn-operator*
 
diff --git a/build/Dockerfile b/build/Dockerfile
new file mode 100644 (file)
index 0000000..43d6731
--- /dev/null
@@ -0,0 +1,27 @@
+FROM ubuntu:18.04
+
+ARG HTTP_PROXY=${HTTP_PROXY}
+ARG HTTPS_PROXY=${HTTPS_PROXY}
+
+ENV http_proxy $HTTP_PROXY
+ENV https_proxy $HTTPS_PROXY
+ENV no_proxy $NO_PROXY
+
+RUN apt-get update && apt-get install -y -qq apt-transport-https curl \
+ && echo "deb https://packages.wand.net.nz xenial main" > /etc/apt/sources.list.d/wand.list \
+ && curl https://packages.wand.net.nz/keyring.gpg -o /etc/apt/trusted.gpg.d/wand.gpg \
+ && apt-get update && apt install -y -qq ovn-common
+
+
+ENV OPERATOR=/usr/local/bin/nfn-operator \
+    USER_UID=1001 \
+    USER_NAME=nfn-operator
+
+# install operator binary
+COPY bin/nfn-operator ${OPERATOR}
+
+COPY bin /usr/local/bin
+
+ENTRYPOINT ["/usr/local/bin/entrypoint"]
+
+
diff --git a/build/bin/entrypoint b/build/bin/entrypoint
new file mode 100755 (executable)
index 0000000..af0d88a
--- /dev/null
@@ -0,0 +1,27 @@
+#!/bin/sh -e
+
+
+cmd=${1:-""}
+
+case ${cmd} in
+   "cni")
+      CNI_BIN_DIR="/host/opt/cni/bin"
+      OVN4NFV_CONF_DIR="/host/etc/openvswitch"
+      OVN4NFV_BIN_FILE="/usr/local/bin/ovn4nfvk8s-cni"
+      OVN4NFV_CONF_FILE="/tmp/ovn4nfv-conf/ovn4nfv_k8s.conf"
+      cp -f $OVN4NFV_BIN_FILE $CNI_BIN_DIR
+      cp -f $OVN4NFV_CONF_FILE $OVN4NFV_CONF_DIR
+      # Sleep forever.
+      sleep infinity
+      ;;
+
+    "operator")
+      shift
+      exec ${OPERATOR} $@
+      ;;
+
+    *)
+      echo "invalid command ${cmd}"
+
+esac
+
diff --git a/build/bin/user_setup b/build/bin/user_setup
new file mode 100755 (executable)
index 0000000..1e36064
--- /dev/null
@@ -0,0 +1,13 @@
+#!/bin/sh
+set -x
+
+# ensure $HOME exists and is accessible by group 0 (we don't know what the runtime UID will be)
+mkdir -p ${HOME}
+chown ${USER_UID}:0 ${HOME}
+chmod ug+rwx ${HOME}
+
+# runtime user will need to be able to self-insert in /etc/passwd
+chmod g+rw /etc/passwd
+
+# no need for this script to remain in the image after running
+rm $0
diff --git a/cmd/nfn-operator/nfn-operator.go b/cmd/nfn-operator/nfn-operator.go
new file mode 100644 (file)
index 0000000..2925ac6
--- /dev/null
@@ -0,0 +1,91 @@
+package main
+
+import (
+       "flag"
+       "fmt"
+       "os"
+       "runtime"
+
+       // Import all Kubernetes client auth plugins (e.g. Azure, GCP, OIDC, etc.)
+       _ "k8s.io/client-go/plugin/pkg/client/auth"
+
+       "github.com/spf13/pflag"
+//     "ovn4nfv-k8s-plugin/pkg/apis"
+       "ovn4nfv-k8s-plugin/internal/pkg/ovn"
+       "ovn4nfv-k8s-plugin/pkg/controller"
+       "sigs.k8s.io/controller-runtime/pkg/client/config"
+       "sigs.k8s.io/controller-runtime/pkg/log/zap"
+       "sigs.k8s.io/controller-runtime/pkg/manager"
+       logf "sigs.k8s.io/controller-runtime/pkg/runtime/log"
+       "sigs.k8s.io/controller-runtime/pkg/runtime/signals"
+)
+
+var log = logf.Log.WithName("nfn-operator")
+
+func printVersion() {
+       log.Info(fmt.Sprintf("Go Version: %s", runtime.Version()))
+       log.Info(fmt.Sprintf("Go OS/Arch: %s/%s", runtime.GOOS, runtime.GOARCH))
+}
+
+func main() {
+
+       // Add flags registered by imported packages (e.g. glog and
+       // controller-runtime)
+       pflag.CommandLine.AddGoFlagSet(flag.CommandLine)
+
+       pflag.Parse()
+
+       // Use a zap logr.Logger implementation. If none of the zap
+       // flags are configured (or if the zap flag set is not being
+       // used), this defaults to a production zap logger.
+       //
+       // The logger instantiated here can be changed to any logger
+       // implementing the logr.Logger interface. This logger will
+       // be propagated through the whole operator, generating
+       // uniform and structured logs.
+       logf.SetLogger(zap.Logger(true))
+
+       printVersion()
+
+       // Create an OVN Controller
+    _, err := ovn.NewOvnController(nil)
+    if err != nil {
+               log.Error(err, "")
+               os.Exit(1)
+       }
+       //Initialize all the controllers that are supported here
+
+       // Get a config to talk to the apiserver
+       cfg, err := config.GetConfig()
+       if err != nil {
+               log.Error(err, "")
+               os.Exit(1)
+       }
+       // Create a new Cmd to provide shared dependencies and start components
+       mgr, err := manager.New(cfg, manager.Options{})
+       if err != nil {
+               log.Error(err, "")
+               os.Exit(1)
+       }
+
+       log.Info("Registering Components.")
+
+       // Setup Scheme for all resources
+       //if err := apis.AddToScheme(mgr.GetScheme()); err != nil {
+       //      log.Error(err, "")
+       //      os.Exit(1)
+       //}
+
+       // Setup all Controllers
+       if err := controller.AddToManager(mgr); err != nil {
+               log.Error(err, "")
+               os.Exit(1)
+       }
+       log.Info("Starting the Cmd.")
+
+       // Start the Cmd
+       if err := mgr.Start(signals.SetupSignalHandler()); err != nil {
+               log.Error(err, "Manager exited non-zero")
+               os.Exit(1)
+       }
+}
index 3a6b7f0..2585fcf 100644 (file)
@@ -26,6 +26,10 @@ import (
        "ovn4nfv-k8s-plugin/internal/pkg/config"
 )
 
+const (
+       ovn4nfvAnnotationTag = "k8s.plugin.opnfv.org/ovnInterfaces"
+)
+
 func argString2Map(args string) (map[string]string, error) {
        argsMap := make(map[string]string)
 
@@ -110,7 +114,7 @@ func addMultipleInterfaces(args *skel.CmdArgs, ovnAnnotation, namespace, podName
        var ovnAnnotatedMap []map[string]string
        ovnAnnotatedMap, err := parseOvnNetworkObject(ovnAnnotation)
        if err != nil {
-               logrus.Errorf("addLogicalPort : Error Parsing Ovn Network List %v", ovnAnnotatedMap)
+               logrus.Errorf("addLogicalPort : Error Parsing Ovn Network List %v %v", ovnAnnotatedMap, err)
                return nil
        }
        if namespace == "" || podName == "" {
@@ -275,7 +279,7 @@ func cmdAdd(args *skel.CmdArgs) error {
                        logrus.Warningf("Error while obtaining pod annotations - %v", err)
                        return false, nil
                }
-               if _, ok := annotation["ovnIfaceList"]; ok {
+               if _, ok := annotation[ovn4nfvAnnotationTag]; ok {
                        return true, nil
                }
                return false, nil
@@ -283,7 +287,7 @@ func cmdAdd(args *skel.CmdArgs) error {
                return fmt.Errorf("failed to get pod annotation - %v", err)
        }
        logrus.Infof("ovn4nfvk8s-cni: Annotation Found ")
-       ovnAnnotation, ok := annotation["ovnIfaceList"]
+       ovnAnnotation, ok := annotation[ovn4nfvAnnotationTag]
        if !ok {
                return fmt.Errorf("Error while obtaining pod annotations")
        }
@@ -326,7 +330,7 @@ func main() {
                        return err
                }
 
-               skel.PluginMain(cmdAdd, cmdDel, version.All)
+               skel.PluginMain(cmdAdd, nil, cmdDel, version.All, "")
                return nil
        }
 
diff --git a/cmd/ovn4nfvk8s/ovn4nfvk8s.go b/cmd/ovn4nfvk8s/ovn4nfvk8s.go
deleted file mode 100644 (file)
index 607b07f..0000000
+++ /dev/null
@@ -1,129 +0,0 @@
-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"
-)
-
-func main() {
-       c := cli.NewApp()
-       c.Name = "ovn4nfvk8s"
-       c.Usage = "run ovn4nfvk8s to start pod watchers"
-       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 {
-       exec := kexec.New()
-       _, err := config.InitConfig(ctx)
-       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 = ovn.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.SetupDistributedRouter("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
-}
diff --git a/deploy/operator.yaml b/deploy/operator.yaml
new file mode 100644 (file)
index 0000000..a1edde8
--- /dev/null
@@ -0,0 +1,42 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: nfn-operator
+spec:
+  replicas: 1
+  selector:
+    matchLabels:
+      name: nfn-operator
+  template:
+    metadata:
+      labels:
+        name: nfn-operator
+    spec:
+      serviceAccountName: k8s-nfn-sa
+      affinity:
+        nodeAffinity:
+          requiredDuringSchedulingIgnoredDuringExecution:
+            nodeSelectorTerms:
+            - matchExpressions:
+              - key: nfnType
+                operator: In
+                values:
+                - operator
+      containers:
+        - name: nfn-operator
+          # Replace this with the built image name
+          image: rtsood/nfn-operator:latest
+          command:
+          - nfn-operator
+          imagePullPolicy: IfNotPresent
+          env:
+            - name: HOST_IP
+              valueFrom:
+                fieldRef:
+                  fieldPath: status.hostIP
+            - name: POD_NAME
+              valueFrom:
+                fieldRef:
+                  fieldPath: metadata.name
+            - name: OPERATOR_NAME
+              value: "nfn-operator"
diff --git a/deploy/operator_roles.yaml b/deploy/operator_roles.yaml
new file mode 100644 (file)
index 0000000..2bd49ac
--- /dev/null
@@ -0,0 +1,75 @@
+
+---
+
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+  name: k8s-nfn-sa
+
+---
+
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRole
+metadata:
+  creationTimestamp: null
+  name: k8s-nfn-cr
+rules:
+- apiGroups:
+  - ""
+  resources:
+  - pods
+  - services
+  - endpoints
+  - persistentvolumeclaims
+  - events
+  - configmaps
+  - secrets
+  verbs:
+  - '*'
+- apiGroups:
+  - apps
+  resources:
+  - deployments
+  - daemonsets
+  - replicasets
+  - statefulsets
+  verbs:
+  - '*'
+- apiGroups:
+  - monitoring.coreos.com
+  resources:
+  - servicemonitors
+  verbs:
+  - get
+  - create
+- apiGroups:
+  - apps
+  resourceNames:
+  - nfn-operator
+  resources:
+  - deployments/finalizers
+  verbs:
+  - update
+- apiGroups:
+  - k8s.plugin.opnfv.org
+  resources:
+  - '*'
+  - providernetworks
+  verbs:
+  - '*'
+
+---
+
+kind: ClusterRoleBinding
+apiVersion: rbac.authorization.k8s.io/v1
+metadata:
+  name: k8s-nfn-crb
+subjects:
+- kind: Group
+  name: system:serviceaccounts
+  apiGroup: rbac.authorization.k8s.io
+roleRef:
+  kind: ClusterRole
+  name: k8s-nfn-cr
+  apiGroup: rbac.authorization.k8s.io
+
diff --git a/go.mod b/go.mod
index f006a12..4d0d716 100644 (file)
--- a/go.mod
+++ b/go.mod
@@ -1,38 +1,48 @@
 module ovn4nfv-k8s-plugin
 
 require (
-       github.com/containernetworking/cni v0.6.0
-       github.com/containernetworking/plugins v0.7.4
-       github.com/coreos/go-iptables v0.4.0 // indirect
-       github.com/gogo/protobuf v1.1.1 // indirect
-       github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b // indirect
-       github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c // indirect
-       github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf // indirect
-       github.com/googleapis/gnostic v0.2.0 // indirect
-       github.com/gregjones/httpcache v0.0.0-20181110185634-c63ab54fda8f // indirect
-       github.com/hashicorp/golang-lru v0.5.0 // indirect
-       github.com/imdario/mergo v0.3.6 // indirect
-       github.com/json-iterator/go v1.1.5 // indirect
-       github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
-       github.com/modern-go/reflect2 v1.0.1 // indirect
-       github.com/onsi/ginkgo v1.6.0
-       github.com/onsi/gomega v1.4.2
+       github.com/Azure/go-autorest/autorest v0.5.0 // indirect
+       github.com/NYTimes/gziphandler v1.0.1 // indirect
+       github.com/containernetworking/cni v0.7.1
+       github.com/containernetworking/plugins v0.8.1
+       github.com/coreos/go-iptables v0.4.2 // indirect
+       github.com/google/btree v1.0.0 // indirect
+       github.com/gophercloud/gophercloud v0.2.0 // indirect
+       github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 // indirect
+       github.com/mitchellh/mapstructure v1.1.2
+       github.com/onsi/ginkgo v1.7.0
+       github.com/onsi/gomega v1.4.3
        github.com/peterbourgon/diskv v2.0.1+incompatible // indirect
-       github.com/sirupsen/logrus v1.2.0
-       github.com/spf13/pflag v1.0.3 // indirect
+       github.com/safchain/ethtool v0.0.0-20190326074333-42ed695e3de8 // indirect
+       github.com/sirupsen/logrus v1.4.1
+       github.com/spf13/pflag v1.0.3
+       github.com/sqs/goreturns v0.0.0-20181028201513-538ac6014518 // indirect
        github.com/urfave/cli v1.20.0
        github.com/vishvananda/netlink v1.0.0
-       github.com/vishvananda/netns v0.0.0-20180720170159-13995c7128cc // indirect
-       golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288 // indirect
-       golang.org/x/time v0.0.0-20181108054448-85acf8d2951c // indirect
+       github.com/vishvananda/netns v0.0.0-20190625233234-7109fa855b0f // indirect
+       github.com/zmb3/gogetdoc v0.0.0-20190228002656-b37376c5da6a // indirect
+       golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4 // indirect
+       golang.org/x/lint v0.0.0-20190409202823-959b441ac422 // indirect
+       golang.org/x/net v0.0.0-20190724013045-ca1201d0de80 // indirect
+       golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3 // indirect
+       golang.org/x/text v0.3.2 // indirect
+       golang.org/x/tools v0.0.0-20190802220118-1d1727260058 // indirect
+       golang.org/x/tools/gopls v0.1.3 // indirect
        gopkg.in/gcfg.v1 v1.2.3
-       gopkg.in/inf.v0 v0.9.1 // indirect
        gopkg.in/warnings.v0 v0.1.2 // indirect
-       k8s.io/api v0.0.0-20181117111259-46ad728b8d13
-       k8s.io/apimachinery v0.0.0-20181116115711-1b0702fe2927
-       k8s.io/client-go v10.0.0+incompatible
-       k8s.io/klog v0.1.0 // indirect
-       k8s.io/kube-openapi v0.0.0-20181114233023-0317810137be // indirect
-       k8s.io/utils v0.0.0-20181115163542-0d26856f57b3
-       sigs.k8s.io/yaml v1.1.0 // indirect
+       k8s.io/api v0.0.0-20190612125737-db0771252981
+       k8s.io/apimachinery v0.0.0-20190704094733-8f6ac2502e51
+       //k8s.io/apimachinery v0.0.0-20190612125636-6a5db36e93ad
+       k8s.io/client-go v11.0.1-0.20190409021438-1a26190bd76a+incompatible
+       k8s.io/kube-openapi v0.0.0-20190603182131-db7b694dc208 // indirect
+       k8s.io/utils v0.0.0-20190506122338-8fab8cb257d5
+       sigs.k8s.io/controller-runtime v0.2.0-beta.4
+       sigs.k8s.io/controller-tools v0.1.10
+)
+
+// Pinned to kubernetes-1.13.4
+replace (
+       k8s.io/kube-state-metrics => k8s.io/kube-state-metrics v1.6.0
+       sigs.k8s.io/controller-runtime => sigs.k8s.io/controller-runtime v0.2.0-beta.4
+       sigs.k8s.io/controller-tools => sigs.k8s.io/controller-tools v0.1.11-0.20190411181648-9d55346c2bde
 )
diff --git a/go.sum b/go.sum
index 77a3141..9555709 100644 (file)
--- a/go.sum
+++ b/go.sum
-github.com/containernetworking/cni v0.6.0 h1:FXICGBZNMtdHlW65trpoHviHctQD3seWhRRcqp2hMOU=
-github.com/containernetworking/cni v0.6.0/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY=
-github.com/containernetworking/plugins v0.7.4 h1:ugkuXfg1Pdzm54U5DGMzreYIkZPSCmSq4rm5TIXVICA=
-github.com/containernetworking/plugins v0.7.4/go.mod h1:dagHaAhNjXjT9QYOklkKJDGaQPTg4pf//FrUcJeb7FU=
-github.com/coreos/go-iptables v0.4.0 h1:wh4UbVs8DhLUbpyq97GLJDKrQMjEDD63T1xE4CrsKzQ=
-github.com/coreos/go-iptables v0.4.0/go.mod h1:/mVI274lEDI2ns62jHCDnCyBF9Iwsmekav8Dbxlm1MU=
+bitbucket.org/ww/goautoneg v0.0.0-20120707110453-75cd24fc2f2c/go.mod h1:1vhO7Mn/FZMgOgDVGLy5X1mE6rq1HbkBdkF/yj8zkcg=
+cloud.google.com/go v0.0.0-20160913182117-3b1ae45394a2/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
+cloud.google.com/go v0.26.0 h1:e0WKqKTd5BnrG8aKH3J3h+QvEIQtSUcf2n5UZ5ZgLtQ=
+cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
+cloud.google.com/go v0.31.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
+cloud.google.com/go v0.34.0 h1:eOI3/cP2VTU6uZLDYAoic+eyzzB9YyGmJ7eIjl8rOPg=
+cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
+cloud.google.com/go v0.37.2 h1:4y4L7BdHenTfZL0HervofNTHh9Ad6mNX72cQvl+5eH0=
+cloud.google.com/go v0.37.2/go.mod h1:H8IAquKe2L30IxoupDgqTaQvKSwF/c8prYHynGIWQbA=
+contrib.go.opencensus.io/exporter/ocagent v0.4.9/go.mod h1:ueLzZcP7LPhPulEBukGn4aLh7Mx9YJwpVJ9nL2FYltw=
+contrib.go.opencensus.io/exporter/ocagent v0.4.11 h1:Zwy9skaqR2igcEfSVYDuAsbpa33N0RPtnYTHEe2whPI=
+contrib.go.opencensus.io/exporter/ocagent v0.4.11/go.mod h1:7ihiYRbdcVfW4m4wlXi9WRPdv79C0fStcjNlyE6ek9s=
+contrib.go.opencensus.io/exporter/ocagent v0.4.12 h1:jGFvw3l57ViIVEPKKEUXPcLYIXJmQxLUh6ey1eJhwyc=
+contrib.go.opencensus.io/exporter/ocagent v0.4.12/go.mod h1:450APlNTSR6FrvC3CTRqYosuDstRB9un7SOx2k/9ckA=
+git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg=
+git.apache.org/thrift.git v0.12.0/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg=
+github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
+github.com/Azure/go-autorest v11.1.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
+github.com/Azure/go-autorest v11.5.2+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
+github.com/Azure/go-autorest v11.7.0+incompatible h1:gzma19dc9ejB75D90E5S+/wXouzpZyA+CV+/MJPSD/k=
+github.com/Azure/go-autorest v11.7.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
+github.com/Azure/go-autorest/autorest v0.5.0 h1:Mlm9qy2fpQ9MvfyI41G2Zf5B4CsgjjNbLOWszfK6KrY=
+github.com/Azure/go-autorest/autorest v0.5.0/go.mod h1:9HLKlQjVBH6U3oDfsXOeVc56THsLPw1L03yban4xThw=
+github.com/Azure/go-autorest/autorest/adal v0.2.0 h1:7IBDu1jgh+ADHXnEYExkV9RE/ztOOlxdACkkPRthGKw=
+github.com/Azure/go-autorest/autorest/adal v0.2.0/go.mod h1:MeS4XhScH55IST095THyTxElntu7WqB7pNbZo8Q5G3E=
+github.com/Azure/go-autorest/autorest/date v0.1.0 h1:YGrhWfrgtFs84+h0o46rJrlmsZtyZRg470CqAXTZaGM=
+github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA=
+github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0=
+github.com/Azure/go-autorest/logger v0.1.0 h1:ruG4BSDXONFRrZZJ2GUXDiUyVpayPmb1GnWeHDdaNKY=
+github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc=
+github.com/Azure/go-autorest/tracing v0.1.0 h1:TRBxC5Pj/fIuh4Qob0ZpkggbfT8RC0SubHbpV3p4/Vc=
+github.com/Azure/go-autorest/tracing v0.1.0/go.mod h1:ROEEAFwXycQw7Sn3DXNtEedEvdeRAgDr0izn4z5Ij88=
+github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
+github.com/MakeNowJust/heredoc v0.0.0-20171113091838-e9091a26100e/go.mod h1:64YHyfSL2R96J44Nlwm39UHepQbyR5q10x7iYa1ks2E=
+github.com/Masterminds/goutils v1.1.0/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
+github.com/Masterminds/semver v1.4.2/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y=
+github.com/Masterminds/sprig v0.0.0-20190301161902-9f8fceff796f/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o=
+github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=
+github.com/NYTimes/gziphandler v1.0.1/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=
+github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
+github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
+github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI=
+github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
+github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
+github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M=
+github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
+github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
+github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
+github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
+github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
+github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
+github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
+github.com/appscode/jsonpatch v0.0.0-20190108182946-7c0e3b262f30 h1:Kn3rqvbUFqSepE2OqVu0Pn1CbDw9IuMlONapol0zuwk=
+github.com/appscode/jsonpatch v0.0.0-20190108182946-7c0e3b262f30/go.mod h1:4AJxUpXUhv4N+ziTvIcWWXgeorXpxPZOfk9HdEVr96M=
+github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
+github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
+github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973 h1:xJ4a3vCFaGF/jqvzLMYoU8P317H5OQ+Via4RmuPwCS0=
+github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
+github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps=
+github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g=
+github.com/census-instrumentation/opencensus-proto v0.2.0 h1:LzQXZOgg4CQfE6bFvXGM30YZL1WW/M337pXml+GrcZ4=
+github.com/census-instrumentation/opencensus-proto v0.2.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
+github.com/chai2010/gettext-go v0.0.0-20170215093142-bf70f2a70fb1/go.mod h1:/iP1qXHoty45bqomnu2LM+VVyAEdWN+vtSHGlQgyxbw=
+github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
+github.com/containernetworking/cni v0.7.1 h1:fE3r16wpSEyaqY4Z4oFrLMmIGfBYIKpPrHK31EJ9FzE=
+github.com/containernetworking/cni v0.7.1/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY=
+github.com/containernetworking/plugins v0.8.1 h1:dJbykiiSIS3Xvo8d+A6rSXcUEFGfvCjUA+bUED4qegQ=
+github.com/containernetworking/plugins v0.8.1/go.mod h1:dagHaAhNjXjT9QYOklkKJDGaQPTg4pf//FrUcJeb7FU=
+github.com/coreos/bbolt v1.3.0/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
+github.com/coreos/bbolt v1.3.3/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
+github.com/coreos/etcd v3.3.9+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
+github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
+github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
+github.com/coreos/go-iptables v0.4.2 h1:KH0EwId05JwWIfb96gWvkiT2cbuOu8ygqUaB+yPAwIg=
+github.com/coreos/go-iptables v0.4.2/go.mod h1:/mVI274lEDI2ns62jHCDnCyBF9Iwsmekav8Dbxlm1MU=
+github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
+github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
+github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
+github.com/coreos/go-systemd v0.0.0-20181031085051-9002847aa142/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
+github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
+github.com/coreos/prometheus-operator v0.29.0 h1:Moi4klbr1xUVaofWzlaM12mxwCL294GiLW2Qj8ku0sY=
+github.com/coreos/prometheus-operator v0.29.0/go.mod h1:SO+r5yZUacDFPKHfPoUjI3hMsH+ZUdiuNNhuSq3WoSg=
+github.com/cyphar/filepath-securejoin v0.2.2/go.mod h1:FpkQEhXnPnOthhzymB7CGsFk2G9VLXONKD9G7QGMM+4=
+github.com/davecgh/go-spew v0.0.0-20151105211317-5215b55f46b2/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/dgrijalva/jwt-go v0.0.0-20160705203006-01aeca54ebda/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
+github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
+github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
+github.com/docker/distribution v2.6.2+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
+github.com/docker/distribution v2.7.0+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
+github.com/docker/docker v0.0.0-20180612054059-a9fbbdc8dd87/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
+github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM=
+github.com/docker/spdystream v0.0.0-20181023171402-6480d4af844c/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM=
+github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
+github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
+github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
+github.com/elazarl/go-bindata-assetfs v1.0.0/go.mod h1:v+YaWX3bdea5J/mo8dSETolEo7R71Vk1u8bnjau5yw4=
+github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc=
+github.com/elazarl/goproxy v0.0.0-20190421051319-9d40249d3c2f/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc=
+github.com/elazarl/goproxy/ext v0.0.0-20190421051319-9d40249d3c2f/go.mod h1:gNh8nYJoAm43RfaxurUnxr+N1PwuFV3ZMl/efxlIlY8=
+github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
+github.com/emicklei/go-restful v2.8.0+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
+github.com/emicklei/go-restful v2.8.1+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
+github.com/emicklei/go-restful v2.9.3+incompatible h1:2OwhVdhtzYUp5P5wuGsVDPagKSRd9JK72sJCHVCXh5g=
+github.com/emicklei/go-restful v2.9.3+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
+github.com/emicklei/go-restful-swagger12 v0.0.0-20170926063155-7524189396c6/go.mod h1:qr0VowGBT4CS4Q8vFF8BSeKz34PuqKGxs/L0IAQA9DQ=
+github.com/evanphx/json-patch v0.0.0-20190203023257-5858425f7550/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
+github.com/evanphx/json-patch v3.0.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
+github.com/evanphx/json-patch v4.0.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
+github.com/evanphx/json-patch v4.1.0+incompatible h1:K1MDoo4AZ4wU0GIU/fPmtZg7VpzLjCxu+UwBD1FvwOc=
+github.com/evanphx/json-patch v4.1.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
+github.com/evanphx/json-patch v4.5.0+incompatible h1:ouOWdg56aJriqS0huScTkVXPC5IcNrDCXZ6OoTAWu7M=
+github.com/evanphx/json-patch v4.5.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
+github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d/go.mod h1:ZZMPRZwes7CROmyNKgQzC3XPs6L/G2EJLHddWejkmf4=
+github.com/fatih/camelcase v1.0.0/go.mod h1:yN2Sb0lFhZJUdVvtELVWefmrXpuZESvPmqwoZc+/fpc=
+github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
 github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
-github.com/gogo/protobuf v1.1.1 h1:72R+M5VuhED/KujmZVcIquuo8mBgX4oVda//DQb3PXo=
+github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
+github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
+github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
+github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q=
+github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
+github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
+github.com/go-logr/logr v0.1.0 h1:M1Tv3VzNlEHg6uyACnRdtrploV2P7wZqH8BoQMtz0cg=
+github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas=
+github.com/go-logr/zapr v0.1.0 h1:h+WVe9j6HAA01niTJPA/kKH0i7e0rLZBCwauQFcRE54=
+github.com/go-logr/zapr v0.1.0/go.mod h1:tabnROwaDl0UNxkVeFRbY8bwB37GwRv0P8lg6aAiEnk=
+github.com/go-logr/zapr v0.1.1 h1:qXBXPDdNncunGs7XeEpsJt8wCjYBygluzfdLO0G5baE=
+github.com/go-logr/zapr v0.1.1/go.mod h1:tabnROwaDl0UNxkVeFRbY8bwB37GwRv0P8lg6aAiEnk=
+github.com/go-openapi/analysis v0.0.0-20180825180245-b006789cd277/go.mod h1:k70tL6pCuVxPJOHXQ+wIac1FUrvNkHolPie/cLEU6hI=
+github.com/go-openapi/analysis v0.17.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik=
+github.com/go-openapi/errors v0.17.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0=
+github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0=
+github.com/go-openapi/jsonpointer v0.17.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M=
+github.com/go-openapi/jsonpointer v0.19.0 h1:FTUMcX77w5rQkClIzDtTxvn6Bsa894CcrzNj2MMfeg8=
+github.com/go-openapi/jsonpointer v0.19.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M=
+github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg=
+github.com/go-openapi/jsonreference v0.17.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I=
+github.com/go-openapi/jsonreference v0.19.0 h1:BqWKpV1dFd+AuiKlgtddwVIFQsuMpxfBDBHGfM2yNpk=
+github.com/go-openapi/jsonreference v0.19.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I=
+github.com/go-openapi/loads v0.17.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU=
+github.com/go-openapi/runtime v0.0.0-20180920151709-4f900dc2ade9/go.mod h1:6v9a6LTXWQCdL8k1AO3cvqx5OtZY/Y9wKTgaoP6YRfA=
+github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc=
+github.com/go-openapi/spec v0.17.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI=
+github.com/go-openapi/spec v0.17.2/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI=
+github.com/go-openapi/spec v0.18.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI=
+github.com/go-openapi/spec v0.19.0 h1:A4SZ6IWh3lnjH0rG0Z5lkxazMGBECtrZcbyYQi+64k4=
+github.com/go-openapi/spec v0.19.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI=
+github.com/go-openapi/strfmt v0.17.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU=
+github.com/go-openapi/strfmt v0.17.2/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU=
+github.com/go-openapi/strfmt v0.18.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU=
+github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I=
+github.com/go-openapi/swag v0.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg=
+github.com/go-openapi/swag v0.19.0 h1:Kg7Wl7LkTPlmc393QZQ/5rQadPhi7pBVEMZxyTi0Ii8=
+github.com/go-openapi/swag v0.19.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg=
+github.com/go-openapi/validate v0.17.2/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+MYsct2VUrAJ4=
+github.com/go-openapi/validate v0.18.0/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+MYsct2VUrAJ4=
+github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
+github.com/gobuffalo/envy v1.6.5/go.mod h1:N+GkhhZ/93bGZc6ZKhJLP6+m+tCNPKwgSpH9kaifseQ=
+github.com/gobuffalo/envy v1.6.15/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI=
+github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
+github.com/gogo/protobuf v0.0.0-20170330071051-c0656edd0d9e/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
+github.com/gogo/protobuf v0.0.0-20171007142547-342cbe0a0415/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
 github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
-github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=
+github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
+github.com/gogo/protobuf v1.2.1 h1:/s5zKNz0uPFCZ5hddgPdo2TK2TVrUNMn0OOX8/aZMTE=
+github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
+github.com/golang/glog v0.0.0-20141105023935-44145f04b68c/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
 github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
+github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/groupcache v0.0.0-20180513044358-24b0969c4cb7 h1:u4bArs140e9+AfE52mFHOXVFnOSBJBRlzTHrOPLOIhE=
+github.com/golang/groupcache v0.0.0-20180513044358-24b0969c4cb7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/groupcache v0.0.0-20180924190550-6f2cf27854a4/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/groupcache v0.0.0-20181024230925-c65c006176ff/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef h1:veQD95Isof8w9/WXiA+pa3tz3fJXkt5B7QaRBrM62gk=
+github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E=
+github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
+github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
+github.com/golang/protobuf v0.0.0-20161109072736-4bd1920723d7/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
 github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM=
 github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
-github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c h1:964Od4U6p2jUkFxvCydnIczKteheJEzHRToSGK3Bnlw=
+github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg=
+github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
 github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
+github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo=
+github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
+github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
+github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY=
+github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
+github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ=
+github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
+github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI=
 github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf h1:+RRA9JqSOZFfKrOeqr2z77+8R2RKyh8PG66dcu1V0ck=
 github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI=
+github.com/google/gofuzz v1.0.0 h1:A8PeW59pxE9IoFRqBp37U+mSNaQoZ46F1f0f863XSXw=
+github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
+github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
+github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
+github.com/google/uuid v1.0.0 h1:b4Gk+7WdP/d3HZH8EJsZpvV7EtDOgaZLtnaNGIu1adA=
+github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
+github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY=
+github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
+github.com/googleapis/gnostic v0.0.0-20170426233943-68f4ded48ba9/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY=
+github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY=
 github.com/googleapis/gnostic v0.2.0 h1:l6N3VoaVzTncYYW+9yOz2LJJammFZGBO13sqgEhpy9g=
 github.com/googleapis/gnostic v0.2.0/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY=
+github.com/gophercloud/gophercloud v0.0.0-20180330165814-781450b3c4fc/go.mod h1:3WdhXV3rUYy9p6AUW8d94kr+HS62Y4VL9mBnFxsD8q4=
+github.com/gophercloud/gophercloud v0.0.0-20190318015731-ff9851476e98/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8=
+github.com/gophercloud/gophercloud v0.0.0-20190408160324-6c7ac67f8855 h1:3dfUujjROkkXcwIpsh9z6bjOhPFooLpxejc7qgX13/g=
+github.com/gophercloud/gophercloud v0.0.0-20190408160324-6c7ac67f8855/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8=
+github.com/gophercloud/gophercloud v0.2.0 h1:lD2Bce2xBAMNNcFZ0dObTpXkGLlVIb33RPVUNVpw6ic=
+github.com/gophercloud/gophercloud v0.2.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8=
+github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
+github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
+github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
+github.com/gotestyourself/gotestyourself v2.2.0+incompatible/go.mod h1:zZKM6oeNM8k+FRljX1mnzVYeS8wiGgQyvST1/GafPbY=
+github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
 github.com/gregjones/httpcache v0.0.0-20181110185634-c63ab54fda8f h1:ShTPMJQes6tubcjzGMODIVG5hlrCeImaBnZzKF2N8SM=
 github.com/gregjones/httpcache v0.0.0-20181110185634-c63ab54fda8f/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
+github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 h1:+ngKgrYPPJrOjhax5N+uePQ0Fh1Z7PheYoUI/0nzkPA=
+github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
+github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
+github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
+github.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw=
+github.com/grpc-ecosystem/grpc-gateway v1.5.1/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw=
+github.com/grpc-ecosystem/grpc-gateway v1.6.2/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw=
+github.com/grpc-ecosystem/grpc-gateway v1.6.3/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw=
+github.com/grpc-ecosystem/grpc-gateway v1.8.5 h1:2+KSC78XiO6Qy0hIjfc1OD9H+hsaJdJlb8Kqsd41CTE=
+github.com/grpc-ecosystem/grpc-gateway v1.8.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
+github.com/grpc-ecosystem/grpc-health-probe v0.2.0/go.mod h1:4GVx/bTCtZaSzhjbGueDY5YgBdsmKeVx+LErv/n0L6s=
+github.com/hashicorp/golang-lru v0.0.0-20160207214719-a0d98a5f2880/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
+github.com/hashicorp/golang-lru v0.0.0-20180201235237-0fb14efe8c47 h1:UnszMmmmm5vLwWzDjTFVIkfhvWF1NdrmChl8L2NUDCw=
+github.com/hashicorp/golang-lru v0.0.0-20180201235237-0fb14efe8c47/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
 github.com/hashicorp/golang-lru v0.5.0 h1:CL2msUPvZTLb5O648aiLNJw3hnBxN2+1Jq8rCOH9wdo=
 github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
+github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU=
+github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
+github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
 github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
 github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
+github.com/huandu/xstrings v1.2.0/go.mod h1:DvyZB1rfVYsBIigL8HwpZgxHwXozlTgGqn63UyNX5k4=
+github.com/iancoleman/strcase v0.0.0-20180726023541-3605ed457bf7/go.mod h1:SK73tn/9oHe+/Y0h39VT4UCxmurVJkR5NA7kMEAOgSE=
+github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
 github.com/imdario/mergo v0.3.6 h1:xTNEAn+kxVO7dTZGu0CegyqKZmoWFI0rF8UxjlB2d28=
 github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
-github.com/json-iterator/go v1.1.5 h1:gL2yXlmiIo4+t+y32d4WGwOjKGYcGOuyrg46vadswDE=
+github.com/imdario/mergo v0.3.7 h1:Y+UAYTZ7gDEuOfhxKWy+dvb5dRQ6rJjFSdX2HZY1/gI=
+github.com/imdario/mergo v0.3.7/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
+github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
+github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU=
+github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
+github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
+github.com/json-iterator/go v0.0.0-20180612202835-f2b4162afba3/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
+github.com/json-iterator/go v0.0.0-20180701071628-ab8a2e0c74be/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
 github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
+github.com/json-iterator/go v1.1.6 h1:MrUvLMLTMxbqFJ9kzlvat/rYZqZnW3u4wkLzWTaFwKs=
+github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
+github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
+github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
+github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
+github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
+github.com/konsorten/go-windows-terminal-sequences v0.0.0-20180402223658-b729f2633dfe/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
 github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
+github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
+github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
+github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
+github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
+github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
+github.com/kr/pty v1.1.4/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
+github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
+github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
+github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
+github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
+github.com/mailru/easyjson v0.0.0-20190403194419-1ea4449da983 h1:wL11wNW7dhKIcRCHSm4sHKPWz0tt4mwBsVodG7+Xyqg=
+github.com/mailru/easyjson v0.0.0-20190403194419-1ea4449da983/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
+github.com/markbates/inflect v1.0.4/go.mod h1:1fR9+pO2KHEO9ZRtto13gDwwZaAKstQzferVeWqbgNs=
+github.com/martinlindhe/base36 v0.0.0-20180729042928-5cda0030da17/go.mod h1:+AtEs8xrBpCeYgSLoY/aJ6Wf37jtBuR0s35750M27+8=
+github.com/mattbaird/jsonpatch v0.0.0-20171005235357-81af80346b1a/go.mod h1:M1qoD/MqPgTZIk0EWKB38wE28ACRfVcn+cU08jyArI0=
+github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
+github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
+github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
+github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
+github.com/maxbrunsfeld/counterfeiter v0.0.0-20181017030959-1aadac120687/go.mod h1:aoVsckWnsNzazwF2kmD+bzgdr4GBlbK91zsdivQJ2eU=
+github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
+github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo=
+github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
+github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
 github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
 github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/reflect2 v0.0.0-20180320133207-05fbef0ca5da/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
+github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
 github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
 github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
-github.com/onsi/ginkgo v1.6.0 h1:Ix8l273rp3QzYgXSR+c8d1fTG7UPgYkOSELPhiY/YGw=
+github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
+github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
+github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
+github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
 github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
-github.com/onsi/gomega v1.4.2 h1:3mYCb7aPxS/RU7TI1y4rkEn1oKmPRjNJLNEXgw7MH2I=
+github.com/onsi/ginkgo v1.7.0 h1:WSHQ+IS43OoUrWtD1/bbclrwK8TTH5hzp+umCiuxHgs=
+github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
+github.com/onsi/gomega v0.0.0-20190113212917-5533ce8a0da3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
+github.com/onsi/gomega v1.4.2-0.20180831124310-ae19f1b56d53/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
 github.com/onsi/gomega v1.4.2/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
+github.com/onsi/gomega v1.4.3 h1:RE1xgDvH7imwFD45h+u2SgIfERHlS2yNG4DObb5BSKU=
+github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
+github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
+github.com/openshift/origin v0.0.0-20160503220234-8f127d736703/go.mod h1:0Rox5r9C8aQn6j1oAOQ0c1uC86mYbUFObzjBRvUKHII=
+github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8=
+github.com/openzipkin/zipkin-go v0.1.3/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8=
+github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw=
+github.com/operator-framework/operator-lifecycle-manager v0.0.0-20181023032605-e838f7fb2186/go.mod h1:Ma5ZXd4S1vmMyewWlF7aO8CZiokR7Sd8dhSfkGkNU4U=
+github.com/operator-framework/operator-lifecycle-manager v0.0.0-20190105193533-81104ffdc4fb/go.mod h1:XMyE4n2opUK4N6L45YGQkXXi8F9fD7XDYFv/CsS6V5I=
+github.com/operator-framework/operator-lifecycle-manager v0.0.0-20190128024246-5eb7ae5bdb7a/go.mod h1:vq6TTFvg6ti1Bn6ACsZneZTmjTsURgDD6tQtVDbEgsU=
+github.com/operator-framework/operator-registry v1.0.1/go.mod h1:1xEdZjjUg2hPEd52LG3YQ0jtwiwEGdm98S1TH5P4RAA=
+github.com/operator-framework/operator-registry v1.0.4/go.mod h1:hve6YwcjM2nGVlscLtNsp9sIIBkNZo6jlJgzWw7vP9s=
+github.com/operator-framework/operator-sdk v0.9.0 h1:moY3n5vsg4OpD3FzHvqI68Fv+gJFQ1GaDKMHm2NRpF8=
+github.com/operator-framework/operator-sdk v0.9.0/go.mod h1:7eW7ldXmvenehIMVdO2zCdERf/828Mrftq4u7GS0I68=
+github.com/pborman/uuid v0.0.0-20170612153648-e790cca94e6c h1:MUyE44mTvnI5A0xrxIxaMqoWFzPfQvtE2IWUollMDMs=
+github.com/pborman/uuid v0.0.0-20170612153648-e790cca94e6c/go.mod h1:VyrYX9gd7irzKovcSS6BIIEwPRkP2Wm2m9ufcdFSJ34=
+github.com/pborman/uuid v0.0.0-20180906182336-adf5a7427709/go.mod h1:VyrYX9gd7irzKovcSS6BIIEwPRkP2Wm2m9ufcdFSJ34=
+github.com/pborman/uuid v1.2.0 h1:J7Q5mO4ysT1dv8hyrUGHb9+ooztCXu1D8MY8DZYsu3g=
+github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
+github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
+github.com/pelletier/go-toml v1.3.0/go.mod h1:PN7xzY2wHTK0K9p34ErDQMlFxa51Fk0OUruD3k1mMwo=
+github.com/petar/GoLLRB v0.0.0-20130427215148-53be0d36a84c/go.mod h1:HUpKUBZnpzkdx0kD/+Yfuft+uD3zHGtXF/XJB14TUr4=
 github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI=
 github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
+github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
+github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
+github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
-github.com/sirupsen/logrus v1.2.0 h1:juTguoYk5qI21pwyTXY3B3Y5cOTH3ZUyZCg1v/mihuo=
+github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
+github.com/prometheus/client_golang v0.9.0 h1:tXuTFVHC03mW0D+Ua1Q2d1EAVqLTuggX50V0VLICCzY=
+github.com/prometheus/client_golang v0.9.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
+github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
+github.com/prometheus/client_golang v0.9.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4xf/QclQDMrYNZzcM=
+github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829 h1:D+CiwcpGTW6pL6bv6KI3KbyEyCKyS+1JWS2h8PNDnGA=
+github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs=
+github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910 h1:idejC8f05m9MGOsuEi1ATq9shN03HrxNkD/luQvxCv8=
+github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
+github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f h1:BVwpUVJDADN2ufcGik7W992pyps0wZ888b/y9GXcLTU=
+github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
+github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90 h1:S/YWwWx/RA8rT8tKFRuGUZhuA90OyIBpPCXkcbwU8DE=
+github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e h1:n/3MEhJQjQxrOUCzh1Y3Re6aJUUWRp2M9+Oc3eVn/54=
+github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
+github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
+github.com/prometheus/common v0.0.0-20190104105734-b1c43a6df3ae/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
+github.com/prometheus/common v0.2.0 h1:kUZDBDTdBVBYBj5Tmh2NZLlF60mfjA27rM34b+cVwNU=
+github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
+github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273 h1:agujYaXJSxSo18YNX3jzl+4G6Bstwt+kqv47GS12uL0=
+github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
+github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
+github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
+github.com/prometheus/procfs v0.0.0-20190104112138-b1a0a9a36d74/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
+github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1 h1:/K3IL0Z1quvmJ7X0A1AwNEK7CRkVK3YwfOU/QAL4WGg=
+github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
+github.com/prometheus/procfs v0.0.0-20190403104016-ea9eea638872 h1:0aNv3xC7DmQoy1/x1sMh18g+fihWW68LL13i8ao9kl4=
+github.com/prometheus/procfs v0.0.0-20190403104016-ea9eea638872/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
+github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
+github.com/robfig/cron v0.0.0-20170526150127-736158dc09e1/go.mod h1:JGuDeoQd7Z6yL4zQhZ3OPEVHB7fL6Ka6skscFHfmt2k=
+github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
+github.com/rogpeppe/go-charset v0.0.0-20180617210344-2471d30d28b4/go.mod h1:qgYeAmZ5ZIpBWTGllZSQnw97Dj+woV0toclVaRGI8pc=
+github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
+github.com/rogpeppe/go-internal v1.2.2/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
+github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
+github.com/russross/blackfriday v0.0.0-20151117072312-300106c228d5/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
+github.com/safchain/ethtool v0.0.0-20190326074333-42ed695e3de8 h1:2c1EFnZHIPCW8qKWgHMH/fX2PkSabFc5mrVzfUNdg5U=
+github.com/safchain/ethtool v0.0.0-20190326074333-42ed695e3de8/go.mod h1:Z0q5wiBQGYcxhMZ6gUqHn6pYNLypFAvaL3UvgZLR0U4=
+github.com/sclevine/spec v1.0.0/go.mod h1:W4J29eT/Kzv7/b9IWLB055Z+qvVC9vt0Arko24q7p+U=
+github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
+github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
+github.com/sirupsen/logrus v1.1.1/go.mod h1:zrgwTnHtNr00buQ1vSptGe8m1f/BbgsPukg8qsT7A+A=
 github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
+github.com/sirupsen/logrus v1.4.1 h1:GL2rEmy6nsikmW0r8opw9JIRScdMF5hA8cOYLH7In1k=
+github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
+github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
+github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
+github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
+github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
+github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
+github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
+github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
+github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
+github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
+github.com/spf13/pflag v1.0.2/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
 github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg=
 github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
+github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
+github.com/sqs/goreturns v0.0.0-20181028201513-538ac6014518 h1:iD+PFTQwKEmbwSdwfvP5ld2WEI/g7qbdhmHJ2ASfYGs=
+github.com/sqs/goreturns v0.0.0-20181028201513-538ac6014518/go.mod h1:CKI4AZ4XmGV240rTHfO0hfE83S6/a3/Q1siZJ/vXf7A=
+github.com/stevvooe/resumable v0.0.0-20180830230917-22b14a53ba50/go.mod h1:1pdIZTAHUz+HDKDVZ++5xg/duPlhKAIzw9qy42CWYp4=
+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/testify v0.0.0-20151208002404-e3a8ff8ce365/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
 github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
+github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
+github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
+github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA=
+github.com/technosophos/moniker v0.0.0-20180509230615-a5dbd03a2245/go.mod h1:O1c8HleITsZqzNZDjSNzirUGsMT0oGu9LhHKoJrqO+A=
+github.com/tmc/grpc-websocket-proxy v0.0.0-20171017195756-830351dc03c6/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
+github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
+github.com/ugorji/go v1.1.1/go.mod h1:hnLbHMwcvSihnDhEfx2/BzKp2xb0Y+ErdfYcrs9tkJQ=
+github.com/ugorji/go/codec v0.0.0-20181022190402-e5e69e061d4f/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
+github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
 github.com/urfave/cli v1.20.0 h1:fDqGv3UG/4jbVl/QkFwEdddtEDjh/5Ov6X+0B/3bPaw=
 github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
 github.com/vishvananda/netlink v1.0.0 h1:bqNY2lgheFIu1meHUFSH3d7vG93AFyqg3oGbJCOJgSM=
 github.com/vishvananda/netlink v1.0.0/go.mod h1:+SR5DhBJrl6ZM7CoCKvpw5BKroDKQ+PJqOg65H/2ktk=
-github.com/vishvananda/netns v0.0.0-20180720170159-13995c7128cc h1:R83G5ikgLMxrBvLh22JhdfI8K6YXEPHx5P03Uu3DRs4=
-github.com/vishvananda/netns v0.0.0-20180720170159-13995c7128cc/go.mod h1:ZjcWmFBXmLKZu9Nxj3WKYEafiSqer2rnvPr0en9UNpI=
-golang.org/x/crypto v0.0.0-20180904163835-0709b304e793 h1:u+LnwYTOOW7Ukr/fppxEb1Nwz0AtPflrblfvUudpo+I=
+github.com/vishvananda/netns v0.0.0-20190625233234-7109fa855b0f h1:nBX3nTcmxEtHSERBJaIo1Qa26VwRaopnZmfDQUXsF4I=
+github.com/vishvananda/netns v0.0.0-20190625233234-7109fa855b0f/go.mod h1:ZjcWmFBXmLKZu9Nxj3WKYEafiSqer2rnvPr0en9UNpI=
+github.com/xiang90/probing v0.0.0-20160813154853-07dd2e8dfe18/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
+github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
+github.com/xlab/handysort v0.0.0-20150421192137-fb3537ed64a1/go.mod h1:QcJo0QPSfTONNIgpN5RA8prR7fF8nkF6cTWTcNerRO8=
+github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
+github.com/zmb3/gogetdoc v0.0.0-20190228002656-b37376c5da6a h1:00UFliGZl2UciXe8o/2iuEsRQ9u7z0rzDTVzuj6EYY0=
+github.com/zmb3/gogetdoc v0.0.0-20190228002656-b37376c5da6a/go.mod h1:ofmGw6LrMypycsiWcyug6516EXpIxSbZ+uI9ppGypfY=
+go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
+go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA=
+go.opencensus.io v0.19.1/go.mod h1:gug0GbSHa8Pafr0d2urOSgoXHZ6x/RUlaiT0d9pqb4A=
+go.opencensus.io v0.19.2/go.mod h1:NO/8qkisMZLZ1FCsKNqtJPwc8/TaclWyY0B6wcYNg9M=
+go.opencensus.io v0.20.0 h1:L/ARO58pdktB6dLmYI0zAyW1XnavEmGziFd0MKfxnck=
+go.opencensus.io v0.20.0/go.mod h1:NO/8qkisMZLZ1FCsKNqtJPwc8/TaclWyY0B6wcYNg9M=
+go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
+go.opencensus.io v0.20.2 h1:NAfh7zF0/3/HqtMvJNZ/RFrSlCE6ZTlHmKfhL/Dm1Jk=
+go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
+go.uber.org/atomic v1.3.2 h1:2Oa65PReHzfn29GpvgsYwloV9AVFHPDk8tYxt2c2tr4=
+go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
+go.uber.org/multierr v1.1.0 h1:HoEmRHQPVSqub6w2z2d2EOVs2fjyFRGyofhKuyDq0QI=
+go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
+go.uber.org/zap v1.9.1 h1:XCJQEf3W6eZaVwhRBof6ImoYGJSITeKWsyeh3HFu/5o=
+go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
+go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE=
+golang.org/x/build v0.0.0-20190314133821-5284462c4bec/go.mod h1:atTaCNAy0f16Ah5aV1gMSwgiKVHwu/JncqDpuRr7lS4=
+golang.org/x/crypto v0.0.0-20180222182404-49796115aa4b/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
+golang.org/x/crypto v0.0.0-20180820150726-614d502a4dac h1:7d7lG9fHOLdL6jZPtnV4LpI41SbohIJ1Atq7U991dMg=
+golang.org/x/crypto v0.0.0-20180820150726-614d502a4dac/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
 golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
-golang.org/x/net v0.0.0-20180906233101-161cd47e91fd h1:nTDtHvHSdCn1m6ITfMRqtOd/9+7a3s8RBNOZ3eYZzJA=
+golang.org/x/crypto v0.0.0-20181015023909-0c41d7ab0a0e/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
+golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
+golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
+golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
+golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M=
+golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20190404164418-38d8ce5564a5 h1:bselrhR0Or1vomJZC8ZIjWtbDmn9OYFLX5Ik9alpJpE=
+golang.org/x/crypto v0.0.0-20190404164418-38d8ce5564a5/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
+golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4 h1:HuIa8hRrWRSrqYzx1qI49NNxhdi2PrY7gxVSq1JjLDc=
+golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
+golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
+golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
+golang.org/x/lint v0.0.0-20181217174547-8f45f776aaf1/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
+golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
+golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
+golang.org/x/lint v0.0.0-20190409202823-959b441ac422 h1:QzoH/1pFpZguR8NrRHLcO6jKqfv2zpuSqZLgdm7ZmjI=
+golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288 h1:JIqe8uIcRBHXDQVvZtHwp80ai3Lw3IJAeJEs55Dc1W0=
-golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
+golang.org/x/net v0.0.0-20180911220305-26e67e76b6c3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181005035420-146acd28ed58/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181029044818-c44066c5c816/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181106065722-10aee1819953/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190206173232-65e2d4e15006 h1:bfLnR+k0tq5Lqt6dflRLcZiz6UaXCMt3vhYJ1l4FQ80=
+golang.org/x/net v0.0.0-20190206173232-65e2d4e15006/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190311183353-d8887717615a h1:oWX7TPOiFAMXLq8o0ikBYfCJVlRHBcsciT5bXOrH628=
+golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3 h1:0GoQqolDA55aaLxZyTzK/Y2ePZzZTUrRacwib7cNsYQ=
+golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20190724013045-ca1201d0de80 h1:Ao/3l156eZf2AW5wK8a7/smtodRU+gha3+BeqJ69lRk=
+golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/oauth2 v0.0.0-20170412232759-a6bd8cefa181/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
+golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be h1:vEDujvNQGv4jgYKudGeI/+DAX4Jffq6hpD55MmoEvKs=
+golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
+golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
+golang.org/x/oauth2 v0.0.0-20181105165119-ca4130e427c7/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
+golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
+golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421 h1:Wo7BWFiOk0QRFMLYMqJGFMd9CgUAcGx7V+qEg/h5IBI=
+golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a h1:tImsplftrFpALCYumobsd0K86vlAs/eXGFms2txfJfA=
+golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/perf v0.0.0-20180704124530-6e6d33e29852/go.mod h1:JLpeXjPJfIyPr5TlbXLkXWLhP8nz10XfvxElABhCtcw=
 golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6 h1:bjcUS9ztw9kFmmIxJInhon/0Is3p+EHBKNgquIzo1OI=
+golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU=
+golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e h1:o3PsSEY8E4eXWkXrIP9YJALUkVZqzHJT5DOasTyn8Vs=
 golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20181023152157-44b849a8bc13/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20181029174526-d69651ed3497/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20181218192612-074acd46bca6/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190209173611-3b5209105503/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a h1:1BGLXjeY4akVXGgbC9HugT3Jv3hCI0z56oJR5vAMgBU=
+golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190312061237-fead79001313 h1:pczuHS43Cp2ktBEEmLwScxgjWsBSzdaQiKzUyf3DTTc=
+golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190405154228-4b34438f7a67 h1:1Fzlr8kkDLQwqMP8GxrhptBLqZG/EDpiATneiZHY998=
+golang.org/x/sys v0.0.0-20190405154228-4b34438f7a67/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3 h1:4y9KwBHBgBNwDbtu44R5o1fdOCQUEXhbk/P4A9WmJq0=
+golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
-golang.org/x/time v0.0.0-20181108054448-85acf8d2951c h1:fqgJT0MGcGpPgpWU7VRdRjuArfcOvC4AoJmILihzhDg=
+golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2 h1:z99zHgr7hKfrUcX/KsoJk5FJfjTceCKIp96+biqP4To=
+golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.1-0.20181227161524-e6919f6577db h1:6/JqlYfC1CCaLnGceQTI+sDGhC9UBSPAsBqI0Gun6kU=
+golang.org/x/text v0.3.1-0.20181227161524-e6919f6577db/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
+golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
+golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
+golang.org/x/time v0.0.0-20161028155119-f51c12702a4d/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2 h1:+DCIGbF/swA92ohVg0//6X2IVY3KZs6p9mix0ziNYJM=
+golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 h1:SvFZT6jyqRaOeXpc5h/JSfZenJ2O330aBsf7JfSUXmQ=
+golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20181011152555-a398e557df60/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20181207195948-8634b1ecd393/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20181207222222-4c874b978acb/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20181219222714-6e267b5cc78e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190213015956-f7e1b50d2251/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
+golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190408170212-12dd9f86f350/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190710153321-831012c29e42/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI=
+golang.org/x/tools v0.0.0-20190802220118-1d1727260058 h1:OsDcfiJHbqcv+S4eovUaiPY2ILzR76hXrjILS4sV4Wg=
+golang.org/x/tools v0.0.0-20190802220118-1d1727260058/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI=
+golang.org/x/tools/gopls v0.1.3 h1:CB5ECiPysqZrwxcyRjN+exyZpY0gODTZvNiqQi3lpeo=
+golang.org/x/tools/gopls v0.1.3/go.mod h1:vrCQzOKxvuiZLjCKSmbbov04oeBQQOb4VQqwYK2PWIY=
+gomodules.xyz/jsonpatch/v2 v2.0.0 h1:OyHbl+7IOECpPKfVK42oFr6N7+Y2dR+Jsb/IiDV3hOo=
+gomodules.xyz/jsonpatch/v2 v2.0.0/go.mod h1:IhYNNY4jnS53ZnfE4PAmpKtDpTCj1JFXc+3mwe7XcUU=
+google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
+google.golang.org/api v0.0.0-20181030000543-1d582fd0359e/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
+google.golang.org/api v0.0.0-20181220000619-583d854617af/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
+google.golang.org/api v0.2.0/go.mod h1:IfRCZScioGtypHNTlz3gFk67J8uePVW7uDTBzXuIkhU=
+google.golang.org/api v0.3.0 h1:UIJY20OEo3+tK5MBlcdx37kmdH6EnRjGkW78mc6+EeA=
+google.golang.org/api v0.3.0/go.mod h1:IuvZyQh8jgscv8qWfQ4ABd8m7hEudgBFM/EdhA3BnXw=
+google.golang.org/api v0.3.1 h1:oJra/lMfmtm13/rgY/8i3MzjFWYXvQIAKjQ3HqofMk8=
+google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk=
+google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
+google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
+google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
+google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
+google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
+google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
+google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
+google.golang.org/genproto v0.0.0-20181016170114-94acd270e44e/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
+google.golang.org/genproto v0.0.0-20181029155118-b69ba1387ce2/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
+google.golang.org/genproto v0.0.0-20181219182458-5a97ab628bfb/go.mod h1:7Ep/1NZk928CDR8SjdVbjWNpdIf6nzjE3BTgJDr2Atg=
+google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19 h1:Lj2SnHtxkRGJDqnGaSjo+CCdIieEnwVazbOXILwQemk=
+google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190404172233-64821d5d2107 h1:xtNn7qFlagY2mQNFHMSRPjT2RkOV4OXM7P5TVy9xATo=
+google.golang.org/genproto v0.0.0-20190404172233-64821d5d2107/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
+google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio=
+google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
+google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
+google.golang.org/grpc v1.19.1 h1:TrBcJ1yqAl1G++wO39nD/qtgpsW9/1+QGrluyMGEYgM=
+google.golang.org/grpc v1.19.1/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
+gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
 gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
 gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
 gopkg.in/gcfg.v1 v1.2.3 h1:m8OOJ4ccYHnx2f4gQwpno8nAX5OGOh7RLaaz0pj3Ogs=
 gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o=
+gopkg.in/inf.v0 v0.9.0/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
 gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
 gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
+gopkg.in/natefinch/lumberjack.v2 v2.0.0-20170531160350-a96e63847dc3/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
+gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
+gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
+gopkg.in/square/go-jose.v2 v2.3.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
 gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
 gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
 gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME=
 gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
-gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE=
+gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
 gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
-k8s.io/api v0.0.0-20181117111259-46ad728b8d13 h1:kScMdtyRni4/487ib8PTPnHNcgWWiRRH94iyicChmS0=
-k8s.io/api v0.0.0-20181117111259-46ad728b8d13/go.mod h1:iuAfoD4hCxJ8Onx9kaTIt30j7jUFS00AXQi6QMi99vA=
-k8s.io/apimachinery v0.0.0-20181116115711-1b0702fe2927 h1:RkGqNDA3mKVqAQbCHoB+QeHshksgEzhAlFqY4HhlSu0=
-k8s.io/apimachinery v0.0.0-20181116115711-1b0702fe2927/go.mod h1:ccL7Eh7zubPUSh9A3USN90/OzHNSVN6zxzde07TDCL0=
-k8s.io/client-go v9.0.0+incompatible h1:/PdJjifJTjMFe0G4ESclZDcwF1+bFePTJ2xf+MXjcvs=
-k8s.io/client-go v9.0.0+incompatible/go.mod h1:7vJpHMYJwNQCWgzmNV+VYUl1zCObLyodBc8nIyt8L5s=
-k8s.io/client-go v10.0.0+incompatible h1:F1IqCqw7oMBzDkqlcBymRq1450wD0eNqLE9jzUrIi34=
-k8s.io/client-go v10.0.0+incompatible/go.mod h1:7vJpHMYJwNQCWgzmNV+VYUl1zCObLyodBc8nIyt8L5s=
-k8s.io/klog v0.1.0 h1:I5HMfc/DtuVaGR1KPwUrTc476K8NCqNBldC7H4dYEzk=
+gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
+gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
+grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o=
+honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.0-20180920025451-e3ad64cb4ed3/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+k8s.io/api v0.0.0-20190222213804-5cb15d344471 h1:MzQGt8qWQCR+39kbYRd0uQqsvSidpYqJLFeWiJ9l4OE=
+k8s.io/api v0.0.0-20190222213804-5cb15d344471/go.mod h1:iuAfoD4hCxJ8Onx9kaTIt30j7jUFS00AXQi6QMi99vA=
+k8s.io/api v0.0.0-20190409021203-6e4e0e4f393b/go.mod h1:iuAfoD4hCxJ8Onx9kaTIt30j7jUFS00AXQi6QMi99vA=
+k8s.io/api v0.0.0-20190612125737-db0771252981 h1:DN1D/gMpl+h70Ek3Gb2ykCEI0QqIUtJ2e2z9PnAYz+Q=
+k8s.io/api v0.0.0-20190612125737-db0771252981/go.mod h1:SR4nMi8IQTDnEi4768MsMCoZ9DyfRls7wy+TbRrFicA=
+k8s.io/apiextensions-apiserver v0.0.0-20190228180357-d002e88f6236/go.mod h1:IxkesAMoaCRoLrPJdZNZUQp9NfZnzqaVzLhb2VEQzXE=
+k8s.io/apiextensions-apiserver v0.0.0-20190409022649-727a075fdec8 h1:q1Qvjzs/iEdXF6A1a8H3AKVFDzJNcJn3nXMs6R6qFtA=
+k8s.io/apiextensions-apiserver v0.0.0-20190409022649-727a075fdec8/go.mod h1:IxkesAMoaCRoLrPJdZNZUQp9NfZnzqaVzLhb2VEQzXE=
+k8s.io/apimachinery v0.0.0-20190221213512-86fb29eff628 h1:UYfHH+KEF88OTg+GojQUwFTNxbxwmoktLwutUzR0GPg=
+k8s.io/apimachinery v0.0.0-20190221213512-86fb29eff628/go.mod h1:ccL7Eh7zubPUSh9A3USN90/OzHNSVN6zxzde07TDCL0=
+k8s.io/apimachinery v0.0.0-20190404173353-6a84e37a896d/go.mod h1:ccL7Eh7zubPUSh9A3USN90/OzHNSVN6zxzde07TDCL0=
+k8s.io/apimachinery v0.0.0-20190612125636-6a5db36e93ad h1:x1lITOfDEbnzt8D1cZJsPbdnx/hnv28FxY2GKkxmxgU=
+k8s.io/apimachinery v0.0.0-20190612125636-6a5db36e93ad/go.mod h1:I4A+glKBHiTgiEjQiCCQfCAIcIMFGt291SmsvcrFzJA=
+k8s.io/apimachinery v0.0.0-20190704094733-8f6ac2502e51 h1:Nuz3yWD9v9dVvDiVSBIah+B+pxkxQxtuBAx2712t7tQ=
+k8s.io/apimachinery v0.0.0-20190704094733-8f6ac2502e51/go.mod h1:ccL7Eh7zubPUSh9A3USN90/OzHNSVN6zxzde07TDCL0=
+k8s.io/apiserver v0.0.0-20181026151315-13cfe3978170/go.mod h1:6bqaTSOSJavUIXUtfaR9Os9JtTCm8ZqH2SUl2S60C4w=
+k8s.io/apiserver v0.0.0-20181213151703-3ccfe8365421/go.mod h1:6bqaTSOSJavUIXUtfaR9Os9JtTCm8ZqH2SUl2S60C4w=
+k8s.io/cli-runtime v0.0.0-20181213153952-835b10687cb6/go.mod h1:qWnH3/b8sp/l7EvlDh7ulDU3UWA4P4N1NFbEEP791tM=
+k8s.io/client-go v0.0.0-20190228174230-b40b2a5939e4 h1:aE8wOCKuoRs2aU0OP/Rz8SXiAB0FTTku3VtGhhrkSmc=
+k8s.io/client-go v0.0.0-20190228174230-b40b2a5939e4/go.mod h1:7vJpHMYJwNQCWgzmNV+VYUl1zCObLyodBc8nIyt8L5s=
+k8s.io/client-go v11.0.1-0.20190409021438-1a26190bd76a+incompatible h1:U5Bt+dab9K8qaUmXINrkXO135kA11/i5Kg1RUydgaMQ=
+k8s.io/client-go v11.0.1-0.20190409021438-1a26190bd76a+incompatible/go.mod h1:7vJpHMYJwNQCWgzmNV+VYUl1zCObLyodBc8nIyt8L5s=
+k8s.io/code-generator v0.0.0-20181203235156-f8cba74510f3/go.mod h1:MYiN+ZJZ9HkETbgVZdWw2AsuAi9PZ4V80cwfuf2axe8=
+k8s.io/gengo v0.0.0-20181106084056-51747d6e00da/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
+k8s.io/gengo v0.0.0-20181113154421-fd15ee9cc2f7/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
+k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
+k8s.io/gengo v0.0.0-20190327210449-e17681d19d3a/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
+k8s.io/helm v2.13.1+incompatible/go.mod h1:LZzlS4LQBHfciFOurYBFkCMTaZ0D1l+p0teMg7TSULI=
+k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk=
 k8s.io/klog v0.1.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk=
-k8s.io/kube-openapi v0.0.0-20181114233023-0317810137be h1:aWEq4nbj7HRJ0mtKYjNSk/7X28Tl6TI6FeG8gKF+r7Q=
-k8s.io/kube-openapi v0.0.0-20181114233023-0317810137be/go.mod h1:BXM9ceUBTj2QnfH2MK1odQs778ajze1RxcmP6S8RVVc=
-k8s.io/utils v0.0.0-20181115163542-0d26856f57b3 h1:S3/Kq185JnolOEemhmDXXd23l2t4bX5hPQPQPADlF1E=
-k8s.io/utils v0.0.0-20181115163542-0d26856f57b3/go.mod h1:8k8uAuAQ0rXslZKaEWd0c3oVhZz7sSzSiPnVZayjIX0=
+k8s.io/klog v0.2.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk=
+k8s.io/klog v0.3.0 h1:0VPpR+sizsiivjIfIAQH/rl8tan6jvWkS7lU+0di3lE=
+k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk=
+k8s.io/klog v0.3.1 h1:RVgyDHY/kFKtLqh67NvEWIgkMneNoIrdkN0CxDSQc68=
+k8s.io/klog v0.3.1/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk=
+k8s.io/kube-aggregator v0.0.0-20181204002017-122bac39d429/go.mod h1:8sbzT4QQKDEmSCIbfqjV0sd97GpUT7A4W626sBiYJmU=
+k8s.io/kube-aggregator v0.0.0-20181213152105-1e8cd453c474/go.mod h1:8sbzT4QQKDEmSCIbfqjV0sd97GpUT7A4W626sBiYJmU=
+k8s.io/kube-openapi v0.0.0-20180731170545-e3762e86a74c/go.mod h1:BXM9ceUBTj2QnfH2MK1odQs778ajze1RxcmP6S8RVVc=
+k8s.io/kube-openapi v0.0.0-20181031203759-72693cb1fadd/go.mod h1:BXM9ceUBTj2QnfH2MK1odQs778ajze1RxcmP6S8RVVc=
+k8s.io/kube-openapi v0.0.0-20190228160746-b3a7cee44a30/go.mod h1:BXM9ceUBTj2QnfH2MK1odQs778ajze1RxcmP6S8RVVc=
+k8s.io/kube-openapi v0.0.0-20190320154901-5e45bb682580/go.mod h1:BXM9ceUBTj2QnfH2MK1odQs778ajze1RxcmP6S8RVVc=
+k8s.io/kube-openapi v0.0.0-20190603182131-db7b694dc208 h1:5sW+fEHvlJI3Ngolx30CmubFulwH28DhKjGf70Xmtco=
+k8s.io/kube-openapi v0.0.0-20190603182131-db7b694dc208/go.mod h1:nfDlWeOsu3pUf4yWGL+ERqohP4YsZcBJXWMK+gkzOA4=
+k8s.io/kube-state-metrics v1.6.0 h1:6wkxiTPTZ4j+LoMWuT+rZ+OlUWswktzXs5yHmggmAZ0=
+k8s.io/kube-state-metrics v1.6.0/go.mod h1:84+q9aGVQPzXYGgtvyhZr/fSI6BdLsbPWXn37RASc9k=
+k8s.io/kubernetes v1.11.7-beta.0.0.20181219023948-b875d52ea96d/go.mod h1:ocZa8+6APFNC2tX1DZASIbocyYT5jHzqFVsY5aoB7Jk=
+k8s.io/kubernetes v1.11.8-beta.0.0.20190124204751-3a10094374f2/go.mod h1:ocZa8+6APFNC2tX1DZASIbocyYT5jHzqFVsY5aoB7Jk=
+k8s.io/utils v0.0.0-20190308190857-21c4ce38f2a7 h1:8r+l4bNWjRlsFYlQJnKJ2p7s1YQPj4XyXiJVqDHRx7c=
+k8s.io/utils v0.0.0-20190308190857-21c4ce38f2a7/go.mod h1:8k8uAuAQ0rXslZKaEWd0c3oVhZz7sSzSiPnVZayjIX0=
+k8s.io/utils v0.0.0-20190506122338-8fab8cb257d5 h1:VBM/0P5TWxwk+Nw6Z+lAw3DKgO76g90ETOiA6rfLV1Y=
+k8s.io/utils v0.0.0-20190506122338-8fab8cb257d5/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew=
+sigs.k8s.io/controller-runtime v0.1.12 h1:ovDq28E64PeY1yR+6H7DthakIC09soiDCrKvfP2tPYo=
+sigs.k8s.io/controller-runtime v0.1.12/go.mod h1:HFAYoOh6XMV+jKF1UjFwrknPbowfyHEHHRdJMf2jMX8=
+sigs.k8s.io/controller-runtime v0.2.0-alpha.0 h1:WM6lu3SNU4SsMlDYvjJyLsG9nW3ffb/4/FpE2ZGrtnc=
+sigs.k8s.io/controller-runtime v0.2.0-alpha.0/go.mod h1:HFAYoOh6XMV+jKF1UjFwrknPbowfyHEHHRdJMf2jMX8=
+sigs.k8s.io/controller-runtime v0.2.0-alpha.1 h1:JptNtMgYhE/eRAtHSkHiCJPntPpuVHHq2vAQQD/S3Oo=
+sigs.k8s.io/controller-runtime v0.2.0-alpha.1/go.mod h1:TSH2R0nSz4WAlUUlNnOFcOR/VUhfwBLlmtq2X6AiQCA=
+sigs.k8s.io/controller-runtime v0.2.0-beta.4 h1:S1XVfRWR1MuIXZdkYx3jN8JDw+bbQxmWZroy0i87z/A=
+sigs.k8s.io/controller-runtime v0.2.0-beta.4/go.mod h1:HweyYKQ8fBuzdu2bdaeBJvsFgAi/OqBBnrVGXcqKhME=
+sigs.k8s.io/controller-tools v0.1.11-0.20190411181648-9d55346c2bde/go.mod h1:ATWLRP3WGxuAN9HcT2LaKHReXIH+EZGzRuMHuxjXfhQ=
+sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI=
+sigs.k8s.io/testing_frameworks v0.1.0/go.mod h1:VVBKrHmJ6Ekkfz284YKhQePcdycOzNH9qL6ht1zEr/U=
+sigs.k8s.io/testing_frameworks v0.1.1 h1:cP2l8fkA3O9vekpy5Ks8mmA0NW/F7yBdXf8brkWhVrs=
+sigs.k8s.io/testing_frameworks v0.1.1/go.mod h1:VVBKrHmJ6Ekkfz284YKhQePcdycOzNH9qL6ht1zEr/U=
 sigs.k8s.io/yaml v1.1.0 h1:4A07+ZFc2wgJwo8YNlQpr1rVlgUDlxXHhPJciaPY5gs=
 sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
+vbom.ml/util v0.0.0-20180919145318-efcd4e0f9787/go.mod h1:so/NYdZXCz+E3ZpW0uAoCj6uzU2+8OWDFv/HxUSs7kI=
diff --git a/internal/pkg/factory/factory.go b/internal/pkg/factory/factory.go
deleted file mode 100644 (file)
index a635e3f..0000000
+++ /dev/null
@@ -1,318 +0,0 @@
-package factory
-
-import (
-       "fmt"
-       "reflect"
-       "sync"
-       "sync/atomic"
-       "time"
-
-       "github.com/sirupsen/logrus"
-
-       kapi "k8s.io/api/core/v1"
-       knet "k8s.io/api/networking/v1"
-       metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-       "k8s.io/apimachinery/pkg/labels"
-       informerfactory "k8s.io/client-go/informers"
-       "k8s.io/client-go/kubernetes"
-       "k8s.io/client-go/tools/cache"
-)
-
-type informer struct {
-       sync.Mutex
-       oType    reflect.Type
-       inf      cache.SharedIndexInformer
-       handlers map[uint64]cache.ResourceEventHandler
-}
-
-func (i *informer) forEachHandler(obj interface{}, f func(id uint64, handler cache.ResourceEventHandler)) {
-       i.Lock()
-       defer i.Unlock()
-
-       objType := reflect.TypeOf(obj)
-       if objType != i.oType {
-               logrus.Errorf("object type %v did not match expected %v", objType, i.oType)
-               return
-       }
-
-       for id, handler := range i.handlers {
-               f(id, handler)
-       }
-}
-
-// WatchFactory initializes and manages common kube watches
-type WatchFactory struct {
-       iFactory       informerfactory.SharedInformerFactory
-       informers      map[reflect.Type]*informer
-       handlerCounter uint64
-}
-
-const (
-       resyncInterval = 12 * time.Hour
-)
-
-func newInformer(oType reflect.Type, inf cache.SharedIndexInformer) *informer {
-       return &informer{
-               oType:    oType,
-               inf:      inf,
-               handlers: make(map[uint64]cache.ResourceEventHandler),
-       }
-}
-
-var (
-       podType       reflect.Type = reflect.TypeOf(&kapi.Pod{})
-       serviceType   reflect.Type = reflect.TypeOf(&kapi.Service{})
-       endpointsType reflect.Type = reflect.TypeOf(&kapi.Endpoints{})
-       policyType    reflect.Type = reflect.TypeOf(&knet.NetworkPolicy{})
-       namespaceType reflect.Type = reflect.TypeOf(&kapi.Namespace{})
-       nodeType      reflect.Type = reflect.TypeOf(&kapi.Node{})
-)
-
-// NewWatchFactory initializes a new watch factory
-func NewWatchFactory(c kubernetes.Interface, stopChan <-chan struct{}) (*WatchFactory, error) {
-       // resync time is 12 hours, none of the resources being watched in ovn-kubernetes have
-       // any race condition where a resync may be required e.g. cni executable on node watching for
-       // events on pods and assuming that an 'ADD' event will contain the annotations put in by
-       // ovnkube master (currently, it is just a 'get' loop)
-       // the downside of making it tight (like 10 minutes) is needless spinning on all resources
-       wf := &WatchFactory{
-               iFactory:  informerfactory.NewSharedInformerFactory(c, resyncInterval),
-               informers: make(map[reflect.Type]*informer),
-       }
-
-       // Create shared informers we know we'll use
-       wf.informers[podType] = newInformer(podType, wf.iFactory.Core().V1().Pods().Informer())
-       wf.informers[serviceType] = newInformer(serviceType, wf.iFactory.Core().V1().Services().Informer())
-       wf.informers[endpointsType] = newInformer(endpointsType, wf.iFactory.Core().V1().Endpoints().Informer())
-       wf.informers[policyType] = newInformer(policyType, wf.iFactory.Networking().V1().NetworkPolicies().Informer())
-       wf.informers[namespaceType] = newInformer(namespaceType, wf.iFactory.Core().V1().Namespaces().Informer())
-       wf.informers[nodeType] = newInformer(nodeType, wf.iFactory.Core().V1().Nodes().Informer())
-
-       wf.iFactory.Start(stopChan)
-       res := wf.iFactory.WaitForCacheSync(stopChan)
-       for oType, synced := range res {
-               if !synced {
-                       return nil, fmt.Errorf("error in syncing cache for %v informer", oType)
-               }
-               informer := wf.informers[oType]
-               informer.inf.AddEventHandler(wf.newFederatedHandler(informer))
-       }
-
-       return wf, nil
-}
-
-func (wf *WatchFactory) newFederatedHandler(inf *informer) cache.ResourceEventHandlerFuncs {
-       return cache.ResourceEventHandlerFuncs{
-               AddFunc: func(obj interface{}) {
-                       inf.forEachHandler(obj, func(id uint64, handler cache.ResourceEventHandler) {
-                               logrus.Debugf("running %v ADD event for handler %d", inf.oType, id)
-                               handler.OnAdd(obj)
-                       })
-               },
-               UpdateFunc: func(oldObj, newObj interface{}) {
-                       inf.forEachHandler(newObj, func(id uint64, handler cache.ResourceEventHandler) {
-                               logrus.Debugf("running %v UPDATE event for handler %d", inf.oType, id)
-                               handler.OnUpdate(oldObj, newObj)
-                       })
-               },
-               DeleteFunc: func(obj interface{}) {
-                       if inf.oType != reflect.TypeOf(obj) {
-                               tombstone, ok := obj.(cache.DeletedFinalStateUnknown)
-                               if !ok {
-                                       logrus.Errorf("couldn't get object from tombstone: %+v", obj)
-                                       return
-                               }
-                               obj = tombstone.Obj
-                               objType := reflect.TypeOf(obj)
-                               if inf.oType != objType {
-                                       logrus.Errorf("expected tombstone object resource type %v but got %v", inf.oType, objType)
-                                       return
-                               }
-                       }
-                       inf.forEachHandler(obj, func(id uint64, handler cache.ResourceEventHandler) {
-                               logrus.Debugf("running %v DELETE event for handler %d", inf.oType, id)
-                               handler.OnDelete(obj)
-                       })
-               },
-       }
-}
-
-func getObjectMeta(objType reflect.Type, obj interface{}) (*metav1.ObjectMeta, error) {
-       switch objType {
-       case podType:
-               if pod, ok := obj.(*kapi.Pod); ok {
-                       return &pod.ObjectMeta, nil
-               }
-       case serviceType:
-               if service, ok := obj.(*kapi.Service); ok {
-                       return &service.ObjectMeta, nil
-               }
-       case endpointsType:
-               if endpoints, ok := obj.(*kapi.Endpoints); ok {
-                       return &endpoints.ObjectMeta, nil
-               }
-       case policyType:
-               if policy, ok := obj.(*knet.NetworkPolicy); ok {
-                       return &policy.ObjectMeta, nil
-               }
-       case namespaceType:
-               if namespace, ok := obj.(*kapi.Namespace); ok {
-                       return &namespace.ObjectMeta, nil
-               }
-       case nodeType:
-               if node, ok := obj.(*kapi.Node); ok {
-                       return &node.ObjectMeta, nil
-               }
-       }
-       return nil, fmt.Errorf("cannot get ObjectMeta from type %v", objType)
-}
-
-func (wf *WatchFactory) addHandler(objType reflect.Type, namespace string, lsel *metav1.LabelSelector, funcs cache.ResourceEventHandler, processExisting func([]interface{})) (uint64, error) {
-       inf, ok := wf.informers[objType]
-       if !ok {
-               return 0, fmt.Errorf("unknown object type %v", objType)
-       }
-
-       sel, err := metav1.LabelSelectorAsSelector(lsel)
-       if err != nil {
-               return 0, fmt.Errorf("error creating label selector: %v", err)
-       }
-
-       filterFunc := func(obj interface{}) bool {
-               if namespace == "" && lsel == nil {
-                       // Unfiltered handler
-                       return true
-               }
-               meta, err := getObjectMeta(objType, obj)
-               if err != nil {
-                       logrus.Errorf("watch handler filter error: %v", err)
-                       return false
-               }
-               if namespace != "" && meta.Namespace != namespace {
-                       return false
-               }
-               if lsel != nil && !sel.Matches(labels.Set(meta.Labels)) {
-                       return false
-               }
-               return true
-       }
-
-       // Process existing items as a set so the caller can clean up
-       // after a restart or whatever
-       existingItems := inf.inf.GetStore().List()
-       if processExisting != nil {
-               items := make([]interface{}, 0)
-               for _, obj := range existingItems {
-                       if filterFunc(obj) {
-                               items = append(items, obj)
-                       }
-               }
-               processExisting(items)
-       }
-
-       handlerID := atomic.AddUint64(&wf.handlerCounter, 1)
-
-       inf.Lock()
-       defer inf.Unlock()
-
-       inf.handlers[handlerID] = cache.FilteringResourceEventHandler{
-               FilterFunc: filterFunc,
-               Handler:    funcs,
-       }
-       logrus.Debugf("added %v event handler %d", objType, handlerID)
-
-       // Send existing items to the handler's add function; informers usually
-       // do this but since we share informers, it's long-since happened so
-       // we must emulate that here
-       for _, obj := range existingItems {
-               inf.handlers[handlerID].OnAdd(obj)
-       }
-
-       return handlerID, nil
-}
-
-func (wf *WatchFactory) removeHandler(objType reflect.Type, handlerID uint64) error {
-       inf, ok := wf.informers[objType]
-       if !ok {
-               return fmt.Errorf("tried to remove unknown object type %v event handler", objType)
-       }
-
-       inf.Lock()
-       defer inf.Unlock()
-       if _, ok := inf.handlers[handlerID]; !ok {
-               return fmt.Errorf("tried to remove unknown object type %v event handler %d", objType, handlerID)
-       }
-       delete(inf.handlers, handlerID)
-       logrus.Debugf("removed %v event handler %d", objType, handlerID)
-       return nil
-}
-
-// AddPodHandler adds a handler function that will be executed on Pod object changes
-func (wf *WatchFactory) AddPodHandler(handlerFuncs cache.ResourceEventHandler, processExisting func([]interface{})) (uint64, error) {
-       return wf.addHandler(podType, "", nil, handlerFuncs, processExisting)
-}
-
-// AddFilteredPodHandler adds a handler function that will be executed when Pod objects that match the given filters change
-func (wf *WatchFactory) AddFilteredPodHandler(namespace string, lsel *metav1.LabelSelector, handlerFuncs cache.ResourceEventHandler, processExisting func([]interface{})) (uint64, error) {
-       return wf.addHandler(podType, namespace, lsel, handlerFuncs, processExisting)
-}
-
-// RemovePodHandler removes a Pod object event handler function
-func (wf *WatchFactory) RemovePodHandler(handlerID uint64) error {
-       return wf.removeHandler(podType, handlerID)
-}
-
-// AddServiceHandler adds a handler function that will be executed on Service object changes
-func (wf *WatchFactory) AddServiceHandler(handlerFuncs cache.ResourceEventHandler, processExisting func([]interface{})) (uint64, error) {
-       return wf.addHandler(serviceType, "", nil, handlerFuncs, processExisting)
-}
-
-// RemoveServiceHandler removes a Service object event handler function
-func (wf *WatchFactory) RemoveServiceHandler(handlerID uint64) error {
-       return wf.removeHandler(serviceType, handlerID)
-}
-
-// AddEndpointsHandler adds a handler function that will be executed on Endpoints object changes
-func (wf *WatchFactory) AddEndpointsHandler(handlerFuncs cache.ResourceEventHandler, processExisting func([]interface{})) (uint64, error) {
-       return wf.addHandler(endpointsType, "", nil, handlerFuncs, processExisting)
-}
-
-// RemoveEndpointsHandler removes a Endpoints object event handler function
-func (wf *WatchFactory) RemoveEndpointsHandler(handlerID uint64) error {
-       return wf.removeHandler(endpointsType, handlerID)
-}
-
-// AddPolicyHandler adds a handler function that will be executed on NetworkPolicy object changes
-func (wf *WatchFactory) AddPolicyHandler(handlerFuncs cache.ResourceEventHandler, processExisting func([]interface{})) (uint64, error) {
-       return wf.addHandler(policyType, "", nil, handlerFuncs, processExisting)
-}
-
-// RemovePolicyHandler removes a NetworkPolicy object event handler function
-func (wf *WatchFactory) RemovePolicyHandler(handlerID uint64) error {
-       return wf.removeHandler(policyType, handlerID)
-}
-
-// AddNamespaceHandler adds a handler function that will be executed on Namespace object changes
-func (wf *WatchFactory) AddNamespaceHandler(handlerFuncs cache.ResourceEventHandler, processExisting func([]interface{})) (uint64, error) {
-       return wf.addHandler(namespaceType, "", nil, handlerFuncs, processExisting)
-}
-
-// AddFilteredNamespaceHandler adds a handler function that will be executed when Namespace objects that match the given filters change
-func (wf *WatchFactory) AddFilteredNamespaceHandler(namespace string, lsel *metav1.LabelSelector, handlerFuncs cache.ResourceEventHandler, processExisting func([]interface{})) (uint64, error) {
-       return wf.addHandler(namespaceType, namespace, lsel, handlerFuncs, processExisting)
-}
-
-// RemoveNamespaceHandler removes a Namespace object event handler function
-func (wf *WatchFactory) RemoveNamespaceHandler(handlerID uint64) error {
-       return wf.removeHandler(namespaceType, handlerID)
-}
-
-// AddNodeHandler adds a handler function that will be executed on Node object changes
-func (wf *WatchFactory) AddNodeHandler(handlerFuncs cache.ResourceEventHandler, processExisting func([]interface{})) (uint64, error) {
-       return wf.addHandler(nodeType, "", nil, handlerFuncs, processExisting)
-}
-
-// RemoveNodeHandler removes a Node object event handler function
-func (wf *WatchFactory) RemoveNodeHandler(handlerID uint64) error {
-       return wf.removeHandler(nodeType, handlerID)
-}
diff --git a/internal/pkg/factory/factory_test.go b/internal/pkg/factory/factory_test.go
deleted file mode 100644 (file)
index 38fb77e..0000000
+++ /dev/null
@@ -1,686 +0,0 @@
-package factory
-
-import (
-       "reflect"
-       "testing"
-
-       "k8s.io/api/core/v1"
-       knet "k8s.io/api/networking/v1"
-       metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-       "k8s.io/apimachinery/pkg/runtime"
-       "k8s.io/apimachinery/pkg/types"
-       "k8s.io/apimachinery/pkg/watch"
-       "k8s.io/client-go/kubernetes/fake"
-       core "k8s.io/client-go/testing"
-       "k8s.io/client-go/tools/cache"
-
-       . "github.com/onsi/ginkgo"
-       . "github.com/onsi/gomega"
-)
-
-func TestFactory(t *testing.T) {
-       RegisterFailHandler(Fail)
-       RunSpecs(t, "Watch Factory Suite")
-}
-
-func newObjectMeta(name, namespace string) metav1.ObjectMeta {
-       return metav1.ObjectMeta{
-               Name:      name,
-               UID:       types.UID(name),
-               Namespace: namespace,
-               Labels: map[string]string{
-                       "name": name,
-               },
-       }
-}
-
-func newPod(name, namespace string) *v1.Pod {
-       return &v1.Pod{
-               Status: v1.PodStatus{
-                       Phase: v1.PodRunning,
-               },
-               ObjectMeta: newObjectMeta(name, namespace),
-               Spec: v1.PodSpec{
-                       Containers: []v1.Container{
-                               {
-                                       Name:  "containerName",
-                                       Image: "containerImage",
-                               },
-                       },
-                       NodeName: "mynode",
-               },
-       }
-}
-
-func newNamespace(name string) *v1.Namespace {
-       return &v1.Namespace{
-               Status: v1.NamespaceStatus{
-                       Phase: v1.NamespaceActive,
-               },
-               ObjectMeta: newObjectMeta(name, name),
-       }
-}
-
-func newNode(name string) *v1.Node {
-       return &v1.Node{
-               Status: v1.NodeStatus{
-                       Phase: v1.NodeRunning,
-               },
-               ObjectMeta: newObjectMeta(name, ""),
-       }
-}
-
-func newPolicy(name, namespace string) *knet.NetworkPolicy {
-       return &knet.NetworkPolicy{
-               ObjectMeta: newObjectMeta(name, namespace),
-       }
-}
-
-func newEndpoints(name, namespace string) *v1.Endpoints {
-       return &v1.Endpoints{
-               ObjectMeta: newObjectMeta(name, namespace),
-       }
-}
-
-func newService(name, namespace string) *v1.Service {
-       return &v1.Service{
-               ObjectMeta: metav1.ObjectMeta{
-                       Name:      name,
-                       UID:       types.UID(name),
-                       Namespace: namespace,
-                       Labels: map[string]string{
-                               "name": name,
-                       },
-               },
-       }
-}
-
-func objSetup(c *fake.Clientset, objType string, listFn func(core.Action) (bool, runtime.Object, error)) *watch.FakeWatcher {
-       w := watch.NewFake()
-       c.AddWatchReactor(objType, core.DefaultWatchReactor(w, nil))
-       c.AddReactor("list", objType, listFn)
-       return w
-}
-
-var _ = Describe("Watch Factory Operations", func() {
-       var (
-               fakeClient                                *fake.Clientset
-               podWatch, namespaceWatch, nodeWatch       *watch.FakeWatcher
-               policyWatch, endpointsWatch, serviceWatch *watch.FakeWatcher
-               pods                                      []*v1.Pod
-               namespaces                                []*v1.Namespace
-               nodes                                     []*v1.Node
-               policies                                  []*knet.NetworkPolicy
-               endpoints                                 []*v1.Endpoints
-               services                                  []*v1.Service
-               stop                                      chan struct{}
-               numAdded, numUpdated, numDeleted          int
-       )
-
-       BeforeEach(func() {
-               fakeClient = &fake.Clientset{}
-               stop = make(chan struct{})
-
-               pods = make([]*v1.Pod, 0)
-               podWatch = objSetup(fakeClient, "pods", func(core.Action) (bool, runtime.Object, error) {
-                       obj := &v1.PodList{}
-                       for _, p := range pods {
-                               obj.Items = append(obj.Items, *p)
-                       }
-                       return true, obj, nil
-               })
-
-               namespaces = make([]*v1.Namespace, 0)
-               namespaceWatch = objSetup(fakeClient, "namespaces", func(core.Action) (bool, runtime.Object, error) {
-                       obj := &v1.NamespaceList{}
-                       for _, p := range namespaces {
-                               obj.Items = append(obj.Items, *p)
-                       }
-                       return true, obj, nil
-               })
-
-               nodes = make([]*v1.Node, 0)
-               nodeWatch = objSetup(fakeClient, "nodes", func(core.Action) (bool, runtime.Object, error) {
-                       obj := &v1.NodeList{}
-                       for _, p := range nodes {
-                               obj.Items = append(obj.Items, *p)
-                       }
-                       return true, obj, nil
-               })
-
-               policies = make([]*knet.NetworkPolicy, 0)
-               policyWatch = objSetup(fakeClient, "networkpolicies", func(core.Action) (bool, runtime.Object, error) {
-                       obj := &knet.NetworkPolicyList{}
-                       for _, p := range policies {
-                               obj.Items = append(obj.Items, *p)
-                       }
-                       return true, obj, nil
-               })
-
-               endpoints = make([]*v1.Endpoints, 0)
-               endpointsWatch = objSetup(fakeClient, "endpoints", func(core.Action) (bool, runtime.Object, error) {
-                       obj := &v1.EndpointsList{}
-                       for _, p := range endpoints {
-                               obj.Items = append(obj.Items, *p)
-                       }
-                       return true, obj, nil
-               })
-
-               services = make([]*v1.Service, 0)
-               serviceWatch = objSetup(fakeClient, "services", func(core.Action) (bool, runtime.Object, error) {
-                       obj := &v1.ServiceList{}
-                       for _, p := range services {
-                               obj.Items = append(obj.Items, *p)
-                       }
-                       return true, obj, nil
-               })
-
-               numAdded = 0
-               numUpdated = 0
-               numDeleted = 0
-       })
-
-       Context("when a processExisting is given", func() {
-               testExisting := func(objType reflect.Type, namespace string, lsel *metav1.LabelSelector) {
-                       wf, err := NewWatchFactory(fakeClient, stop)
-                       Expect(err).NotTo(HaveOccurred())
-                       id, err := wf.addHandler(objType, namespace, lsel,
-                               cache.ResourceEventHandlerFuncs{},
-                               func(objs []interface{}) {
-                                       Expect(len(objs)).To(Equal(1))
-                               })
-                       Expect(err).NotTo(HaveOccurred())
-                       Expect(id).To(BeNumerically(">", uint64(0)))
-                       wf.removeHandler(objType, id)
-                       close(stop)
-               }
-
-               It("is called for each existing pod", func() {
-                       pods = append(pods, newPod("pod1", "default"))
-                       testExisting(podType, "", nil)
-               })
-
-               It("is called for each existing namespace", func() {
-                       namespaces = append(namespaces, newNamespace("default"))
-                       testExisting(namespaceType, "", nil)
-               })
-
-               It("is called for each existing node", func() {
-                       nodes = append(nodes, newNode("default"))
-                       testExisting(nodeType, "", nil)
-               })
-
-               It("is called for each existing policy", func() {
-                       policies = append(policies, newPolicy("denyall", "default"))
-                       testExisting(policyType, "", nil)
-               })
-
-               It("is called for each existing endpoints", func() {
-                       endpoints = append(endpoints, newEndpoints("myendpoint", "default"))
-                       testExisting(endpointsType, "", nil)
-               })
-
-               It("is called for each existing service", func() {
-                       services = append(services, newService("myservice", "default"))
-                       testExisting(serviceType, "", nil)
-               })
-
-               It("is called for each existing pod that matches a given namespace and label", func() {
-                       pod := newPod("pod1", "default")
-                       pod.ObjectMeta.Labels["blah"] = "foobar"
-                       pods = append(pods, pod)
-                       testExisting(podType, "default", &metav1.LabelSelector{
-                               MatchLabels: map[string]string{"blah": "foobar"},
-                       })
-               })
-       })
-
-       Context("when existing items are known to the informer", func() {
-               testExisting := func(objType reflect.Type) {
-                       wf, err := NewWatchFactory(fakeClient, stop)
-                       Expect(err).NotTo(HaveOccurred())
-                       id, err := wf.addHandler(objType, "", nil,
-                               cache.ResourceEventHandlerFuncs{
-                                       AddFunc: func(obj interface{}) {
-                                               numAdded++
-                                       },
-                                       UpdateFunc: func(old, new interface{}) {},
-                                       DeleteFunc: func(obj interface{}) {},
-                               }, nil)
-                       Expect(err).NotTo(HaveOccurred())
-                       Expect(numAdded).To(Equal(2))
-                       wf.removeHandler(objType, id)
-                       close(stop)
-               }
-
-               It("calls ADD for each existing pod", func() {
-                       pods = append(pods, newPod("pod1", "default"))
-                       pods = append(pods, newPod("pod2", "default"))
-                       testExisting(podType)
-               })
-
-               It("calls ADD for each existing namespace", func() {
-                       namespaces = append(namespaces, newNamespace("default"))
-                       namespaces = append(namespaces, newNamespace("default2"))
-                       testExisting(namespaceType)
-               })
-
-               It("calls ADD for each existing node", func() {
-                       nodes = append(nodes, newNode("default"))
-                       nodes = append(nodes, newNode("default2"))
-                       testExisting(nodeType)
-               })
-
-               It("calls ADD for each existing policy", func() {
-                       policies = append(policies, newPolicy("denyall", "default"))
-                       policies = append(policies, newPolicy("denyall2", "default"))
-                       testExisting(policyType)
-               })
-
-               It("calls ADD for each existing endpoints", func() {
-                       endpoints = append(endpoints, newEndpoints("myendpoint", "default"))
-                       endpoints = append(endpoints, newEndpoints("myendpoint2", "default"))
-                       testExisting(endpointsType)
-               })
-
-               It("calls ADD for each existing service", func() {
-                       services = append(services, newService("myservice", "default"))
-                       services = append(services, newService("myservice2", "default"))
-                       testExisting(serviceType)
-               })
-       })
-
-       addFilteredHandler := func(wf *WatchFactory, objType reflect.Type, namespace string, lsel *metav1.LabelSelector, funcs cache.ResourceEventHandlerFuncs) uint64 {
-               id, err := wf.addHandler(objType, namespace, lsel, cache.ResourceEventHandlerFuncs{
-                       AddFunc: func(obj interface{}) {
-                               defer GinkgoRecover()
-                               numAdded++
-                               funcs.AddFunc(obj)
-                       },
-                       UpdateFunc: func(old, new interface{}) {
-                               defer GinkgoRecover()
-                               numUpdated++
-                               funcs.UpdateFunc(old, new)
-                       },
-                       DeleteFunc: func(obj interface{}) {
-                               defer GinkgoRecover()
-                               numDeleted++
-                               funcs.DeleteFunc(obj)
-                       },
-               }, nil)
-               Expect(err).NotTo(HaveOccurred())
-               Expect(id).To(BeNumerically(">", uint64(0)))
-               return id
-       }
-
-       addHandler := func(wf *WatchFactory, objType reflect.Type, funcs cache.ResourceEventHandlerFuncs) uint64 {
-               return addFilteredHandler(wf, objType, "", nil, funcs)
-       }
-
-       It("responds to pod add/update/delete events", func() {
-               wf, err := NewWatchFactory(fakeClient, stop)
-               Expect(err).NotTo(HaveOccurred())
-
-               added := newPod("pod1", "default")
-               id := addHandler(wf, podType, cache.ResourceEventHandlerFuncs{
-                       AddFunc: func(obj interface{}) {
-                               pod := obj.(*v1.Pod)
-                               Expect(reflect.DeepEqual(pod, added)).To(BeTrue())
-                       },
-                       UpdateFunc: func(old, new interface{}) {
-                               newPod := new.(*v1.Pod)
-                               Expect(reflect.DeepEqual(newPod, added)).To(BeTrue())
-                               Expect(newPod.Spec.NodeName).To(Equal("foobar"))
-                       },
-                       DeleteFunc: func(obj interface{}) {
-                               pod := obj.(*v1.Pod)
-                               Expect(reflect.DeepEqual(pod, added)).To(BeTrue())
-                       },
-               })
-
-               pods = append(pods, added)
-               podWatch.Add(added)
-               Eventually(func() int { return numAdded }, 2).Should(Equal(1))
-               added.Spec.NodeName = "foobar"
-               podWatch.Modify(added)
-               Eventually(func() int { return numUpdated }, 2).Should(Equal(1))
-               pods = pods[:0]
-               podWatch.Delete(added)
-               Eventually(func() int { return numDeleted }, 2).Should(Equal(1))
-
-               wf.RemovePodHandler(id)
-               close(stop)
-       })
-
-       It("responds to namespace add/update/delete events", func() {
-               wf, err := NewWatchFactory(fakeClient, stop)
-               Expect(err).NotTo(HaveOccurred())
-
-               added := newNamespace("default")
-               id := addHandler(wf, namespaceType, cache.ResourceEventHandlerFuncs{
-                       AddFunc: func(obj interface{}) {
-                               ns := obj.(*v1.Namespace)
-                               Expect(reflect.DeepEqual(ns, added)).To(BeTrue())
-                       },
-                       UpdateFunc: func(old, new interface{}) {
-                               newNS := new.(*v1.Namespace)
-                               Expect(reflect.DeepEqual(newNS, added)).To(BeTrue())
-                               Expect(newNS.Status.Phase).To(Equal(v1.NamespaceTerminating))
-                       },
-                       DeleteFunc: func(obj interface{}) {
-                               ns := obj.(*v1.Namespace)
-                               Expect(reflect.DeepEqual(ns, added)).To(BeTrue())
-                       },
-               })
-
-               namespaces = append(namespaces, added)
-               namespaceWatch.Add(added)
-               Eventually(func() int { return numAdded }, 2).Should(Equal(1))
-               added.Status.Phase = v1.NamespaceTerminating
-               namespaceWatch.Modify(added)
-               Eventually(func() int { return numUpdated }, 2).Should(Equal(1))
-               namespaces = namespaces[:0]
-               namespaceWatch.Delete(added)
-               Eventually(func() int { return numDeleted }, 2).Should(Equal(1))
-
-               wf.RemoveNamespaceHandler(id)
-               close(stop)
-       })
-
-       It("responds to node add/update/delete events", func() {
-               wf, err := NewWatchFactory(fakeClient, stop)
-               Expect(err).NotTo(HaveOccurred())
-
-               added := newNode("mynode")
-               id := addHandler(wf, nodeType, cache.ResourceEventHandlerFuncs{
-                       AddFunc: func(obj interface{}) {
-                               node := obj.(*v1.Node)
-                               Expect(reflect.DeepEqual(node, added)).To(BeTrue())
-                       },
-                       UpdateFunc: func(old, new interface{}) {
-                               newNode := new.(*v1.Node)
-                               Expect(reflect.DeepEqual(newNode, added)).To(BeTrue())
-                               Expect(newNode.Status.Phase).To(Equal(v1.NodeTerminated))
-                       },
-                       DeleteFunc: func(obj interface{}) {
-                               node := obj.(*v1.Node)
-                               Expect(reflect.DeepEqual(node, added)).To(BeTrue())
-                       },
-               })
-
-               nodes = append(nodes, added)
-               nodeWatch.Add(added)
-               Eventually(func() int { return numAdded }, 2).Should(Equal(1))
-               added.Status.Phase = v1.NodeTerminated
-               nodeWatch.Modify(added)
-               Eventually(func() int { return numUpdated }, 2).Should(Equal(1))
-               nodes = nodes[:0]
-               nodeWatch.Delete(added)
-               Eventually(func() int { return numDeleted }, 2).Should(Equal(1))
-
-               wf.removeHandler(nodeType, id)
-               close(stop)
-       })
-
-       It("responds to policy add/update/delete events", func() {
-               wf, err := NewWatchFactory(fakeClient, stop)
-               Expect(err).NotTo(HaveOccurred())
-
-               added := newPolicy("mypolicy", "default")
-               id := addHandler(wf, policyType, cache.ResourceEventHandlerFuncs{
-                       AddFunc: func(obj interface{}) {
-                               np := obj.(*knet.NetworkPolicy)
-                               Expect(reflect.DeepEqual(np, added)).To(BeTrue())
-                       },
-                       UpdateFunc: func(old, new interface{}) {
-                               newNP := new.(*knet.NetworkPolicy)
-                               Expect(reflect.DeepEqual(newNP, added)).To(BeTrue())
-                               Expect(newNP.Spec.PolicyTypes).To(Equal([]knet.PolicyType{knet.PolicyTypeIngress}))
-                       },
-                       DeleteFunc: func(obj interface{}) {
-                               np := obj.(*knet.NetworkPolicy)
-                               Expect(reflect.DeepEqual(np, added)).To(BeTrue())
-                       },
-               })
-
-               policies = append(policies, added)
-               policyWatch.Add(added)
-               Eventually(func() int { return numAdded }, 2).Should(Equal(1))
-               added.Spec.PolicyTypes = []knet.PolicyType{knet.PolicyTypeIngress}
-               policyWatch.Modify(added)
-               Eventually(func() int { return numUpdated }, 2).Should(Equal(1))
-               policies = policies[:0]
-               policyWatch.Delete(added)
-               Eventually(func() int { return numDeleted }, 2).Should(Equal(1))
-
-               wf.removeHandler(policyType, id)
-               close(stop)
-       })
-
-       It("responds to endpoints add/update/delete events", func() {
-               wf, err := NewWatchFactory(fakeClient, stop)
-               Expect(err).NotTo(HaveOccurred())
-
-               added := newEndpoints("myendpoints", "default")
-               id := addHandler(wf, endpointsType, cache.ResourceEventHandlerFuncs{
-                       AddFunc: func(obj interface{}) {
-                               eps := obj.(*v1.Endpoints)
-                               Expect(reflect.DeepEqual(eps, added)).To(BeTrue())
-                       },
-                       UpdateFunc: func(old, new interface{}) {
-                               newEPs := new.(*v1.Endpoints)
-                               Expect(reflect.DeepEqual(newEPs, added)).To(BeTrue())
-                               Expect(len(newEPs.Subsets)).To(Equal(1))
-                       },
-                       DeleteFunc: func(obj interface{}) {
-                               eps := obj.(*v1.Endpoints)
-                               Expect(reflect.DeepEqual(eps, added)).To(BeTrue())
-                       },
-               })
-
-               endpoints = append(endpoints, added)
-               endpointsWatch.Add(added)
-               Eventually(func() int { return numAdded }, 2).Should(Equal(1))
-               added.Subsets = append(added.Subsets, v1.EndpointSubset{
-                       Ports: []v1.EndpointPort{
-                               {
-                                       Name: "foobar",
-                                       Port: 1234,
-                               },
-                       },
-               })
-               endpointsWatch.Modify(added)
-               Eventually(func() int { return numUpdated }, 2).Should(Equal(1))
-               endpoints = endpoints[:0]
-               endpointsWatch.Delete(added)
-               Eventually(func() int { return numDeleted }, 2).Should(Equal(1))
-
-               wf.removeHandler(endpointsType, id)
-               close(stop)
-       })
-
-       It("responds to service add/update/delete events", func() {
-               wf, err := NewWatchFactory(fakeClient, stop)
-               Expect(err).NotTo(HaveOccurred())
-
-               added := newService("myservice", "default")
-               id := addHandler(wf, serviceType, cache.ResourceEventHandlerFuncs{
-                       AddFunc: func(obj interface{}) {
-                               service := obj.(*v1.Service)
-                               Expect(reflect.DeepEqual(service, added)).To(BeTrue())
-                       },
-                       UpdateFunc: func(old, new interface{}) {
-                               newService := new.(*v1.Service)
-                               Expect(reflect.DeepEqual(newService, added)).To(BeTrue())
-                               Expect(newService.Spec.ClusterIP).To(Equal("1.1.1.1"))
-                       },
-                       DeleteFunc: func(obj interface{}) {
-                               service := obj.(*v1.Service)
-                               Expect(reflect.DeepEqual(service, added)).To(BeTrue())
-                       },
-               })
-
-               services = append(services, added)
-               serviceWatch.Add(added)
-               Eventually(func() int { return numAdded }, 2).Should(Equal(1))
-               added.Spec.ClusterIP = "1.1.1.1"
-               serviceWatch.Modify(added)
-               Eventually(func() int { return numUpdated }, 2).Should(Equal(1))
-               services = services[:0]
-               serviceWatch.Delete(added)
-               Eventually(func() int { return numDeleted }, 2).Should(Equal(1))
-
-               wf.removeHandler(serviceType, id)
-               close(stop)
-       })
-
-       It("stops processing events after the handler is removed", func() {
-               wf, err := NewWatchFactory(fakeClient, stop)
-               Expect(err).NotTo(HaveOccurred())
-
-               added := newNamespace("default")
-               id := addHandler(wf, namespaceType, cache.ResourceEventHandlerFuncs{
-                       AddFunc:    func(obj interface{}) {},
-                       UpdateFunc: func(old, new interface{}) {},
-                       DeleteFunc: func(obj interface{}) {},
-               })
-
-               namespaces = append(namespaces, added)
-               namespaceWatch.Add(added)
-               Eventually(func() int { return numAdded }, 2).Should(Equal(1))
-               wf.RemoveNamespaceHandler(id)
-
-               added2 := newNamespace("other")
-               namespaces = append(namespaces, added2)
-               namespaceWatch.Add(added2)
-               Consistently(func() int { return numAdded }, 2).Should(Equal(1))
-
-               added2.Status.Phase = v1.NamespaceTerminating
-               namespaceWatch.Modify(added2)
-               Consistently(func() int { return numUpdated }, 2).Should(Equal(0))
-               namespaces = []*v1.Namespace{added}
-               namespaceWatch.Delete(added2)
-               Consistently(func() int { return numDeleted }, 2).Should(Equal(0))
-
-               close(stop)
-       })
-
-       It("filters correctly by label and namespace", func() {
-               wf, err := NewWatchFactory(fakeClient, stop)
-               Expect(err).NotTo(HaveOccurred())
-
-               passesFilter := newPod("pod1", "default")
-               passesFilter.ObjectMeta.Labels["blah"] = "foobar"
-               failsFilter := newPod("pod2", "default")
-               failsFilter.ObjectMeta.Labels["blah"] = "baz"
-               failsFilter2 := newPod("pod3", "otherns")
-               failsFilter2.ObjectMeta.Labels["blah"] = "foobar"
-
-               addFilteredHandler(wf,
-                       podType,
-                       "default",
-                       &metav1.LabelSelector{
-                               MatchLabels: map[string]string{"blah": "foobar"},
-                       },
-                       cache.ResourceEventHandlerFuncs{
-                               AddFunc: func(obj interface{}) {
-                                       pod := obj.(*v1.Pod)
-                                       Expect(reflect.DeepEqual(pod, passesFilter)).To(BeTrue())
-                               },
-                               UpdateFunc: func(old, new interface{}) {
-                                       newPod := new.(*v1.Pod)
-                                       Expect(reflect.DeepEqual(newPod, passesFilter)).To(BeTrue())
-                               },
-                               DeleteFunc: func(obj interface{}) {
-                                       pod := obj.(*v1.Pod)
-                                       Expect(reflect.DeepEqual(pod, passesFilter)).To(BeTrue())
-                               },
-                       })
-
-               pods = append(pods, passesFilter)
-               podWatch.Add(passesFilter)
-               Eventually(func() int { return numAdded }, 2).Should(Equal(1))
-
-               // numAdded should remain 1
-               pods = append(pods, failsFilter)
-               podWatch.Add(failsFilter)
-               Consistently(func() int { return numAdded }, 2).Should(Equal(1))
-
-               // numAdded should remain 1
-               pods = append(pods, failsFilter2)
-               podWatch.Add(failsFilter2)
-               Consistently(func() int { return numAdded }, 2).Should(Equal(1))
-
-               passesFilter.Status.Phase = v1.PodFailed
-               podWatch.Modify(passesFilter)
-               Eventually(func() int { return numUpdated }, 2).Should(Equal(1))
-
-               // numAdded should remain 1
-               failsFilter.Status.Phase = v1.PodFailed
-               podWatch.Modify(failsFilter)
-               Consistently(func() int { return numUpdated }, 2).Should(Equal(1))
-
-               failsFilter2.Status.Phase = v1.PodFailed
-               podWatch.Modify(failsFilter2)
-               Consistently(func() int { return numUpdated }, 2).Should(Equal(1))
-
-               pods = []*v1.Pod{failsFilter, failsFilter2}
-               podWatch.Delete(passesFilter)
-               Eventually(func() int { return numDeleted }, 2).Should(Equal(1))
-
-               close(stop)
-       })
-
-       It("correctly handles object updates that cause filter changes", func() {
-               wf, err := NewWatchFactory(fakeClient, stop)
-               Expect(err).NotTo(HaveOccurred())
-
-               pod := newPod("pod1", "default")
-               pod.ObjectMeta.Labels["blah"] = "baz"
-
-               equalPod := pod
-               id := addFilteredHandler(wf,
-                       podType,
-                       "default",
-                       &metav1.LabelSelector{
-                               MatchLabels: map[string]string{"blah": "foobar"},
-                       },
-                       cache.ResourceEventHandlerFuncs{
-                               AddFunc: func(obj interface{}) {
-                                       p := obj.(*v1.Pod)
-                                       Expect(reflect.DeepEqual(p, equalPod)).To(BeTrue())
-                               },
-                               UpdateFunc: func(old, new interface{}) {},
-                               DeleteFunc: func(obj interface{}) {
-                                       p := obj.(*v1.Pod)
-                                       Expect(reflect.DeepEqual(p, equalPod)).To(BeTrue())
-                               },
-                       })
-
-               pods = append(pods, pod)
-
-               // Pod doesn't pass filter; shouldn't be added
-               podWatch.Add(pod)
-               Consistently(func() int { return numAdded }, 2).Should(Equal(0))
-
-               // Update pod to pass filter; should be treated as add.  Need
-               // to deep-copy pod when modifying because it's a pointer all
-               // the way through when using FakeClient
-               podCopy := pod.DeepCopy()
-               podCopy.ObjectMeta.Labels["blah"] = "foobar"
-               pods = []*v1.Pod{podCopy}
-               equalPod = podCopy
-               podWatch.Modify(podCopy)
-               Eventually(func() int { return numAdded }, 2).Should(Equal(1))
-
-               // Update pod to fail filter; should be treated as delete
-               pod.ObjectMeta.Labels["blah"] = "baz"
-               podWatch.Modify(pod)
-               Eventually(func() int { return numDeleted }, 2).Should(Equal(1))
-               Consistently(func() int { return numAdded }, 2).Should(Equal(1))
-               Consistently(func() int { return numUpdated }, 2).Should(Equal(0))
-
-               wf.RemovePodHandler(id)
-               close(stop)
-       })
-})
index cc7c29b..e51963e 100644 (file)
@@ -41,7 +41,7 @@ type Kube struct {
 func (k *Kube) SetAnnotationOnPod(pod *kapi.Pod, key, value string) error {
        logrus.Infof("Setting annotations %s=%s on pod %s", key, value, pod.Name)
        patchData := fmt.Sprintf(`{"metadata":{"annotations":{"%s":"%s"}}}`, key, value)
-       _, err := k.KClient.Core().Pods(pod.Namespace).Patch(pod.Name, types.MergePatchType, []byte(patchData))
+       _, err := k.KClient.CoreV1().Pods(pod.Namespace).Patch(pod.Name, types.MergePatchType, []byte(patchData))
        if err != nil {
                logrus.Errorf("Error in setting annotation on pod %s/%s: %v", pod.Name, pod.Namespace, err)
        }
@@ -52,7 +52,7 @@ func (k *Kube) SetAnnotationOnPod(pod *kapi.Pod, key, value string) error {
 func (k *Kube) SetAnnotationOnNode(node *kapi.Node, key, value string) error {
        logrus.Infof("Setting annotations %s=%s on node %s", key, value, node.Name)
        patchData := fmt.Sprintf(`{"metadata":{"annotations":{"%s":"%s"}}}`, key, value)
-       _, err := k.KClient.Core().Nodes().Patch(node.Name, types.MergePatchType, []byte(patchData))
+       _, err := k.KClient.CoreV1().Nodes().Patch(node.Name, types.MergePatchType, []byte(patchData))
        if err != nil {
                logrus.Errorf("Error in setting annotation on node %s: %v", node.Name, err)
        }
@@ -67,7 +67,7 @@ func (k *Kube) SetAnnotationOnNamespace(ns *kapi.Namespace, key,
                ns.Name)
        patchData := fmt.Sprintf(`{"metadata":{"annotations":{"%s":"%s"}}}`, key,
                value)
-       _, err := k.KClient.Core().Namespaces().Patch(ns.Name,
+       _, err := k.KClient.CoreV1().Namespaces().Patch(ns.Name,
                types.MergePatchType, []byte(patchData))
        if err != nil {
                logrus.Errorf("Error in setting annotation on namespace %s: %v",
@@ -78,7 +78,7 @@ func (k *Kube) SetAnnotationOnNamespace(ns *kapi.Namespace, key,
 
 // GetAnnotationsOnPod obtains the pod annotations from kubernetes apiserver, given the name and namespace
 func (k *Kube) GetAnnotationsOnPod(namespace, name string) (map[string]string, error) {
-       pod, err := k.KClient.Core().Pods(namespace).Get(name, metav1.GetOptions{})
+       pod, err := k.KClient.CoreV1().Pods(namespace).Get(name, metav1.GetOptions{})
        if err != nil {
                return nil, err
        }
@@ -87,12 +87,12 @@ func (k *Kube) GetAnnotationsOnPod(namespace, name string) (map[string]string, e
 
 // GetPod obtains the Pod resource from kubernetes apiserver, given the name and namespace
 func (k *Kube) GetPod(namespace, name string) (*kapi.Pod, error) {
-       return k.KClient.Core().Pods(namespace).Get(name, metav1.GetOptions{})
+       return k.KClient.CoreV1().Pods(namespace).Get(name, metav1.GetOptions{})
 }
 
 // GetPods obtains the Pod resource from kubernetes apiserver, given the name and namespace
 func (k *Kube) GetPods(namespace string) (*kapi.PodList, error) {
-       return k.KClient.Core().Pods(namespace).List(metav1.ListOptions{})
+       return k.KClient.CoreV1().Pods(namespace).List(metav1.ListOptions{})
 }
 
 // GetPodsByLabels obtains the Pod resources from kubernetes apiserver,
@@ -100,42 +100,42 @@ func (k *Kube) GetPods(namespace string) (*kapi.PodList, error) {
 func (k *Kube) GetPodsByLabels(namespace string, selector labels.Selector) (*kapi.PodList, error) {
        options := metav1.ListOptions{}
        options.LabelSelector = selector.String()
-       return k.KClient.Core().Pods(namespace).List(options)
+       return k.KClient.CoreV1().Pods(namespace).List(options)
 }
 
 // GetNodes returns the list of all Node objects from kubernetes
 func (k *Kube) GetNodes() (*kapi.NodeList, error) {
-       return k.KClient.Core().Nodes().List(metav1.ListOptions{})
+       return k.KClient.CoreV1().Nodes().List(metav1.ListOptions{})
 }
 
 // GetNode returns the Node resource from kubernetes apiserver, given its name
 func (k *Kube) GetNode(name string) (*kapi.Node, error) {
-       return k.KClient.Core().Nodes().Get(name, metav1.GetOptions{})
+       return k.KClient.CoreV1().Nodes().Get(name, metav1.GetOptions{})
 }
 
 // GetService returns the Service resource from kubernetes apiserver, given its name and namespace
 func (k *Kube) GetService(namespace, name string) (*kapi.Service, error) {
-       return k.KClient.Core().Services(namespace).Get(name, metav1.GetOptions{})
+       return k.KClient.CoreV1().Services(namespace).Get(name, metav1.GetOptions{})
 }
 
 // GetEndpoints returns all the Endpoint resources from kubernetes
 // apiserver, given namespace
 func (k *Kube) GetEndpoints(namespace string) (*kapi.EndpointsList, error) {
-       return k.KClient.Core().Endpoints(namespace).List(metav1.ListOptions{})
+       return k.KClient.CoreV1().Endpoints(namespace).List(metav1.ListOptions{})
 }
 
 // GetNamespace returns the Namespace resource from kubernetes apiserver,
 // given its name
 func (k *Kube) GetNamespace(name string) (*kapi.Namespace, error) {
-       return k.KClient.Core().Namespaces().Get(name, metav1.GetOptions{})
+       return k.KClient.CoreV1().Namespaces().Get(name, metav1.GetOptions{})
 }
 
 // GetNamespaces returns all Namespace resource from kubernetes apiserver
 func (k *Kube) GetNamespaces() (*kapi.NamespaceList, error) {
-       return k.KClient.Core().Namespaces().List(metav1.ListOptions{})
+       return k.KClient.CoreV1().Namespaces().List(metav1.ListOptions{})
 }
 
 // GetNetworkPolicies returns all network policy objects from kubernetes
 func (k *Kube) GetNetworkPolicies(namespace string) (*kapisnetworking.NetworkPolicyList, error) {
-       return k.KClient.Networking().NetworkPolicies(namespace).List(metav1.ListOptions{})
+       return k.KClient.NetworkingV1().NetworkPolicies(namespace).List(metav1.ListOptions{})
 }
index b504440..60cd202 100644 (file)
@@ -3,69 +3,82 @@ package ovn
 import (
        "encoding/json"
        "fmt"
-       "github.com/sirupsen/logrus"
        "math/big"
        "math/rand"
        "net"
+       logf "sigs.k8s.io/controller-runtime/pkg/runtime/log"
+       "strings"
        "time"
 )
 
-func SetupDistributedRouter(name string) error {
+var log = logf.Log.WithName("ovn")
 
-       // Make sure br-int is created.
-       stdout, stderr, err := RunOVSVsctlUnix("--", "--may-exist", "add-br", "br-int")
-       if err != nil {
-               logrus.Errorf("Failed to create br-int, stdout: %q, stderr: %q, error: %v", stdout, stderr, err)
-               return err
+func parseOvnNetworkObject(ovnnetwork string) ([]map[string]interface{}, error) {
+       var ovnNet []map[string]interface{}
+
+       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 setupDistributedRouter(name string) error {
+
        // Create a single common distributed router for the cluster.
-       stdout, stderr, err = RunOVNNbctlUnix("--", "--may-exist", "lr-add", name, "--", "set", "logical_router", name, "external_ids:ovn4nfv-cluster-router=yes")
+       stdout, stderr, err := RunOVNNbctl("--", "--may-exist", "lr-add", name, "--", "set", "logical_router", name, "external_ids:ovn4nfv-cluster-router=yes")
        if err != nil {
-               logrus.Errorf("Failed to create a single common distributed router for the cluster, stdout: %q, stderr: %q, error: %v", stdout, stderr, err)
+               log.Error(err, "Failed to create a single common distributed router for the cluster", "stdout", stdout, "stderr", stderr)
                return err
        }
        // Create a logical switch called "ovn4nfv-join" that will be used to connect gateway routers to the distributed router.
        // The "ovn4nfv-join" will be allocated IP addresses in the range 100.64.1.0/24.
-       stdout, stderr, err = RunOVNNbctlUnix("--may-exist", "ls-add", "ovn4nfv-join")
+       stdout, stderr, err = RunOVNNbctl("--may-exist", "ls-add", "ovn4nfv-join")
        if err != nil {
-               logrus.Errorf("Failed to create logical switch called \"ovn4nfv-join\", stdout: %q, stderr: %q, error: %v", stdout, stderr, err)
+               log.Error(err, "Failed to create logical switch called \"ovn4nfv-join\"", "stdout", stdout, "stderr", stderr)
                return err
        }
        // Connect the distributed router to "ovn4nfv-join".
-       routerMac, stderr, err := RunOVNNbctlUnix("--if-exist", "get", "logical_router_port", "rtoj-"+name, "mac")
+       routerMac, stderr, err := RunOVNNbctl("--if-exist", "get", "logical_router_port", "rtoj-"+name, "mac")
        if err != nil {
-               logrus.Errorf("Failed to get logical router port rtoj-%v, stderr: %q, error: %v", name, stderr, err)
+               log.Error(err, "Failed to get logical router port rtoj-", "name", name, "stdout", stdout, "stderr", stderr)
                return err
        }
        if routerMac == "" {
                routerMac = generateMac()
-               stdout, stderr, err = RunOVNNbctlUnix("--", "--may-exist", "lrp-add", name, "rtoj-"+name, routerMac, "100.64.1.1/24", "--", "set", "logical_router_port", "rtoj-"+name, "external_ids:connect_to_ovn4nfvjoin=yes")
+               stdout, stderr, err = RunOVNNbctl("--", "--may-exist", "lrp-add", name, "rtoj-"+name, routerMac, "100.64.1.1/24", "--", "set", "logical_router_port", "rtoj-"+name, "external_ids:connect_to_ovn4nfvjoin=yes")
                if err != nil {
-                       logrus.Errorf("Failed to add logical router port rtoj-%v, stdout: %q, stderr: %q, error: %v", name, stdout, stderr, err)
+                       log.Error(err, "Failed to add logical router port rtoj", "name", name, "stdout", stdout, "stderr", stderr)
                        return err
                }
        }
        // Connect the switch "ovn4nfv-join" to the router.
-       stdout, stderr, err = RunOVNNbctlUnix("--", "--may-exist", "lsp-add", "ovn4nfv-join", "jtor-"+name, "--", "set", "logical_switch_port", "jtor-"+name, "type=router", "options:router-port=rtoj-"+name, "addresses="+"\""+routerMac+"\"")
+       stdout, stderr, err = RunOVNNbctl("--", "--may-exist", "lsp-add", "ovn4nfv-join", "jtor-"+name, "--", "set", "logical_switch_port", "jtor-"+name, "type=router", "options:router-port=rtoj-"+name, "addresses="+"\""+routerMac+"\"")
        if err != nil {
-               logrus.Errorf("Failed to add logical switch port to logical router, stdout: %q, stderr: %q, error: %v", stdout, stderr, err)
+               log.Error(err, "Failed to add logical switch port to logical router", "stdout", stdout, "stderr", stderr)
                return err
        }
        return nil
 }
 
-func parseOvnNetworkObject(ovnnetwork string) ([]map[string]interface{}, error) {
-       var ovnNet []map[string]interface{}
-
-       if ovnnetwork == "" {
-               return nil, fmt.Errorf("parseOvnNetworkObject:error")
+// Find if switch exists
+func findLogicalSwitch(name string) bool {
+       // get logical switch from OVN
+       output, stderr, err := RunOVNNbctl("--data=bare", "--no-heading",
+               "--columns=name", "find", "logical_switch", "name="+name)
+       if err != nil {
+               log.Error(err, "Error in obtaining list of logical switch", "stderr", stderr)
+               return false
        }
 
-       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)
+       if strings.Compare(name, output) == 0 {
+               return true
        }
-
-       return ovnNet, nil
+       return false
 }
 
 // generateMac generates mac address.
index 470416b..dad4641 100644 (file)
@@ -2,93 +2,174 @@ package ovn
 
 import (
        "fmt"
+       "github.com/mitchellh/mapstructure"
+       kapi "k8s.io/api/core/v1"
+       kexec "k8s.io/utils/exec"
        "strings"
        "time"
-
-       "github.com/sirupsen/logrus"
-       kapi "k8s.io/api/core/v1"
-       "k8s.io/client-go/kubernetes"
-       "k8s.io/client-go/tools/cache"
-       "ovn4nfv-k8s-plugin/internal/pkg/factory"
-       "ovn4nfv-k8s-plugin/internal/pkg/kube"
 )
 
-// Controller structure is the object which holds the controls for starting
-// and reacting upon the watched resources (e.g. pods, endpoints)
 type Controller struct {
-       kube         kube.Interface
-       watchFactory *factory.WatchFactory
-
        gatewayCache map[string]string
-       // A cache of all logical switches seen by the watcher
-       logicalSwitchCache map[string]bool
-       // A cache of all logical ports seen by the watcher and
-       // its corresponding logical switch
-       logicalPortCache map[string]string
 }
 
-// NewOvnController creates a new OVN controller for creating logical network
-// infrastructure and policy
-func NewOvnController(kubeClient kubernetes.Interface, wf *factory.WatchFactory) *Controller {
-       return &Controller{
-               kube:               &kube.Kube{KClient: kubeClient},
-               watchFactory:       wf,
-               logicalSwitchCache: make(map[string]bool),
-               logicalPortCache:   make(map[string]string),
-               gatewayCache:       make(map[string]string),
+const (
+       ovn4nfvRouterName    = "ovn4nfv-master"
+       Ovn4nfvAnnotationTag = "k8s.plugin.opnfv.org/ovnInterfaces"
+)
+
+type netInterface struct {
+       Name           string
+       Interface      string
+       NetType        string
+       DefaultGateway string
+       IPAddress      string
+       MacAddress     string
+}
+
+var ovnCtl *Controller
+
+// NewOvnController creates a new OVN controller for creating logical networks
+func NewOvnController(exec kexec.Interface) (*Controller, error) {
+
+       if exec == nil {
+               exec = kexec.New()
+       }
+
+       if err := SetExec(exec); err != nil {
+               log.Error(err, "Failed to initialize exec helper")
+               return nil, err
+       }
+
+       if err := SetupOvnUtils(); err != nil {
+               log.Error(err, "Failed to initialize OVN State")
+               return nil, err
+       }
+       ovnCtl = &Controller{
+               gatewayCache: make(map[string]string),
        }
+       return ovnCtl, nil
 }
 
-// Run starts the actual watching. Also initializes any local structures needed.
-func (oc *Controller) Run() error {
-       fmt.Println("ovn4nfvk8s watching Pods")
-       for _, f := range []func() error{oc.WatchPods} {
-               if err := f(); err != nil {
-                       return err
-               }
+// GetOvnController returns OVN controller for creating logical networks
+func GetOvnController() (*Controller, error) {
+       if ovnCtl != nil {
+               return ovnCtl, nil
        }
-       return nil
+       return nil, fmt.Errorf("OVN Controller not initialized")
 }
 
-// WatchPods starts the watching of Pod resource and calls back the appropriate handler logic
-func (oc *Controller) WatchPods() error {
-       _, err := oc.watchFactory.AddPodHandler(cache.ResourceEventHandlerFuncs{
-               AddFunc: func(obj interface{}) {
-                       pod := obj.(*kapi.Pod)
-                       if pod.Spec.NodeName != "" {
-                               oc.addLogicalPort(pod)
+// AddLogicalPorts adds ports to the Pod
+func (oc *Controller) AddLogicalPorts(pod *kapi.Pod, ovnNetObjs []map[string]interface{}) (key, value string) {
+
+       if ovnNetObjs == nil {
+               return
+       }
+
+       if pod.Spec.HostNetwork {
+               return
+       }
+
+       if _, ok := pod.Annotations[Ovn4nfvAnnotationTag]; ok {
+               log.Info("AddLogicalPorts : Pod annotation found")
+               return
+       }
+
+       var ovnString, outStr string
+       ovnString = "["
+       var ns netInterface
+       for _, net := range ovnNetObjs {
+
+               err := mapstructure.Decode(net, &ns)
+               if err != nil {
+                       log.Error(err, "mapstruct error", "network", net)
+                       return
+               }
+
+               if !findLogicalSwitch(ns.Name) {
+                       log.Info("Logical Switch not found")
+                       return
+               }
+               if ns.Interface == "" {
+                       log.Info("Interface name must be provided")
+                       return
+               }
+               if ns.DefaultGateway == "" {
+                       ns.DefaultGateway = "false"
+               }
+               if ns.NetType == "" || ns.NetType != "provider" {
+                       ns.NetType = "virtual"
+               }
+               if ns.NetType == "provider" {
+                       if ns.IPAddress == "" {
+                               log.Info("ipAddress must be provided for netType Provider")
+                               return
                        }
-               },
-               UpdateFunc: func(old, newer interface{}) {
-                       podNew := newer.(*kapi.Pod)
-                       podOld := old.(*kapi.Pod)
-                       if podOld.Spec.NodeName == "" && podNew.Spec.NodeName != "" {
-                               oc.addLogicalPort(podNew)
+                       if ns.DefaultGateway == "true" {
+                               log.Info("defaultGateway not supported for provider network - Use ovnNetworkRoutes to add routes")
+                               return
                        }
-               },
-               DeleteFunc: func(obj interface{}) {
-                       pod := obj.(*kapi.Pod)
-                       oc.deleteLogicalPort(pod)
-               },
-       }, oc.syncPods)
-       return err
+
+               }
+
+               outStr = oc.addLogicalPortWithSwitch(pod, ns.Name, ns.IPAddress, ns.MacAddress, ns.Interface, ns.NetType)
+               if outStr == "" {
+                       return
+               }
+               last := len(outStr) - 1
+               tmpString := outStr[:last]
+               tmpString += "," + "\\\"defaultGateway\\\":" + "\\\"" + ns.DefaultGateway + "\\\""
+               tmpString += "," + "\\\"interface\\\":" + "\\\"" + ns.Interface + "\\\"}"
+               ovnString += tmpString
+               ovnString += ","
+       }
+       last := len(ovnString) - 1
+       ovnString = ovnString[:last]
+       ovnString += "]"
+       key = Ovn4nfvAnnotationTag
+       value = ovnString
+       return key, value
 }
 
-func (oc *Controller) syncPods(pods []interface{}) {
+func (oc *Controller) DeleteLogicalPorts(name, namespace string) {
+
+       log.Info("Deleting pod", "name", name)
+       logicalPort := fmt.Sprintf("%s_%s", namespace, name)
+
+       // get the list of logical ports from OVN
+       stdout, stderr, err := RunOVNNbctl("--data=bare", "--no-heading",
+               "--columns=name", "find", "logical_switch_port", "external_ids:pod=true")
+       if err != nil {
+               log.Error(err, "Error in obtaining list of logical ports ", "stdout", stdout, "stderr", stderr)
+               return
+       }
+       log.Info("Deleting", "Existing Ports", stdout)
+       existingLogicalPorts := strings.Fields(stdout)
+       for _, existingPort := range existingLogicalPorts {
+               if strings.Contains(existingPort, logicalPort) {
+                       // found, delete this logical port
+                       log.Info("Deleting", "existingPort", existingPort)
+                       stdout, stderr, err := RunOVNNbctl("--if-exists", "lsp-del",
+                               existingPort)
+                       if err != nil {
+                               log.Error(err, "Error in deleting pod's logical port ", "stdout", stdout, "stderr", stderr)
+                       }
+               }
+       }
+       return
 }
 
 func (oc *Controller) getGatewayFromSwitch(logicalSwitch string) (string, string, error) {
        var gatewayIPMaskStr, stderr string
        var ok bool
        var err error
-       logrus.Infof("getGatewayFromSwitch: %s", logicalSwitch)
+       log.Info("getGatewayFromSwitch", "logicalSwitch", logicalSwitch)
        if gatewayIPMaskStr, ok = oc.gatewayCache[logicalSwitch]; !ok {
-               gatewayIPMaskStr, stderr, err = RunOVNNbctlUnix("--if-exists",
+               gatewayIPMaskStr, stderr, err = RunOVNNbctl("--if-exists",
                        "get", "logical_switch", logicalSwitch,
                        "external_ids:gateway_ip")
                if err != nil {
-                       logrus.Errorf("Failed to get gateway IP:  %s, stderr: %q, %v",
-                               gatewayIPMaskStr, stderr, err)
+                       log.Error(err, "Failed to get gateway IP", "stderr", stderr, "gatewayIPMaskStr", gatewayIPMaskStr)
                        return "", "", err
                }
                if gatewayIPMaskStr == "" {
@@ -107,44 +188,6 @@ func (oc *Controller) getGatewayFromSwitch(logicalSwitch string) (string, string
        return gatewayIP, mask, nil
 }
 
-func (oc *Controller) deleteLogicalPort(pod *kapi.Pod) {
-
-       if pod.Spec.HostNetwork {
-               return
-       }
-
-       logrus.Infof("Deleting pod: %s", pod.Name)
-       logicalPort := fmt.Sprintf("%s_%s", pod.Namespace, pod.Name)
-
-       // get the list of logical ports from OVN
-       output, stderr, err := RunOVNNbctlUnix("--data=bare", "--no-heading",
-               "--columns=name", "find", "logical_switch_port", "external_ids:pod=true")
-       if err != nil {
-               logrus.Errorf("Error in obtaining list of logical ports, "+
-                       "stderr: %q, err: %v",
-                       stderr, err)
-               return
-       }
-       logrus.Infof("Exising Ports : %s. ", output)
-       existingLogicalPorts := strings.Fields(output)
-       for _, existingPort := range existingLogicalPorts {
-               if strings.Contains(existingPort, logicalPort) {
-                       // found, delete this logical port
-                       logrus.Infof("Deleting: %s. ", existingPort)
-                       out, stderr, err := RunOVNNbctlUnix("--if-exists", "lsp-del",
-                               existingPort)
-                       if err != nil {
-                               logrus.Errorf("Error in deleting pod's logical port "+
-                                       "stdout: %q, stderr: %q err: %v",
-                                       out, stderr, err)
-                       } else {
-                               delete(oc.logicalPortCache, existingPort)
-                       }
-               }
-       }
-       return
-}
-
 func (oc *Controller) addLogicalPortWithSwitch(pod *kapi.Pod, logicalSwitch, ipAddress, macAddress, interfaceName, netType string) (annotation string) {
        var out, stderr string
        var err error
@@ -153,9 +196,6 @@ func (oc *Controller) addLogicalPortWithSwitch(pod *kapi.Pod, logicalSwitch, ipA
                return
        }
 
-       if !oc.logicalSwitchCache[logicalSwitch] {
-               oc.logicalSwitchCache[logicalSwitch] = true
-       }
        var portName string
        if interfaceName != "" {
                portName = fmt.Sprintf("%s_%s_%s", pod.Namespace, pod.Name, interfaceName)
@@ -163,7 +203,7 @@ func (oc *Controller) addLogicalPortWithSwitch(pod *kapi.Pod, logicalSwitch, ipA
                return
        }
 
-       logrus.Infof("Creating logical port for %s on switch %s", portName, logicalSwitch)
+       log.Info("Creating logical port for on switch", "portName", portName, "logicalSwitch", logicalSwitch)
 
        if ipAddress != "" && macAddress != "" {
                isStaticIP = true
@@ -174,7 +214,7 @@ func (oc *Controller) addLogicalPortWithSwitch(pod *kapi.Pod, logicalSwitch, ipA
        }
 
        if isStaticIP {
-               out, stderr, err = RunOVNNbctlUnix("--may-exist", "lsp-add",
+               out, stderr, err = RunOVNNbctl("--may-exist", "lsp-add",
                        logicalSwitch, portName, "--", "lsp-set-addresses", portName,
                        fmt.Sprintf("%s %s", macAddress, ipAddress), "--", "--if-exists",
                        "clear", "logical_switch_port", portName, "dynamic_addresses", "--", "set",
@@ -183,13 +223,11 @@ func (oc *Controller) addLogicalPortWithSwitch(pod *kapi.Pod, logicalSwitch, ipA
                        "external-ids:logical_switch="+logicalSwitch,
                        "external-ids:pod=true")
                if err != nil {
-                       logrus.Errorf("Failed to add logical port to switch "+
-                               "stdout: %q, stderr: %q (%v)",
-                               out, stderr, err)
+                       log.Error(err, "Failed to add logical port to switch", "out", out, "stderr", stderr)
                        return
                }
        } else {
-               out, stderr, err = RunOVNNbctlUnix("--wait=sb", "--",
+               out, stderr, err = RunOVNNbctl("--wait=sb", "--",
                        "--may-exist", "lsp-add", logicalSwitch, portName,
                        "--", "lsp-set-addresses",
                        portName, "dynamic", "--", "set",
@@ -198,37 +236,32 @@ func (oc *Controller) addLogicalPortWithSwitch(pod *kapi.Pod, logicalSwitch, ipA
                        "external-ids:logical_switch="+logicalSwitch,
                        "external-ids:pod=true")
                if err != nil {
-                       logrus.Errorf("Error while creating logical port %s "+
-                               "stdout: %q, stderr: %q (%v)",
-                               portName, out, stderr, err)
+                       log.Error(err, "Error while creating logical port %s ", "portName", portName, "stdout", out, "stderr", stderr)
                        return
                }
        }
-       oc.logicalPortCache[portName] = logicalSwitch
 
        count := 30
        for count > 0 {
                if isStaticIP {
-                       out, stderr, err = RunOVNNbctlUnix("get",
+                       out, stderr, err = RunOVNNbctl("get",
                                "logical_switch_port", portName, "addresses")
                } else {
-                       out, stderr, err = RunOVNNbctlUnix("get",
+                       out, stderr, err = RunOVNNbctl("get",
                                "logical_switch_port", portName, "dynamic_addresses")
                }
                if err == nil && out != "[]" {
                        break
                }
                if err != nil {
-                       logrus.Errorf("Error while obtaining addresses for %s - %v", portName,
-                               err)
+                       log.Error(err, "Error while obtaining addresses for", "portName", portName)
                        return
                }
                time.Sleep(time.Second)
                count--
        }
        if count == 0 {
-               logrus.Errorf("Error while obtaining addresses for %s "+
-                       "stdout: %q, stderr: %q, (%v)", portName, out, stderr, err)
+               log.Error(err, "Error while obtaining addresses for", "portName", portName, "stdout", out, "stderr", stderr)
                return
        }
 
@@ -239,14 +272,14 @@ func (oc *Controller) addLogicalPortWithSwitch(pod *kapi.Pod, logicalSwitch, ipA
        outStr = strings.Trim(outStr, `"`)
        addresses := strings.Split(outStr, " ")
        if len(addresses) != 2 {
-               logrus.Errorf("Error while obtaining addresses for %s", portName)
+               log.Info("Error while obtaining addresses for", "portName", portName)
                return
        }
 
        if netType == "virtual" {
                gatewayIP, mask, err := oc.getGatewayFromSwitch(logicalSwitch)
                if err != nil {
-                       logrus.Errorf("Error obtaining gateway address for switch %s: %s", logicalSwitch, err)
+                       log.Error(err, "Error obtaining gateway address for switch", "logicalSwitch", logicalSwitch)
                        return
                }
                annotation = fmt.Sprintf(`{\"ip_address\":\"%s/%s\", \"mac_address\":\"%s\", \"gateway_ip\": \"%s\"}`, addresses[1], mask, addresses[0], gatewayIP)
@@ -256,102 +289,3 @@ func (oc *Controller) addLogicalPortWithSwitch(pod *kapi.Pod, logicalSwitch, ipA
 
        return annotation
 }
-
-func (oc *Controller) findLogicalSwitch(name string) bool {
-       // get logical switch from OVN
-       output, stderr, err := RunOVNNbctlUnix("--data=bare", "--no-heading",
-               "--columns=name", "find", "logical_switch", "name="+name)
-       if err != nil {
-               logrus.Errorf("Error in obtaining list of logical switch, "+
-                       "stderr: %q, err: %v",
-                       stderr, err)
-               return false
-       }
-
-       if strings.Compare(name, output) == 0 {
-               return true
-       } else {
-               logrus.Errorf("Error finding Switch %v", name)
-               return false
-       }
-}
-
-func (oc *Controller) addLogicalPort(pod *kapi.Pod) {
-       var logicalSwitch string
-       var ipAddress, macAddress, interfaceName, defaultGateway, netType string
-
-       annotation := pod.Annotations["ovnNetwork"]
-
-       if annotation != "" {
-               ovnNetObjs, err := parseOvnNetworkObject(annotation)
-               if err != nil {
-                       logrus.Errorf("addLogicalPort : Error Parsing OvnNetwork List")
-                       return
-               }
-               var ovnString, outStr string
-               ovnString = "["
-               for _, net := range ovnNetObjs {
-                       logicalSwitch = net["name"].(string)
-                       if !oc.findLogicalSwitch(logicalSwitch) {
-                               logrus.Errorf("Logical Switch not found")
-                               return
-                       }
-                       if _, ok := net["interface"]; ok {
-                               interfaceName = net["interface"].(string)
-                       } else {
-                               logrus.Errorf("Interface name must be provided")
-                               return
-                       }
-                       if _, ok := net["ipAddress"]; ok {
-                               ipAddress = net["ipAddress"].(string)
-                       } else {
-                               ipAddress = ""
-                       }
-                       if _, ok := net["macAddress"]; ok {
-                               macAddress = net["macAddress"].(string)
-                       } else {
-                               macAddress = ""
-                       }
-                       if _, ok := net["defaultGateway"]; ok {
-                               defaultGateway = net["defaultGateway"].(string)
-                       } else {
-                               defaultGateway = "false"
-                       }
-                       if _, ok := net["netType"]; ok {
-                               netType = net["netType"].(string)
-                       } else {
-                               netType = "virtual"
-                       }
-                       if netType != "provider" && netType != "virtual" {
-                               logrus.Errorf("netType is not supported")
-                               return
-                       }
-                       if netType == "provider" && ipAddress == "" {
-                               logrus.Errorf("ipAddress must be provided for netType Provider")
-                               return
-                       }
-                       if netType == "provider" && defaultGateway == "true" {
-                               logrus.Errorf("defaultGateway not supported for provider network - Use ovnNetworkRoutes to add routes")
-                               return
-                       }
-                       outStr = oc.addLogicalPortWithSwitch(pod, logicalSwitch, ipAddress, macAddress, interfaceName, netType)
-                       if outStr == "" {
-                               return
-                       }
-                       last := len(outStr) - 1
-                       tmpString := outStr[:last]
-                       tmpString += "," + "\\\"defaultGateway\\\":" + "\\\"" + defaultGateway + "\\\""
-                       tmpString += "," + "\\\"interface\\\":" + "\\\"" + interfaceName + "\\\"}"
-                       ovnString += tmpString
-                       ovnString += ","
-               }
-               last := len(ovnString) - 1
-               ovnString = ovnString[:last]
-               ovnString += "]"
-               logrus.Debugf("ovnIfaceList - %v", ovnString)
-               err = oc.kube.SetAnnotationOnPod(pod, "ovnIfaceList", ovnString)
-               if err != nil {
-                       logrus.Errorf("Failed to set annotation on pod %s - %v", pod.Name, err)
-               }
-       }
-}
index bc33d35..6e38759 100644 (file)
@@ -9,9 +9,7 @@ import (
 
        "k8s.io/api/core/v1"
        metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-       "k8s.io/client-go/kubernetes/fake"
        "ovn4nfv-k8s-plugin/internal/pkg/config"
-       "ovn4nfv-k8s-plugin/internal/pkg/factory"
        ovntest "ovn4nfv-k8s-plugin/internal/pkg/testing"
 
        . "github.com/onsi/ginkgo"
@@ -30,10 +28,10 @@ var _ = Describe("Add logical Port", func() {
        var app *cli.App
 
        BeforeEach(func() {
-
                app = cli.NewApp()
                app.Name = "test"
                app.Flags = config.Flags
+
        })
 
        It("tests Pod", func() {
@@ -68,15 +66,15 @@ var _ = Describe("Add logical Port", func() {
                                        return fmt.Sprintf("/fake-bin/%s", file), nil
                                },
                        }
-
-                       err := SetExec(fexec)
+                       oldSetupOvnUtils := SetupOvnUtils
+                       // as we are exiting, revert ConfigureInterface back  at end of function
+                       defer func() { SetupOvnUtils = oldSetupOvnUtils }()
+                       SetupOvnUtils = func() error {
+                               return nil
+                       }
+                       ovnController, err := NewOvnController(fexec)
                        Expect(err).NotTo(HaveOccurred())
 
-                       fakeClient := &fake.Clientset{}
-                       var fakeWatchFactory factory.WatchFactory
-
-                       ovnController := NewOvnController(fakeClient, &fakeWatchFactory)
-                       Expect(err).NotTo(HaveOccurred())
                        var (
                                okPod = v1.Pod{
                                        TypeMeta: metav1.TypeMeta{
@@ -84,8 +82,7 @@ var _ = Describe("Add logical Port", func() {
                                                APIVersion: "v1",
                                        },
                                        ObjectMeta: metav1.ObjectMeta{
-                                               Name:        "ok",
-                                               Annotations: map[string]string{"ovnNetwork": "[{ \"name\": \"ovn-prot-net\", \"interface\": \"net0\" , \"defaultGateway\": \"true\"}]"},
+                                               Name: "ok",
                                        },
                                        Spec: v1.PodSpec{
                                                Containers: []v1.Container{
@@ -97,8 +94,8 @@ var _ = Describe("Add logical Port", func() {
                                        },
                                }
                        )
-
-                       ovnController.addLogicalPort(&okPod)
+                       a := []map[string]interface{}{{"name": "ovn-prot-net", "interface": "net0"}}
+                       ovnController.AddLogicalPorts(&okPod, a)
                        Expect(fexec.CommandCalls).To(Equal(len(fakeCmds)))
 
                        return nil
@@ -137,13 +134,14 @@ var _ = Describe("Add logical Port", func() {
                                        return fmt.Sprintf("/fake-bin/%s", file), nil
                                },
                        }
-                       err := SetExec(fexec)
+                       oldSetupOvnUtils := SetupOvnUtils
+                       // as we are exiting, revert ConfigureInterface back  at end of function
+                       defer func() { SetupOvnUtils = oldSetupOvnUtils }()
+                       SetupOvnUtils = func() error {
+                               return nil
+                       }
+                       ovnController, err := NewOvnController(fexec)
                        Expect(err).NotTo(HaveOccurred())
-
-                       fakeClient := &fake.Clientset{}
-                       var fakeWatchFactory factory.WatchFactory
-
-                       ovnController := NewOvnController(fakeClient, &fakeWatchFactory)
                        var (
                                okPod = v1.Pod{
                                        TypeMeta: metav1.TypeMeta{
@@ -151,8 +149,7 @@ var _ = Describe("Add logical Port", func() {
                                                APIVersion: "v1",
                                        },
                                        ObjectMeta: metav1.ObjectMeta{
-                                               Name:        "ok",
-                                               Annotations: map[string]string{"ovnNetwork": "[{ \"name\": \"ovn-prot-net\", \"interface\": \"net0\", \"netType\": \"provider\", \"ipAddress\": \"192.168.1.3/24\", \"macAddress\": \"0a:00:00:00:00:01\" }]"},
+                                               Name: "ok",
                                        },
                                        Spec: v1.PodSpec{
                                                Containers: []v1.Container{
@@ -164,7 +161,8 @@ var _ = Describe("Add logical Port", func() {
                                        },
                                }
                        )
-                       ovnController.addLogicalPort(&okPod)
+                       a := []map[string]interface{}{{"name": "ovn-prot-net", "interface": "net0", "netType": "provider", "ipAddress": "192.168.1.3/24", "macAddress": "0a:00:00:00:00:01"}}
+                       ovnController.AddLogicalPorts(&okPod, a)
                        Expect(fexec.CommandCalls).To(Equal(len(fakeCmds)))
 
                        return nil
index 1700bf8..2478ac2 100644 (file)
@@ -3,55 +3,53 @@ package ovn
 import (
        "bytes"
        "fmt"
+       kexec "k8s.io/utils/exec"
+       "os"
        "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
+       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.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
 }
 
@@ -65,7 +63,6 @@ func runOVNretry(cmdPath string, args ...string) (*bytes.Buffer, *bytes.Buffer,
                if err == nil {
                        return stdout, stderr, err
                }
-
                // Connection refused
                // Master may not be up so keep trying
                if strings.Contains(stderr.String(), "Connection refused") {
@@ -87,34 +84,29 @@ func run(cmdPath string, args ...string) (*bytes.Buffer, *bytes.Buffer, error) {
        cmd := runner.exec.Command(cmdPath, args...)
        cmd.SetStdout(stdout)
        cmd.SetStderr(stderr)
-       logrus.Debugf("exec: %s %s", cmdPath, strings.Join(args, " "))
+       log.Info("exec:", "cmdPath", cmdPath, "args", strings.Join(args, " "))
        err := cmd.Run()
        if err != nil {
-               logrus.Debugf("exec: %s %s => %v", cmdPath, strings.Join(args, " "), err)
+               log.Error(err, "exec:", "cmdPath", cmdPath, "args", strings.Join(args, " "))
        }
        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)}
+// 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.TrimFunc(stdout.String(), unicode.IsSpace), "\""),
-               stderr.String(), err
+       return strings.Trim(strings.TrimSpace(stdout.String()), "\""), 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
+// RunOVNNbctl runs a command via ovn-nbctl.
+func RunOVNNbctl(args ...string) (string, string, error) {
+       return RunOVNNbctlWithTimeout(ovsCommandTimeout, args...)
 }
diff --git a/pkg/controller/add_pod.go b/pkg/controller/add_pod.go
new file mode 100644 (file)
index 0000000..cc5f562
--- /dev/null
@@ -0,0 +1,10 @@
+package controller
+
+import (
+       "ovn4nfv-k8s-plugin/pkg/controller/pod"
+)
+
+func init() {
+       // AddToManagerFuncs is a list of functions to create controllers and add them to a manager.
+       AddToManagerFuncs = append(AddToManagerFuncs, pod.Add)
+}
diff --git a/pkg/controller/controller.go b/pkg/controller/controller.go
new file mode 100644 (file)
index 0000000..7c069f3
--- /dev/null
@@ -0,0 +1,18 @@
+package controller
+
+import (
+       "sigs.k8s.io/controller-runtime/pkg/manager"
+)
+
+// AddToManagerFuncs is a list of functions to add all Controllers to the Manager
+var AddToManagerFuncs []func(manager.Manager) error
+
+// AddToManager adds all Controllers to the Manager
+func AddToManager(m manager.Manager) error {
+       for _, f := range AddToManagerFuncs {
+               if err := f(m); err != nil {
+                       return err
+               }
+       }
+       return nil
+}
diff --git a/pkg/controller/pod/pod_controller.go b/pkg/controller/pod/pod_controller.go
new file mode 100644 (file)
index 0000000..8792985
--- /dev/null
@@ -0,0 +1,205 @@
+package pod
+
+import (
+       "context"
+       "encoding/json"
+       "fmt"
+       corev1 "k8s.io/api/core/v1"
+       "k8s.io/apimachinery/pkg/api/errors"
+       "k8s.io/apimachinery/pkg/runtime"
+       "k8s.io/apimachinery/pkg/types"
+       "ovn4nfv-k8s-plugin/internal/pkg/ovn"
+       "sigs.k8s.io/controller-runtime/pkg/client"
+       "sigs.k8s.io/controller-runtime/pkg/controller"
+       "sigs.k8s.io/controller-runtime/pkg/event"
+       "sigs.k8s.io/controller-runtime/pkg/handler"
+       "sigs.k8s.io/controller-runtime/pkg/manager"
+       "sigs.k8s.io/controller-runtime/pkg/predicate"
+       "sigs.k8s.io/controller-runtime/pkg/reconcile"
+       logf "sigs.k8s.io/controller-runtime/pkg/runtime/log"
+       "sigs.k8s.io/controller-runtime/pkg/source"
+)
+
+var log = logf.Log.WithName("controller_pod")
+
+const (
+       nfnNetworkAnnotation = "k8s.plugin.opnfv.org/nfn-network"
+)
+
+type nfnNetwork struct {
+       Type      string                   "json:\"type\""
+       Interface []map[string]interface{} "json:\"interface\""
+}
+
+// Add creates a new Pod Controller and adds it to the Manager. The Manager will set fields on the Controller
+// and Start it when the Manager is Started.
+func Add(mgr manager.Manager) error {
+       return add(mgr, newReconciler(mgr))
+}
+
+// newReconciler returns a new reconcile.Reconciler
+func newReconciler(mgr manager.Manager) reconcile.Reconciler {
+       return &ReconcilePod{client: mgr.GetClient(), scheme: mgr.GetScheme()}
+}
+
+// add adds a new Controller to mgr with r as the reconcile.Reconciler
+func add(mgr manager.Manager, r reconcile.Reconciler) error {
+
+       // Create a new Controller that will call the provided Reconciler function in response
+       // to events.
+       c, err := controller.New("pod-controller", mgr, controller.Options{Reconciler: r})
+       if err != nil {
+               return err
+       }
+       // Define Predicates On Create and Update function
+       p := predicate.Funcs{
+               UpdateFunc: func(e event.UpdateEvent) bool {
+                       annotaion := e.MetaNew.GetAnnotations()
+                       // The object doesn't contain annotation ,nfnNetworkAnnotation so the event will be
+                       // ignored.
+                       if _, ok := annotaion[nfnNetworkAnnotation]; !ok {
+                               return false
+                       }
+                       // If pod is already processed by OVN don't add event
+                       if _, ok := annotaion[ovn.Ovn4nfvAnnotationTag]; ok {
+                               return false
+                       }
+                       return true
+               },
+               CreateFunc: func(e event.CreateEvent) bool {
+                       // The object doesn't contain annotation ,nfnNetworkAnnotation so the event will be
+                       // ignored.
+                       annotaion := e.Meta.GetAnnotations()
+                       if _, ok := annotaion[nfnNetworkAnnotation]; !ok {
+                               return false
+                       }
+                       return true
+               },
+               DeleteFunc: func(e event.DeleteEvent) bool {
+                       // The object doesn't contain annotation ,nfnNetworkAnnotation so the event will be
+                       // ignored.
+                       annotaion := e.Meta.GetAnnotations()
+                       if _, ok := annotaion[nfnNetworkAnnotation]; !ok {
+                               return false
+                       }
+                       return true
+               },
+       }
+
+       // Watch for Pod create / update / delete events and call Reconcile
+       err = c.Watch(&source.Kind{Type: &corev1.Pod{}}, &handler.EnqueueRequestForObject{}, p)
+       if err != nil {
+               return err
+       }
+       return nil
+}
+
+// blank assignment to verify that ReconcuilePod implements reconcile.Reconciler
+var _ reconcile.Reconciler = &ReconcilePod{}
+
+// ReconcilePod reconciles a ProviderNetwork object
+type ReconcilePod struct {
+       // This client, initialized using mgr.Client() above, is a split client
+       // that reads objects from the cache and writes to the apiserver
+       client client.Client
+       scheme *runtime.Scheme
+}
+
+// Reconcile function
+// The Controller will requeue the Request to be processed again if the returned error is non-nil or
+// Result.Requeue is true, otherwise upon completion it will remove the work from the queue.
+func (r *ReconcilePod) Reconcile(request reconcile.Request) (reconcile.Result, error) {
+       reqLogger := log.WithValues("Request.Namespace", request.Namespace, "Request.Name", request.Name)
+       reqLogger.Info("Enter Reconciling Pod")
+
+       // Fetch the Pod instance
+       instance := &corev1.Pod{}
+       err := r.client.Get(context.TODO(), request.NamespacedName, instance)
+
+       if err != nil {
+               if errors.IsNotFound(err) {
+                       // Request object not found, could have been deleted after reconcile request.
+                       // Owned objects are automatically garbage collected. For additional cleanup logic use finalizers.
+                       // Return and don't requeue
+                       if instance.Name == "" || instance.Namespace == "" {
+                               return reconcile.Result{}, nil
+                       }
+                       r.deleteLogicalPorts(request.Name, request.Namespace)
+                       return reconcile.Result{}, nil
+               }
+               // Error reading the object - requeue the request.
+               return reconcile.Result{}, err
+       }
+       if instance.Name == "" || instance.Namespace == "" {
+               return reconcile.Result{}, nil
+       }
+       err = r.addLogicalPorts(instance)
+       if err != nil && err.Error() == "Failed to add ports" {
+               // Requeue the object
+               return reconcile.Result{}, err
+       }
+       reqLogger.Info("Exit Reconciling Pod")
+       return reconcile.Result{}, nil
+}
+
+// annotatePod annotates pod with the given annotations
+func (r *ReconcilePod) setPodAnnotation(pod *corev1.Pod, key, value string) error {
+
+       patchData := fmt.Sprintf(`{"metadata":{"annotations":{"%s":"%s"}}}`, key, value)
+       err := r.client.Patch(context.TODO(), pod, client.ConstantPatch(types.MergePatchType, []byte(patchData)))
+       if err != nil {
+               log.Error(err, "Updating pod failed", "pod", pod, "key", key, "value", value)
+               return err
+       }
+       return nil
+}
+
+func (r *ReconcilePod) addLogicalPorts(pod *corev1.Pod) error {
+
+       nfn, err := r.readPodAnnotation(pod)
+       if err != nil {
+               return err
+       }
+
+       switch {
+       case nfn.Type == "ovn4nfv":
+               ovnCtl, err := ovn.GetOvnController()
+               if err != nil {
+                       return err
+               }
+               key, value := ovnCtl.AddLogicalPorts(pod, nfn.Interface)
+               if len(key) > 0 {
+                       return r.setPodAnnotation(pod, key, value)
+               }
+               return fmt.Errorf("Failed to add ports")
+       default:
+               return fmt.Errorf("Unsupported Networking type %s", nfn.Type)
+       // Add other types here
+       }
+}
+
+func (r *ReconcilePod) deleteLogicalPorts(name, namesapce string) error {
+
+       // Run delete for all controllers; pod annonations inaccessible
+       ovnCtl, err := ovn.GetOvnController()
+       if err != nil {
+               return err
+       }
+       ovnCtl.DeleteLogicalPorts(name, namesapce)
+       return nil
+       // Add other types here
+}
+
+func (r *ReconcilePod) readPodAnnotation(pod *corev1.Pod) (*nfnNetwork, error) {
+       annotaion, ok := pod.Annotations[nfnNetworkAnnotation]
+       if !ok {
+               return nil, fmt.Errorf("Invalid annotations")
+       }
+       var nfn nfnNetwork
+       err := json.Unmarshal([]byte(annotaion), &nfn)
+       if err != nil {
+               log.Error(err, "Invalid nfn annotaion", "annotaiton", annotaion)
+               return nil, err
+       }
+       return &nfn, nil
+}