in cni/network/network.go [1236:1431]
func (plugin *NetPlugin) Update(args *cniSkel.CmdArgs) error {
var (
result *cniTypesCurr.Result
err error
nwCfg *cni.NetworkConfig
existingEpInfo *network.EndpointInfo
podCfg *cni.K8SPodEnvArgs
orchestratorContext []byte
targetNetworkConfig *cns.GetNetworkContainerResponse
cniMetric telemetry.AIMetric
)
startTime := time.Now()
logger.Info("Processing UPDATE command",
zap.String("netns", args.Netns),
zap.String("args", args.Args),
zap.String("path", args.Path))
// Parse network configuration from stdin.
if nwCfg, err = cni.ParseNetworkConfig(args.StdinData); err != nil {
err = plugin.Errorf("Failed to parse network configuration: %v.", err)
return err
}
if argErr := plugin.validateArgs(args, nwCfg); argErr != nil {
err = argErr
return err
}
logger.Info("Read network configuration", zap.Any("config", nwCfg))
iptables.DisableIPTableLock = nwCfg.DisableIPTableLock
plugin.setCNIReportDetails(nwCfg, CNI_UPDATE, "")
defer func() {
operationTimeMs := time.Since(startTime).Milliseconds()
cniMetric.Metric = aitelemetry.Metric{
Name: telemetry.CNIUpdateTimeMetricStr,
Value: float64(operationTimeMs),
AppVersion: plugin.Version,
CustomDimensions: make(map[string]string),
}
SetCustomDimensions(&cniMetric, nwCfg, err)
telemetry.SendCNIMetric(&cniMetric, plugin.tb)
if result == nil {
result = &cniTypesCurr.Result{}
}
// Convert result to the requested CNI version.
res, vererr := result.GetAsVersion(nwCfg.CNIVersion)
if vererr != nil {
logger.Error("GetAsVersion failed", zap.Error(vererr))
plugin.Error(vererr) //nolint
}
if err == nil && res != nil {
// Output the result to stdout.
res.Print()
}
logger.Info("UPDATE command completed",
zap.Any("result", result),
zap.Error(log.NewErrorWithoutStackTrace(err)))
}()
// Parse Pod arguments.
if podCfg, err = cni.ParseCniArgs(args.Args); err != nil {
logger.Error("Error while parsing CNI Args during UPDATE",
zap.Error(err))
return err
}
k8sNamespace := string(podCfg.K8S_POD_NAMESPACE)
if len(k8sNamespace) == 0 {
errMsg := "Required parameter Pod Namespace not specified in CNI Args during UPDATE"
logger.Error(errMsg)
return plugin.Errorf(errMsg)
}
k8sPodName := string(podCfg.K8S_POD_NAME)
if len(k8sPodName) == 0 {
errMsg := "Required parameter Pod Name not specified in CNI Args during UPDATE"
logger.Error(errMsg)
return plugin.Errorf(errMsg)
}
// Initialize values from network config.
networkID := nwCfg.Name
// Query the network.
if _, err = plugin.nm.GetNetworkInfo(networkID); err != nil {
errMsg := fmt.Sprintf("Failed to query network during CNI UPDATE: %v", err)
logger.Error(errMsg)
return plugin.Errorf(errMsg)
}
// Query the existing endpoint since this is an update.
// Right now, we do not support updating pods that have multiple endpoints.
existingEpInfo, err = plugin.nm.GetEndpointInfoBasedOnPODDetails(networkID, k8sPodName, k8sNamespace, nwCfg.EnableExactMatchForPodName)
if err != nil {
plugin.Errorf("Failed to retrieve target endpoint for CNI UPDATE [name=%v, namespace=%v]: %v", k8sPodName, k8sNamespace, err)
return err
}
logger.Info("Retrieved existing endpoint from state that may get update",
zap.Any("info", existingEpInfo))
// now query CNS to get the target routes that should be there in the networknamespace (as a result of update)
logger.Info("Going to collect target routes from CNS",
zap.String("pod", k8sPodName),
zap.String("namespace", k8sNamespace))
// create struct with info for target POD
podInfo := cns.KubernetesPodInfo{
PodName: k8sPodName,
PodNamespace: k8sNamespace,
}
if orchestratorContext, err = json.Marshal(podInfo); err != nil {
logger.Error("Marshalling KubernetesPodInfo failed",
zap.Error(err))
return plugin.Errorf(err.Error())
}
cnsclient, err := cnscli.New(nwCfg.CNSUrl, defaultRequestTimeout)
if err != nil {
logger.Error("failed to initialized cns client",
zap.String("url", nwCfg.CNSUrl),
zap.String("error", err.Error()))
return plugin.Errorf(err.Error())
}
if targetNetworkConfig, err = cnsclient.GetNetworkContainer(context.TODO(), orchestratorContext); err != nil {
logger.Info("GetNetworkContainer failed",
zap.Error(err))
return plugin.Errorf(err.Error())
}
logger.Info("Network config received from cns",
zap.String("pod", k8sPodName),
zap.String("namespace", k8sNamespace),
zap.Any("config", targetNetworkConfig))
targetEpInfo := &network.EndpointInfo{}
// get the target routes that should replace existingEpInfo.Routes inside the network namespace
if targetNetworkConfig.Routes != nil && len(targetNetworkConfig.Routes) > 0 {
for _, route := range targetNetworkConfig.Routes {
logger.Info("Adding route from routes from targetNetworkConfig to targetEpInfo", zap.Any("route", route))
_, dstIPNet, _ := net.ParseCIDR(route.IPAddress)
gwIP := net.ParseIP(route.GatewayIPAddress)
targetEpInfo.Routes = append(targetEpInfo.Routes, network.RouteInfo{Dst: *dstIPNet, Gw: gwIP, DevName: existingEpInfo.IfName})
}
}
logger.Info("Going to collect target routes based on Cnetaddressspace from targetNetworkConfig",
zap.String("pod", k8sPodName),
zap.String("namespace", k8sNamespace))
ipconfig := targetNetworkConfig.IPConfiguration
for _, ipRouteSubnet := range targetNetworkConfig.CnetAddressSpace {
logger.Info("Adding route from cnetAddressspace to targetEpInfo", zap.Any("subnet", ipRouteSubnet))
dstIPNet := net.IPNet{IP: net.ParseIP(ipRouteSubnet.IPAddress), Mask: net.CIDRMask(int(ipRouteSubnet.PrefixLength), 32)}
gwIP := net.ParseIP(ipconfig.GatewayIPAddress)
route := network.RouteInfo{Dst: dstIPNet, Gw: gwIP, DevName: existingEpInfo.IfName}
targetEpInfo.Routes = append(targetEpInfo.Routes, route)
}
logger.Info("Finished collecting new routes in targetEpInfo", zap.Any("route", targetEpInfo.Routes))
logger.Info("Now saving existing infravnetaddress space if needed.")
for _, ns := range nwCfg.PodNamespaceForDualNetwork {
if k8sNamespace == ns {
targetEpInfo.EnableInfraVnet = true
targetEpInfo.InfraVnetAddressSpace = nwCfg.InfraVnetAddressSpace
logger.Info("Saving infravnet address space",
zap.String("space", targetEpInfo.InfraVnetAddressSpace),
zap.String("namespace", existingEpInfo.PODNameSpace),
zap.String("pod", existingEpInfo.PODName))
break
}
}
// Update the endpoint.
logger.Info("Now updating existing endpoint with targetNetworkConfig",
zap.String("endpoint", existingEpInfo.EndpointID),
zap.Any("config", targetNetworkConfig))
if err = plugin.nm.UpdateEndpoint(networkID, existingEpInfo, targetEpInfo); err != nil {
err = plugin.Errorf("Failed to update endpoint: %v", err)
return err
}
msg := fmt.Sprintf("CNI UPDATE succeeded : Updated %+v podname %v namespace %v", targetNetworkConfig, k8sPodName, k8sNamespace)
plugin.setCNIReportDetails(nwCfg, CNI_UPDATE, msg)
return nil
}