in cns/service/main.go [497:1144]
func main() {
// Initialize and parse command line arguments.
acn.ParseArgs(&args, printVersion)
cniPath := acn.GetArg(acn.OptNetPluginPath).(string)
cniConfigFile := acn.GetArg(acn.OptNetPluginConfigFile).(string)
cnsURL := acn.GetArg(acn.OptCnsURL).(string)
cnsPort := acn.GetArg(acn.OptCnsPort).(string)
logLevel := acn.GetArg(acn.OptLogLevel).(int)
logTarget := acn.GetArg(acn.OptLogTarget).(int)
logDirectory := acn.GetArg(acn.OptLogLocation).(string)
vers := acn.GetArg(acn.OptVersion).(bool)
createDefaultExtNetworkType := acn.GetArg(acn.OptCreateDefaultExtNetworkType).(string)
telemetryEnabled := acn.GetArg(acn.OptTelemetry).(bool)
httpConnectionTimeout := acn.GetArg(acn.OptHttpConnectionTimeout).(int)
httpResponseHeaderTimeout := acn.GetArg(acn.OptHttpResponseHeaderTimeout).(int)
storeFileLocation := acn.GetArg(acn.OptStoreFileLocation).(string)
privateEndpoint := acn.GetArg(acn.OptPrivateEndpoint).(string)
infravnet := acn.GetArg(acn.OptInfrastructureNetworkID).(string)
nodeID := acn.GetArg(acn.OptNodeID).(string)
clientDebugCmd := acn.GetArg(acn.OptDebugCmd).(string)
clientDebugArg := acn.GetArg(acn.OptDebugArg).(string)
cmdLineConfigPath := acn.GetArg(acn.OptCNSConfigPath).(string)
telemetryDaemonEnabled := acn.GetArg(acn.OptTelemetryService).(bool)
cniConflistFilepathArg := acn.GetArg(acn.OptCNIConflistFilepath).(string)
cniConflistScenarioArg := acn.GetArg(acn.OptCNIConflistScenario).(string)
if vers {
printVersion()
os.Exit(0)
}
// Initialize CNS.
var (
err error
config common.ServiceConfig
endpointStateStore store.KeyValueStore
)
config.Version = version
config.Name = name
// Create a channel to receive unhandled errors from CNS.
config.ErrChan = rootErrCh
// Create logging provider.
logger.InitLogger(name, logLevel, logTarget, logDirectory)
if clientDebugCmd != "" {
err := cnscli.HandleCNSClientCommands(rootCtx, clientDebugCmd, clientDebugArg)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
os.Exit(0)
}
if !telemetryEnabled {
logger.Errorf("[Azure CNS] Cannot disable telemetry via cmdline. Update cns_config.json to disable telemetry.")
}
cnsconfig, err := configuration.ReadConfig(cmdLineConfigPath)
if err != nil {
if errors.Is(err, fs.ErrNotExist) {
logger.Warnf("config file does not exist, using default")
cnsconfig = &configuration.CNSConfig{}
} else {
logger.Errorf("fatal: failed to read cns config: %v", err)
os.Exit(1)
}
}
configuration.SetCNSConfigDefaults(cnsconfig)
disableTelemetry := cnsconfig.TelemetrySettings.DisableAll
if !disableTelemetry {
ts := cnsconfig.TelemetrySettings
aiConfig := aitelemetry.AIConfig{
AppName: name,
AppVersion: version,
BatchSize: ts.TelemetryBatchSizeBytes,
BatchInterval: ts.TelemetryBatchIntervalInSecs,
RefreshTimeout: ts.RefreshIntervalInSecs,
DisableMetadataRefreshThread: ts.DisableMetadataRefreshThread,
DebugMode: ts.DebugMode,
}
if aiKey := cnsconfig.TelemetrySettings.AppInsightsInstrumentationKey; aiKey != "" {
logger.InitAIWithIKey(aiConfig, aiKey, ts.DisableTrace, ts.DisableMetric, ts.DisableEvent)
} else {
logger.InitAI(aiConfig, ts.DisableTrace, ts.DisableMetric, ts.DisableEvent)
}
if cnsconfig.TelemetrySettings.ConfigSnapshotIntervalInMins > 0 {
go metric.SendCNSConfigSnapshot(rootCtx, cnsconfig)
}
}
logger.Printf("[Azure CNS] Using config: %+v", cnsconfig)
_, envEnableConflistGeneration := os.LookupEnv(envVarEnableCNIConflistGeneration)
var conflistGenerator restserver.CNIConflistGenerator
if cnsconfig.EnableCNIConflistGeneration || envEnableConflistGeneration {
conflistFilepath := cnsconfig.CNIConflistFilepath
if cniConflistFilepathArg != "" {
// allow the filepath to get overidden by command line arg
conflistFilepath = cniConflistFilepathArg
}
writer, newWriterErr := acnfs.NewAtomicWriter(conflistFilepath)
if newWriterErr != nil {
logger.Errorf("unable to create atomic writer to generate cni conflist: %v", newWriterErr)
os.Exit(1)
}
// allow the scenario to get overridden by command line arg
scenarioString := cnsconfig.CNIConflistScenario
if cniConflistScenarioArg != "" {
scenarioString = cniConflistScenarioArg
}
switch scenario := cniConflistScenario(scenarioString); scenario {
case scenarioV4Overlay:
conflistGenerator = &cniconflist.V4OverlayGenerator{Writer: writer}
case scenarioDualStackOverlay:
conflistGenerator = &cniconflist.DualStackOverlayGenerator{Writer: writer}
case scenarioOverlay:
conflistGenerator = &cniconflist.OverlayGenerator{Writer: writer}
case scenarioCilium:
conflistGenerator = &cniconflist.CiliumGenerator{Writer: writer}
case scenarioSWIFT:
conflistGenerator = &cniconflist.SWIFTGenerator{Writer: writer}
default:
logger.Errorf("unable to generate cni conflist for unknown scenario: %s", scenario)
os.Exit(1)
}
}
// configure zap logger
zconfig := zap.NewProductionConfig()
zconfig.EncoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder
if z, err = zconfig.Build(); err != nil {
fmt.Printf("failed to create logger: %v", err)
os.Exit(1)
}
// start the healthz/readyz/metrics server
readyCh := make(chan any)
readyChecker := healthz.CheckHandler{
Checker: healthz.Checker(func(*http.Request) error {
select {
default:
return errors.New("not ready")
case <-readyCh:
}
return nil
}),
}
healthzHandler, err := healthserver.NewHealthzHandlerWithChecks(&healthserver.Config{PingAPIServer: cnsconfig.EnableAPIServerHealthPing})
if err != nil {
logger.Errorf("unable to initialize a healthz handler: %v", err)
return
}
go healthserver.Start(z, cnsconfig.MetricsBindAddress, healthzHandler, readyChecker)
nmaConfig, err := nmagent.NewConfig(cnsconfig.WireserverIP)
if err != nil {
logger.Errorf("[Azure CNS] Failed to produce NMAgent config from the supplied wireserver ip: %v", err)
return
}
nmaClient, err := nmagent.NewClient(nmaConfig)
if err != nil {
logger.Errorf("[Azure CNS] Failed to start nmagent client due to error: %v", err)
return
}
// copy ChannelMode from cnsconfig to HTTPRemoteRestService config
config.ChannelMode = cnsconfig.ChannelMode
if cnsconfig.ChannelMode == cns.Managed {
privateEndpoint = cnsconfig.ManagedSettings.PrivateEndpoint
infravnet = cnsconfig.ManagedSettings.InfrastructureNetworkID
nodeID = cnsconfig.ManagedSettings.NodeID
}
if isManaged, ok := acn.GetArg(acn.OptManaged).(bool); ok && isManaged {
config.ChannelMode = cns.Managed
}
homeAzMonitor := restserver.NewHomeAzMonitor(nmaClient, time.Duration(cnsconfig.AZRSettings.PopulateHomeAzCacheRetryIntervalSecs)*time.Second)
// homeAz monitor is only required when there is a direct channel between DNC and CNS.
// This will prevent the monitor from unnecessarily calling NMA APIs for other scenarios such as AKS-swift, swiftv2
if cnsconfig.ChannelMode == cns.Direct {
homeAzMonitor.Start()
defer homeAzMonitor.Stop()
}
if telemetryDaemonEnabled {
logger.Printf("CNI Telemetry is enabled")
go startTelemetryService(rootCtx)
}
// Log platform information.
logger.Printf("Running on %v", platform.GetOSInfo())
err = platform.CreateDirectory(storeFileLocation)
if err != nil {
logger.Errorf("Failed to create File Store directory %s, due to Error:%v", storeFileLocation, err.Error())
return
}
lockclient, err := processlock.NewFileLock(platform.CNILockPath + name + store.LockExtension)
if err != nil {
logger.Printf("Error initializing file lock:%v", err)
return
}
// Create the key value store.
storeFileName := storeFileLocation + name + ".json"
config.Store, err = store.NewJsonFileStore(storeFileName, lockclient, nil)
if err != nil {
logger.Errorf("Failed to create store file: %s, due to error %v\n", storeFileName, err)
return
}
// Initialize endpoint state store if cns is managing endpoint state.
if cnsconfig.ManageEndpointState {
logger.Printf("[Azure CNS] Configured to manage endpoints state")
endpointStoreLock, err := processlock.NewFileLock(platform.CNILockPath + endpointStoreName + store.LockExtension) // nolint
if err != nil {
logger.Printf("Error initializing endpoint state file lock:%v", err)
return
}
defer endpointStoreLock.Unlock() // nolint
err = platform.CreateDirectory(endpointStorePath)
if err != nil {
logger.Errorf("Failed to create File Store directory %s, due to Error:%v", storeFileLocation, err.Error())
return
}
// Create the key value store.
storeFileName := endpointStorePath + endpointStoreName + ".json"
logger.Printf("EndpointStoreState path is %s", storeFileName)
endpointStateStore, err = store.NewJsonFileStore(storeFileName, endpointStoreLock, nil)
if err != nil {
logger.Errorf("Failed to create endpoint state store file: %s, due to error %v\n", storeFileName, err)
return
}
}
wsProxy := wireserver.Proxy{
Host: cnsconfig.WireserverIP,
HTTPClient: &http.Client{},
}
wsclient := &wireserver.Client{
HostPort: cnsconfig.WireserverIP,
HTTPClient: &http.Client{},
Logger: logger.Log,
}
imdsClient := imds.NewClient()
httpRemoteRestService, err := restserver.NewHTTPRestService(&config, wsclient, &wsProxy, &restserver.IPtablesProvider{}, nmaClient,
endpointStateStore, conflistGenerator, homeAzMonitor, imdsClient)
if err != nil {
logger.Errorf("Failed to create CNS object, err:%v.\n", err)
return
}
// Set CNS options.
httpRemoteRestService.SetOption(acn.OptCnsURL, cnsURL)
httpRemoteRestService.SetOption(acn.OptCnsPort, cnsPort)
httpRemoteRestService.SetOption(acn.OptNetPluginPath, cniPath)
httpRemoteRestService.SetOption(acn.OptNetPluginConfigFile, cniConfigFile)
httpRemoteRestService.SetOption(acn.OptCreateDefaultExtNetworkType, createDefaultExtNetworkType)
httpRemoteRestService.SetOption(acn.OptHttpConnectionTimeout, httpConnectionTimeout)
httpRemoteRestService.SetOption(acn.OptHttpResponseHeaderTimeout, httpResponseHeaderTimeout)
httpRemoteRestService.SetOption(acn.OptProgramSNATIPTables, cnsconfig.ProgramSNATIPTables)
httpRemoteRestService.SetOption(acn.OptManageEndpointState, cnsconfig.ManageEndpointState)
// Create default ext network if commandline option is set
if len(strings.TrimSpace(createDefaultExtNetworkType)) > 0 {
if err := hnsclient.CreateDefaultExtNetwork(createDefaultExtNetworkType); err == nil {
logger.Printf("[Azure CNS] Successfully created default ext network")
} else {
logger.Printf("[Azure CNS] Failed to create default ext network due to error: %v", err)
return
}
}
logger.Printf("[Azure CNS] Initialize HTTPRemoteRestService")
if httpRemoteRestService != nil {
if cnsconfig.UseHTTPS {
config.TLSSettings = localtls.TlsSettings{
TLSSubjectName: cnsconfig.TLSSubjectName,
TLSCertificatePath: cnsconfig.TLSCertificatePath,
TLSPort: cnsconfig.TLSPort,
KeyVaultURL: cnsconfig.KeyVaultSettings.URL,
KeyVaultCertificateName: cnsconfig.KeyVaultSettings.CertificateName,
MSIResourceID: cnsconfig.MSISettings.ResourceID,
KeyVaultCertificateRefreshInterval: time.Duration(cnsconfig.KeyVaultSettings.RefreshIntervalInHrs) * time.Hour,
UseMTLS: cnsconfig.UseMTLS,
MinTLSVersion: cnsconfig.MinTLSVersion,
}
}
err = httpRemoteRestService.Init(&config)
if err != nil {
logger.Errorf("Failed to init HTTPService, err:%v.\n", err)
return
}
}
// Setting the remote ARP MAC address to 12-34-56-78-9a-bc on windows for external traffic if HNS is enabled
err = platform.SetSdnRemoteArpMacAddress(rootCtx)
if err != nil {
logger.Errorf("Failed to set remote ARP MAC address: %v", err)
return
}
// We are only setting the PriorityVLANTag in 'cns.Direct' mode, because it neatly maps today, to 'isUsingMultitenancy'
// In the future, we would want to have a better CNS flag, to explicitly say, this CNS is using multitenancy
if cnsconfig.ChannelMode == cns.Direct {
// Set Mellanox adapter's PriorityVLANTag value to 3 if adapter exists
// reg key value for PriorityVLANTag = 3 --> Packet priority and VLAN enabled
// for more details goto https://docs.nvidia.com/networking/display/winof2v230/Configuring+the+Driver+Registry+Keys#ConfiguringtheDriverRegistryKeys-GeneralRegistryKeysGeneralRegistryKeys
if platform.HasMellanoxAdapter() {
go platform.MonitorAndSetMellanoxRegKeyPriorityVLANTag(rootCtx, cnsconfig.MellanoxMonitorIntervalSecs)
}
// if swiftv2 scenario is enabled, we need to initialize the ServiceFabric(standalone) swiftv2 middleware to process IPConfigsRequests
// RequestIPConfigs() will be invoked only for swiftv2 or swiftv1 k8s scenarios. For swiftv1 direct mode different api will be invoked.
// So initializing this middleware always under direct mode should not affect any other scenarios
swiftV2Middleware := &middlewares.StandaloneSWIFTv2Middleware{}
httpRemoteRestService.AttachIPConfigsHandlerMiddleware(swiftV2Middleware)
}
// Initialze state in if CNS is running in CRD mode
// State must be initialized before we start HTTPRestService
if config.ChannelMode == cns.CRD {
// Add APIServer FQDN to Log metadata
logger.Log.SetAPIServer(os.Getenv("KUBERNETES_SERVICE_HOST"))
// Check the CNI statefile mount, and if the file is empty
// stub an empty JSON object
if err := cnireconciler.WriteObjectToCNIStatefile(); err != nil {
logger.Errorf("Failed to write empty object to CNI state: %v", err)
return
}
// We might be configured to reinitialize state from the CNI instead of the apiserver.
// If so, we should check that the CNI is new enough to support the state commands,
// otherwise we fall back to the existing behavior.
if cnsconfig.InitializeFromCNI {
var isGoodVer bool
isGoodVer, err = cnireconciler.IsDumpStateVer()
if err != nil {
logger.Errorf("error checking CNI ver: %v", err)
}
// override the prior config flag with the result of the ver check.
cnsconfig.InitializeFromCNI = isGoodVer
if cnsconfig.InitializeFromCNI {
// Set the PodInfoVersion by initialization type, so that the
// PodInfo maps use the correct key schema
cns.GlobalPodInfoScheme = cns.InterfaceIDPodInfoScheme
}
}
// If cns manageendpointstate is true, then cns maintains its own state and reconciles from it.
// in this case, cns maintains state with containerid as key and so in-memory cache can lookup
// and update based on container id.
if cnsconfig.ManageEndpointState {
cns.GlobalPodInfoScheme = cns.InfraIDPodInfoScheme
}
logger.Printf("Set GlobalPodInfoScheme %v (InitializeFromCNI=%t)", cns.GlobalPodInfoScheme, cnsconfig.InitializeFromCNI)
err = InitializeCRDState(rootCtx, httpRemoteRestService, cnsconfig)
if err != nil {
logger.Errorf("Failed to start CRD Controller, err:%v.\n", err)
return
}
if cnsconfig.EnableSwiftV2 {
// No-op for linux, mapping is set for windows in aks swiftv2 scenario
logger.Printf("Fetching backend nics for the node")
if err = httpRemoteRestService.SavePnpIDMacaddressMapping(rootCtx); err != nil {
logger.Errorf("Failed to fetch PnpIDMacaddress mapping: %v", err)
}
// No-op for linux, setting primary macaddress if VF is enabled on the nics for aks swiftv2 windows
logger.Printf("Setting VF for accelnet nics if feature is enabled (only on windows VM & swiftV2 scenario)")
if err = httpRemoteRestService.SetVFForAccelnetNICs(); err != nil {
logger.Errorf("Failed to set VF for accelnet NICs: %v", err)
}
}
}
// AzureHost channelmode indicates Nodesubnet. IPs are to be fetched from NMagent.
if config.ChannelMode == cns.AzureHost {
if !cnsconfig.ManageEndpointState {
logger.Errorf("ManageEndpointState must be set to true for AzureHost mode")
return
}
// If cns manageendpointstate is true, then cns maintains its own state and reconciles from it.
// in this case, cns maintains state with containerid as key and so in-memory cache can lookup
// and update based on container id.
cns.GlobalPodInfoScheme = cns.InfraIDPodInfoScheme
var podInfoByIPProvider cns.PodInfoByIPProvider
podInfoByIPProvider, err = getPodInfoByIPProvider(rootCtx, cnsconfig, httpRemoteRestService, nil, "")
if err != nil {
logger.Errorf("[Azure CNS] Failed to get PodInfoByIPProvider: %v", err)
return
}
err = httpRemoteRestService.InitializeNodeSubnet(rootCtx, podInfoByIPProvider)
if err != nil {
logger.Errorf("[Azure CNS] Failed to initialize node subnet: %v", err)
return
}
}
// Initialize multi-tenant controller if the CNS is running in MultiTenantCRD mode.
// It must be started before we start HTTPRemoteRestService.
if config.ChannelMode == cns.MultiTenantCRD {
err = InitializeMultiTenantController(rootCtx, httpRemoteRestService, *cnsconfig)
if err != nil {
logger.Errorf("Failed to start multiTenantController, err:%v.\n", err)
return
}
}
if cnsconfig.EnableSwiftV2 && cnsconfig.EnableK8sDevicePlugin {
// Create device plugin manager instance
pluginManager := deviceplugin.NewPluginManager(z)
pluginManager.AddPlugin(mtv1alpha1.DeviceTypeVnetNIC, initialVnetNICCount)
pluginManager.AddPlugin(mtv1alpha1.DeviceTypeInfiniBandNIC, initialIBNICCount)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
// Start device plugin manager in a separate goroutine
go func() {
retryCount := 0
ticker := time.NewTicker(defaultDevicePluginRetryInterval)
// Ensure the ticker is stopped on exit
defer ticker.Stop()
for {
select {
case <-ctx.Done():
z.Info("Context canceled, stopping plugin manager")
return
case <-ticker.C:
if pluginErr := pluginManager.Run(ctx); pluginErr != nil {
z.Error("plugin manager exited with error", zap.Error(pluginErr))
retryCount++
// Implementing a basic circuit breaker
if retryCount >= defaultDevicePluginMaxRetryCount {
z.Error("Max retries reached, stopping plugin manager")
return
}
} else {
return
}
}
}
}()
// go routine to poll node info crd and update device counts
go func() {
if pollErr := pollNodeInfoCRDAndUpdatePlugin(ctx, z, pluginManager); pollErr != nil {
z.Error("Error in pollNodeInfoCRDAndUpdatePlugin", zap.Error(pollErr))
}
}()
}
// Conditionally initialize and start the gRPC server
if cnsconfig.GRPCSettings.Enable {
// Define gRPC server settings
settings := grpc.ServerSettings{
IPAddress: cnsconfig.GRPCSettings.IPAddress,
Port: cnsconfig.GRPCSettings.Port,
}
// Initialize CNS service
cnsService := &grpc.CNS{Logger: z}
// Create a new gRPC server
server, grpcErr := grpc.NewServer(settings, cnsService, z)
if grpcErr != nil {
logger.Errorf("[Listener] Could not initialize gRPC server: %v", grpcErr)
return
}
// Start the gRPC server
go func() {
if grpcErr := server.Start(); grpcErr != nil {
logger.Errorf("[Listener] Could not start gRPC server: %v", grpcErr)
return
}
}()
}
// if user provides cns url by -c option, then only start HTTP remote server using this url
logger.Printf("[Azure CNS] Start HTTP Remote server")
if httpRemoteRestService != nil {
if cnsconfig.EnablePprof {
httpRemoteRestService.RegisterPProfEndpoints()
}
err = httpRemoteRestService.Start(&config)
if err != nil {
logger.Errorf("Failed to start CNS, err:%v.\n", err)
return
}
}
// if user does not provide cns url by -c option, then start http local server
// TODO: we will deprecated -c option in next phase and start local server in any case
if config.Server.EnableLocalServer {
logger.Printf("[Azure CNS] Start HTTP local server")
var localServerURL string
if config.Server.Port != "" {
localServerURL = fmt.Sprintf(defaultLocalServerIP + ":" + config.Server.Port)
} else {
localServerURL = fmt.Sprintf(defaultLocalServerIP + ":" + defaultLocalServerPort)
}
httpLocalRestService := restserverv2.New(httpRemoteRestService)
if httpLocalRestService != nil {
go func() {
err = httpLocalRestService.Start(rootCtx, localServerURL)
if err != nil {
logger.Errorf("Failed to start local echo server, err:%v.\n", err)
return
}
}()
}
}
if cnsconfig.EnableAsyncPodDelete {
// Start fs watcher here
z.Info("AsyncPodDelete is enabled")
logger.Printf("AsyncPodDelete is enabled")
cnsclient, err := cnsclient.New("", cnsReqTimeout) // nolint
if err != nil {
z.Error("failed to create cnsclient", zap.Error(err))
}
go func() {
_ = retry.Do(func() error {
z.Info("starting fsnotify watcher to process missed Pod deletes")
logger.Printf("starting fsnotify watcher to process missed Pod deletes")
var endpointCleanup fsnotify.ReleaseIPsClient = cnsclient
// using endpointmanager implmentation for stateless CNI sceanrio to remove HNS endpoint alongside the IPs
if cnsconfig.IsStalessCNIWindows() {
endpointCleanup = endpointmanager.WithPlatformReleaseIPsManager(cnsclient)
}
w, err := fsnotify.New(endpointCleanup, cnsconfig.AsyncPodDeletePath, z)
if err != nil {
z.Error("failed to create fsnotify watcher", zap.Error(err))
return errors.Wrap(err, "failed to create fsnotify watcher, will retry")
}
if err := w.Start(rootCtx); err != nil {
z.Error("failed to start fsnotify watcher, will retry", zap.Error(err))
return errors.Wrap(err, "failed to start fsnotify watcher, will retry")
}
return nil
}, retry.DelayType(retry.BackOffDelay), retry.Attempts(0), retry.Context(rootCtx)) // infinite cancellable exponential backoff retrier
}()
}
if !disableTelemetry {
go metric.SendHeartBeat(rootCtx, time.Minute*time.Duration(cnsconfig.TelemetrySettings.HeartBeatIntervalInMins), homeAzMonitor, cnsconfig.ChannelMode)
go httpRemoteRestService.SendNCSnapShotPeriodically(rootCtx, cnsconfig.TelemetrySettings.SnapshotIntervalInMins)
}
// If CNS is running on managed DNC mode
if config.ChannelMode == cns.Managed {
if privateEndpoint == "" || infravnet == "" || nodeID == "" {
logger.Errorf("[Azure CNS] Missing required values to run in managed mode: PrivateEndpoint: %s InfrastructureNetworkID: %s NodeID: %s",
privateEndpoint,
infravnet,
nodeID)
return
}
httpRemoteRestService.SetOption(acn.OptPrivateEndpoint, privateEndpoint)
httpRemoteRestService.SetOption(acn.OptInfrastructureNetworkID, infravnet)
httpRemoteRestService.SetOption(acn.OptNodeID, nodeID)
// Passing in the default http client that already implements Do function
standardClient := http.DefaultClient
registerErr := registerNode(rootCtx, standardClient, httpRemoteRestService, privateEndpoint, infravnet, nodeID, nmaClient)
if registerErr != nil {
logger.Errorf("[Azure CNS] Registering Node failed with error: %v PrivateEndpoint: %s InfrastructureNetworkID: %s NodeID: %s",
registerErr,
privateEndpoint,
infravnet,
nodeID)
return
}
go func(ep, vnet, node string) {
// Periodically poll DNC for node updates
tickerChannel := time.Tick(time.Duration(cnsconfig.ManagedSettings.NodeSyncIntervalInSeconds) * time.Second)
for {
<-tickerChannel
httpRemoteRestService.SyncNodeStatus(ep, vnet, node, json.RawMessage{})
}
}(privateEndpoint, infravnet, nodeID)
}
if config.ChannelMode == cns.AzureHost {
// at this point, rest service is running. We can now start serving new requests. So call StartNodeSubnet, which
// will fetch secondary IPs and generate conflist. Do not move this all before rest service start - this will cause
// CNI to start sending requests, and if the service doesn't start successfully, the requests will fail.
httpRemoteRestService.StartNodeSubnet(rootCtx)
}
// mark the service as "ready"
close(readyCh)
// block until process exiting
<-rootCtx.Done()
if len(strings.TrimSpace(createDefaultExtNetworkType)) > 0 {
if err := hnsclient.DeleteDefaultExtNetwork(); err == nil {
logger.Printf("[Azure CNS] Successfully deleted default ext network")
} else {
logger.Printf("[Azure CNS] Failed to delete default ext network due to error: %v", err)
}
}
logger.Printf("stop cns service")
// Cleanup.
if httpRemoteRestService != nil {
httpRemoteRestService.Stop()
}
if err = lockclient.Unlock(); err != nil {
logger.Errorf("lockclient cns unlock error:%v", err)
}
logger.Printf("CNS exited")
logger.Close()
}