diff --git a/cns/NetworkContainerContract.go b/cns/NetworkContainerContract.go index 6b5f396c2e..a724eaf5bc 100644 --- a/cns/NetworkContainerContract.go +++ b/cns/NetworkContainerContract.go @@ -2,13 +2,14 @@ package cns import ( "encoding/json" - "errors" "fmt" "net" "strconv" "strings" "github.com/Azure/azure-container-networking/cns/types" + "github.com/pkg/errors" + corev1 "k8s.io/api/core/v1" ) // Container Network Service DNC Contract @@ -254,6 +255,19 @@ func NewPodInfoFromIPConfigRequest(req IPConfigRequest) (PodInfo, error) { return p, nil } +func KubePodsToPodInfoByIP(pods []corev1.Pod) (map[string]PodInfo, error) { + podInfoByIP := map[string]PodInfo{} + for i := range pods { + if !pods[i].Spec.HostNetwork { + if _, ok := podInfoByIP[pods[i].Status.PodIP]; ok { + return nil, errors.Wrap(ErrDuplicateIP, pods[i].Status.PodIP) + } + podInfoByIP[pods[i].Status.PodIP] = NewPodInfo("", "", pods[i].Name, pods[i].Namespace) + } + } + return podInfoByIP, nil +} + // MultiTenancyInfo contains encap type and id. type MultiTenancyInfo struct { EncapType string diff --git a/cns/service/main.go b/cns/service/main.go index 521580b708..f997f13904 100644 --- a/cns/service/main.go +++ b/cns/service/main.go @@ -572,12 +572,7 @@ func main() { cns.GlobalPodInfoScheme = cns.InterfaceIDPodInfoScheme } } - if cnsconfig.InitializeFromCNI { - logger.Printf("Initializing from CNI") - } else { - logger.Printf("Initializing from Kubernetes") - } - logger.Printf("Set GlobalPodInfoScheme %v", cns.GlobalPodInfoScheme) + logger.Printf("Set GlobalPodInfoScheme %v (InitializeFromCNI=%t)", cns.GlobalPodInfoScheme, cnsconfig.InitializeFromCNI) err = InitializeCRDState(rootCtx, httpRestService, cnsconfig) if err != nil { @@ -826,7 +821,7 @@ type ncStateReconciler interface { // TODO(rbtr) where should this live?? // InitCNS initializes cns by passing pods and a createnetworkcontainerrequest -func initCNS(ctx context.Context, cli nodeNetworkConfigGetter, ncReconciler ncStateReconciler) error { +func initCNS(ctx context.Context, cli nodeNetworkConfigGetter, ncReconciler ncStateReconciler, podInfoByIPProvider cns.PodInfoByIPProvider) error { // Get nnc using direct client nnc, err := cli.Get(ctx) if err != nil { @@ -856,13 +851,7 @@ func initCNS(ctx context.Context, cli nodeNetworkConfigGetter, ncReconciler ncSt if err != nil { return errors.Wrap(err, "failed to convert NNC status to network container request") } - - // rebuild CNS state from CNI - logger.Printf("initializing CNS from CNI") - podInfoByIPProvider, err := cnireconciler.NewCNIPodInfoProvider() - if err != nil { - return errors.Wrap(err, "failed to create CNI PodInfoProvider") - } + // rebuild CNS state podInfoByIP, err := podInfoByIPProvider.PodInfoByIP() if err != nil { return errors.Wrap(err, "provider failed to provide PodInfoByIP") @@ -921,11 +910,40 @@ func InitializeCRDState(ctx context.Context, httpRestService cns.HTTPService, cn } }() + clientset, err := kubernetes.NewForConfig(kubeConfig) + if err != nil { + return errors.Wrap(err, "failed to build clientset") + } + + var podInfoByIPProvider cns.PodInfoByIPProvider + if cnsconfig.InitializeFromCNI { + logger.Printf("Initializing from CNI") + podInfoByIPProvider, err = cnireconciler.NewCNIPodInfoProvider() + if err != nil { + return errors.Wrap(err, "failed to create CNI PodInfoProvider") + } + } else { + logger.Printf("Initializing from Kubernetes") + podInfoByIPProvider = cns.PodInfoByIPProviderFunc(func() (map[string]cns.PodInfo, error) { + pods, err := clientset.CoreV1().Pods("").List(ctx, metav1.ListOptions{ //nolint:govet // ignore err shadow + FieldSelector: "spec.nodeName=" + nodeName, + }) + if err != nil { + return nil, errors.Wrap(err, "failed to list Pods for PodInfoProvider") + } + podInfo, err := cns.KubePodsToPodInfoByIP(pods.Items) + if err != nil { + return nil, errors.Wrap(err, "failed to convert Pods to PodInfoByIP") + } + return podInfo, nil + }) + } + // apiserver nnc might not be registered or api server might be down and crashloop backof puts us outside of 5-10 minutes we have for // aks addons to come up so retry a bit more aggresively here. // will retry 10 times maxing out at a minute taking about 8 minutes before it gives up. err = retry.Do(func() error { - err = initCNS(ctx, scopedcli, httpRestServiceImplementation) + err = initCNS(ctx, scopedcli, httpRestServiceImplementation, podInfoByIPProvider) if err != nil { logger.Errorf("[Azure CNS] Failed to init cns with err: %v", err) } @@ -957,11 +975,6 @@ func InitializeCRDState(ctx context.Context, httpRestService cns.HTTPService, cn return errors.Wrap(err, "failed to create manager") } - clientset, err := kubernetes.NewForConfig(kubeConfig) - if err != nil { - return errors.Wrap(err, "failed to build clientset") - } - // get our Node so that we can xref it against the NodeNetworkConfig's to make sure that the // NNC is not stale and represents the Node we're running on. node, err := clientset.CoreV1().Nodes().Get(ctx, nodeName, metav1.GetOptions{})