func WatchConfig()

in agentconfig/agentconfig.go [436:502]


func WatchConfig(ctx context.Context) error {
	var md []byte
	var webError error
	// Max watch time, after this WatchConfig will return.
	timeout := time.After(osConfigWatchConfigTimeout)
	// Min watch loop time.
	loopTicker := time.NewTicker(5 * time.Second)
	defer loopTicker.Stop()
	eTag := lEtag.get()
	webErrorCount := 0
	unmarshalErrorCount := 0
	for {
		md, eTag, webError = getMetadata(fmt.Sprintf("?recursive=true&alt=json&wait_for_change=true&last_etag=%s&timeout_sec=%d", lEtag.get(), osConfigMetadataPollTimeout))
		if webError == nil && eTag != lEtag.get() {
			var metadataConfig metadataJSON
			if err := json.Unmarshal(md, &metadataConfig); err != nil {
				// Try up to three times (with 5s sleep) to get and unmarshal metadata.
				// Most unmarshal errors are transient read issues with the metadata server
				// so we should retry without logging the error.
				if unmarshalErrorCount >= 3 {
					return err
				}
				unmarshalErrorCount++
				select {
				case <-timeout:
					return err
				case <-ctx.Done():
					return nil
				case <-loopTicker.C:
					continue
				}
			}
			unmarshalErrorCount = 0
			lEtag.set(eTag)

			newAgentConfig := createConfigFromMetadata(metadataConfig)

			agentConfigMx.Lock()
			if agentConfig.asSha256() != newAgentConfig.asSha256() {
				agentConfig = newAgentConfig
				agentConfigMx.Unlock()
				break
			}
			agentConfigMx.Unlock()
		}

		// Try up to 12 times (60s) to wait for slow network initialization, after
		// that resort to using defaults and returning the error.
		if webError != nil {
			if webErrorCount == 12 {
				return formatMetadataError(webError)
			}
			webErrorCount++
		}

		select {
		case <-timeout:
			return webError
		case <-ctx.Done():
			return nil
		case <-loopTicker.C:
			continue
		}
	}

	return webError
}