func()

in cni/network/multitenancy.go [77:160]


func (m *Multitenancy) DetermineSnatFeatureOnHost(snatFile, nmAgentSupportedApisURL string) (snatForDNS, snatOnHost bool, err error) {
	var (
		snatConfig            snatConfiguration
		retrieveSnatConfigErr error
		jsonFile              *os.File
		httpClient            = &http.Client{Timeout: time.Second * httpTimeout}
		snatConfigFile        = snatConfigFileName + jsonFileExtension
	)

	// Check if we've already retrieved NMAgent version and determined whether to disable snat on host
	if jsonFile, retrieveSnatConfigErr = os.Open(snatFile); retrieveSnatConfigErr == nil {
		bytes, _ := io.ReadAll(jsonFile)
		jsonFile.Close()
		if retrieveSnatConfigErr = json.Unmarshal(bytes, &snatConfig); retrieveSnatConfigErr != nil {
			logger.Error("failed to unmarshal to snatConfig with error %v",
				zap.Error(retrieveSnatConfigErr))
		}
	}

	// If we weren't able to retrieve snatConfiguration, query NMAgent
	if retrieveSnatConfigErr != nil {
		var resp *http.Response
		req, err := http.NewRequestWithContext(context.TODO(), http.MethodGet, nmAgentSupportedApisURL, nil)
		if err != nil {
			logger.Error("failed creating http request", zap.Error(err))
			return false, false, fmt.Errorf("%w", err)
		}
		logger.Info("Query nma for dns snat support", zap.String("query", nmAgentSupportedApisURL))
		resp, retrieveSnatConfigErr = httpClient.Do(req)
		if retrieveSnatConfigErr == nil {
			defer resp.Body.Close()

			if resp.StatusCode == http.StatusOK {
				var bodyBytes []byte
				// if the list of APIs (strings) contains the nmAgentSnatSupportAPI we will disable snat on host
				if bodyBytes, retrieveSnatConfigErr = io.ReadAll(resp.Body); retrieveSnatConfigErr == nil {
					bodyStr := string(bodyBytes)
					if !strings.Contains(bodyStr, nmAgentSnatAndDnsSupportAPI) {
						snatConfig.EnableSnatForDns = true
						snatConfig.EnableSnatOnHost = !strings.Contains(bodyStr, nmAgentSnatSupportAPI)
					}

					jsonStr, _ := json.Marshal(snatConfig)
					fp, err := os.OpenFile(snatConfigFile, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, os.FileMode(filePerm))
					if err == nil {
						_, err = fp.Write(jsonStr)
						if err != nil {
							logger.Error("DetermineSnatFeatureOnHost: Write to json failed", zap.Error(err))
						}
						fp.Close()
					} else {
						logger.Error("failed to save snat settings",
							zap.String("snatConfgFile", snatConfigFile),
							zap.Error(err))
					}
				}
			} else {
				retrieveSnatConfigErr = fmt.Errorf("%w:%d", errNmaResponse, resp.StatusCode)
			}
		}
	}

	// Log and return the error when we fail acquire snat configuration for host and dns
	if retrieveSnatConfigErr != nil {
		logger.Error("failed to acquire SNAT configuration with error %v",
			zap.Error(retrieveSnatConfigErr))
		return snatConfig.EnableSnatForDns, snatConfig.EnableSnatOnHost, retrieveSnatConfigErr
	}

	logger.Info("saved snat settings",
		zap.Any("snatConfig", snatConfig),
		zap.String("snatConfigfile", snatConfigFile))
	if snatConfig.EnableSnatOnHost {
		logger.Info("enabling SNAT on container host for outbound connectivity")
	}
	if snatConfig.EnableSnatForDns {
		logger.Info("enabling SNAT on container host for DNS traffic")
	}
	if !snatConfig.EnableSnatForDns && !snatConfig.EnableSnatOnHost {
		logger.Info("disabling SNAT on container host")
	}

	return snatConfig.EnableSnatForDns, snatConfig.EnableSnatOnHost, nil
}