Skip to content

Commit

Permalink
Add support for pod annotation based scraping (#414)
Browse files Browse the repository at this point in the history
  • Loading branch information
gracewehner authored Mar 9, 2023
1 parent 070eff5 commit d84a02b
Show file tree
Hide file tree
Showing 10 changed files with 238 additions and 36 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
scrape_configs:
- job_name: 'kubernetes-pods'
kubernetes_sd_configs:
- role: pod
relabel_configs:
- source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape]
action: keep
regex: true
- source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_path]
action: replace
target_label: __metrics_path__
regex: (.+)
- source_labels: [__address__, __meta_kubernetes_pod_annotation_prometheus_io_port]
action: replace
regex: ([^:]+)(?::\d+)?;(\d+)
replacement: $1:$2
target_label: __address__
- action: labelmap
regex: __meta_kubernetes_pod_label_(.+)
- source_labels: [__meta_kubernetes_namespace]
action: replace
target_label: kubernetes_namespace
- source_labels: [__meta_kubernetes_pod_name]
action: replace
target_label: kubernetes_pod_name
42 changes: 42 additions & 0 deletions otelcollector/configmapparser/prometheus-config-merger.rb
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
@windowsexporterDefaultDsFile = @defaultPromConfigPathPrefix + "windowsexporterDefaultDs.yml"
@windowskubeproxyDefaultFileRsSimpleFile = @defaultPromConfigPathPrefix + "windowskubeproxyDefaultRsSimple.yml"
@windowskubeproxyDefaultDsFile = @defaultPromConfigPathPrefix + "windowskubeproxyDefaultDs.yml"
@podannotationsDefaultFile = @defaultPromConfigPathPrefix + "podannotationsDefault.yml"
@windowskubeproxyDefaultRsAdvancedFile = @defaultPromConfigPathPrefix + "windowskubeproxyDefaultRsAdvanced.yml"
@kappiebasicDefaultFileDs = @defaultPromConfigPathPrefix + "kappieBasicDefaultDs.yml"

Expand Down Expand Up @@ -128,6 +129,32 @@ def AppendMetricRelabelConfig(yamlConfigFile, keepListRegex)
end
end

def AppendRelabelConfig(yamlConfigFile, relabelConfig, keepRegex)
begin
ConfigParseErrorLogger.log(LOGGING_PREFIX, "Adding relabel config for #{yamlConfigFile}")
config = YAML.load(File.read(yamlConfigFile))

# Iterate through each scrape config and append metric relabel config for keep list
if !config.nil?
scrapeConfigs = config["scrape_configs"]
if !scrapeConfigs.nil? && !scrapeConfigs.empty?
scrapeConfigs.each { |scfg|
relabelCfgs = scfg["relabel_configs"]
if relabelCfgs.nil?
scfg["relabel_configs"] = relabelConfig
else
scfg["relabel_configs"] = relabelCfgs.concat(relabelConfig)
end
}
cfgYamlWithRelabelConfig = YAML::dump(config)
File.open(yamlConfigFile, "w") { |file| file.puts cfgYamlWithRelabelConfig }
end
end
rescue => errorStr
ConfigParseErrorLogger.logError(LOGGING_PREFIX, "Exception while appending relabel config in default target file - #{yamlConfigFile} : #{errorStr}. The keep list regex will not be used")
end
end

# Get the list of default configs to be included in the otel's prometheus config
def populateDefaultPrometheusConfig
begin
Expand Down Expand Up @@ -383,6 +410,21 @@ def populateDefaultPrometheusConfig
end
end

if !ENV["AZMON_PROMETHEUS_POD_ANNOTATION_NAMESPACES_REGEX"].nil? && currentControllerType == @replicasetControllerType
podannotationNamespacesRegex = ENV["AZMON_PROMETHEUS_POD_ANNOTATION_NAMESPACES_REGEX"]
podannotationMetricsKeepListRegex = @regexHash["POD_ANNOTATION_METRICS_KEEP_LIST_REGEX"]
podannotationScrapeInterval = @intervalHash["POD_ANNOTATION_SCRAPE_INTERVAL"]
UpdateScrapeIntervalConfig(@podannotationsDefaultFile, podannotationScrapeInterval)
if !podannotationMetricsKeepListRegex.nil? && !podannotationMetricsKeepListRegex.empty?
AppendMetricRelabelConfig(@podannotationsDefaultFile, podannotationMetricsKeepListRegex)
end
if !podannotationNamespacesRegex.nil? && !podannotationNamespacesRegex.empty?
relabelConfig = [{ "source_labels" => ["__meta_kubernetes_namespace"], "action" => "keep", "regex" => podannotationNamespacesRegex }]
AppendRelabelConfig(@podannotationsDefaultFile, relabelConfig, podannotationNamespacesRegex)
end
defaultConfigs.push(@podannotationsDefaultFile)
end

@mergedDefaultConfigs = mergeDefaultScrapeConfigs(defaultConfigs)
rescue => errorStr
ConfigParseErrorLogger.logError(LOGGING_PREFIX, "Exception while merging default scrape targets - #{errorStr}. No default scrape targets will be included")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
@kubestateEnabled = true
@nodeexporterEnabled = true
@prometheusCollectorHealthEnabled = true
@podannotationEnabled = false
@windowsexporterEnabled = false
@windowskubeproxyEnabled = false
@kappiebasicEnabled = false
Expand Down Expand Up @@ -84,6 +85,10 @@ def populateSettingValuesFromConfigMap(parsedConfig)
@windowskubeproxyEnabled = parsedConfig[:windowskubeproxy]
puts "config::Using configmap scrape settings for windowskubeproxy: #{@windowskubeproxyEnabled}"
end
if !ENV['AZMON_PROMETHEUS_POD_ANNOTATION_NAMESPACES_REGEX'].nil? && !ENV['AZMON_PROMETHEUS_POD_ANNOTATION_NAMESPACES_REGEX'].empty?
@podannotationEnabled = "true"
puts "config::Using configmap scrape settings for podannotations: #{@podannotationEnabled}"
end
if !parsedConfig[:kappiebasic].nil?
@kappiebasicEnabled = parsedConfig[:kappiebasic]
puts "config::Using configmap scrape settings for kappiebasic: #{@kappiebasicEnabled}"
Expand All @@ -100,15 +105,15 @@ def populateSettingValuesFromConfigMap(parsedConfig)
@noDefaultsEnabled = true
elsif controllerType == "DaemonSet" && ENV["OS_TYPE"].downcase == "linux" && !@kubeletEnabled && !@cadvisorEnabled && !@nodeexporterEnabled && !@prometheusCollectorHealthEnabled && !kappiebasicEnabled
@noDefaultsEnabled = true
elsif controllerType == "ReplicaSet" && @sendDsUpMetric && !@kubeletEnabled && !@cadvisorEnabled && !@nodeexporterEnabled && !@corednsEnabled && !@kubeproxyEnabled && !@apiserverEnabled && !@kubestateEnabled && !@windowsexporterEnabled && !@windowskubeproxyEnabled && !@prometheusCollectorHealthEnabled
elsif controllerType == "ReplicaSet" && @sendDsUpMetric && !@kubeletEnabled && !@cadvisorEnabled && !@nodeexporterEnabled && !@corednsEnabled && !@kubeproxyEnabled && !@apiserverEnabled && !@kubestateEnabled && !@windowsexporterEnabled && !@windowskubeproxyEnabled && !@prometheusCollectorHealthEnabled && !@podannotationEnabled
@noDefaultsEnabled = true
elsif controllerType == "ReplicaSet" && !@sendDsUpMetric && windowsDaemonset && !@corednsEnabled && !@kubeproxyEnabled && !@apiserverEnabled && !@kubestateEnabled && !@prometheusCollectorHealthEnabled
elsif controllerType == "ReplicaSet" && !@sendDsUpMetric && windowsDaemonset && !@corednsEnabled && !@kubeproxyEnabled && !@apiserverEnabled && !@kubestateEnabled && !@prometheusCollectorHealthEnabled && !@podannotationEnabled
@noDefaultsEnabled = true
# Windows daemonset is not enabled so Windows kube-proxy and node-exporter are scraped from replica
elsif controllerType == "ReplicaSet" && !@sendDsUpMetric && !windowsDaemonset && !@corednsEnabled && !@kubeproxyEnabled && !@apiserverEnabled && !@kubestateEnabled && !@windowsexporterEnabled && !@windowskubeproxyEnabled && !@prometheusCollectorHealthEnabled
elsif controllerType == "ReplicaSet" && !@sendDsUpMetric && !windowsDaemonset && !@corednsEnabled && !@kubeproxyEnabled && !@apiserverEnabled && !@kubestateEnabled && !@windowsexporterEnabled && !@windowskubeproxyEnabled && !@prometheusCollectorHealthEnabled && !@podannotationEnabled
@noDefaultsEnabled = true
end
elsif !@kubeletEnabled && !@corednsEnabled && !@cadvisorEnabled && !@kubeproxyEnabled && !@apiserverEnabled && !@kubestateEnabled && !@nodeexporterEnabled && !@windowsexporterEnabled && !@windowskubeproxyEnabled && !@prometheusCollectorHealthEnabled
elsif !@kubeletEnabled && !@corednsEnabled && !@cadvisorEnabled && !@kubeproxyEnabled && !@apiserverEnabled && !@kubestateEnabled && !@nodeexporterEnabled && !@windowsexporterEnabled && !@windowskubeproxyEnabled && !@prometheusCollectorHealthEnabled && !@podannotationEnabled
@noDefaultsEnabled = true
end
if @noDefaultsEnabled
Expand Down Expand Up @@ -163,6 +168,7 @@ def populateSettingValuesFromConfigMap(parsedConfig)
file.write($export + "AZMON_PROMETHEUS_WINDOWSEXPORTER_SCRAPING_ENABLED=#{@windowsexporterEnabled}\n")
file.write($export + "AZMON_PROMETHEUS_WINDOWSKUBEPROXY_SCRAPING_ENABLED=#{@windowskubeproxyEnabled}\n")
file.write($export + "AZMON_PROMETHEUS_KAPPIEBASIC_SCRAPING_ENABLED=#{@kappiebasicEnabled}\n")
file.write($export + "AZMON_PROMETHEUS_POD_ANNOTAION_SCRAPING_ENABLED=#{@podannotationEnabled}\n")
# Close file after writing all metric collection setting environment variables
file.close
else
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
end
require "yaml"
require_relative "ConfigParseErrorLogger"
require_relative "tomlparser-utils"

LOGGING_PREFIX = "default-scrape-keep-lists"

Expand All @@ -23,6 +24,7 @@
@nodeexporterRegex = ""
@windowsexporterRegex = ""
@windowskubeproxyRegex = ""
@podannotationRegex = ""
@kappiebasicRegex = ""

#This will always be string "true" as we set the string value in the chart for both MAC and non MAC modes
Expand Down Expand Up @@ -74,37 +76,6 @@ def parseConfigMap
end
end

# RE2 is not supported for windows
def isValidRegex_linux(str)
begin
# invalid regex example -> 'sel/\\'
re2Regex = RE2::Regexp.new(str)
return re2Regex.ok?
rescue => errorStr
ConfigParseErrorLogger.logError(LOGGING_PREFIX, "Exception while validating regex for target metric keep list - #{errorStr}, regular expression str - #{str}")
return false
end
end

def isValidRegex_windows(str)
begin
# invalid regex example -> 'sel/\\'
re2Regex = Regexp.new(str)
return true
rescue => errorStr
ConfigParseErrorLogger.logError(LOGGING_PREFIX, "Exception while validating regex for target metric keep list - #{errorStr}, regular expression str - #{str}")
return false
end
end

def isValidRegex(str)
if ENV["OS_TYPE"] == "linux"
return isValidRegex_linux(str)
else
return isValidRegex_windows(str)
end
end

# Use the ruby structure created after config parsing to set the right values to be used for otel collector settings
def populateSettingValuesFromConfigMap(parsedConfig)
begin
Expand Down Expand Up @@ -248,6 +219,20 @@ def populateSettingValuesFromConfigMap(parsedConfig)
else
ConfigParseErrorLogger.logError(LOGGING_PREFIX, "windowskubeproxyRegex either not specified or not of type string")
end

podannotationRegex = parsedConfig[:podannotations]
if !podannotationRegex.nil? && podannotationRegex.kind_of?(String)
if !podannotationRegex.empty?
if isValidRegex(podannotationRegex) == true
@podannotationRegex = podannotationRegex
ConfigParseErrorLogger.log(LOGGING_PREFIX, "Using configmap metrics keep list regex for podannotations")
else
ConfigParseErrorLogger.logError(LOGGING_PREFIX, "Invalid keep list regex for podannotations")
end
end
else
ConfigParseErrorLogger.logError(LOGGING_PREFIX, "podannotationRegex either not specified or not of type string")
end
rescue => errorStr
ConfigParseErrorLogger.logError(LOGGING_PREFIX, "Exception while reading config map settings for default targets metrics keep list - #{errorStr}, using defaults, please check config map for errors")
end
Expand Down Expand Up @@ -332,6 +317,7 @@ def populateRegexValuesWithMinimalIngestionProfile
regexHash["NODEEXPORTER_METRICS_KEEP_LIST_REGEX"] = @nodeexporterRegex
regexHash["WINDOWSEXPORTER_METRICS_KEEP_LIST_REGEX"] = @windowsexporterRegex
regexHash["WINDOWSKUBEPROXY_METRICS_KEEP_LIST_REGEX"] = @windowskubeproxyRegex
regexHash["POD_ANNOTATION_METRICS_KEEP_LIST_REGEX"] = @podannotationRegex
regexHash["KAPPIEBASIC_METRICS_KEEP_LIST_REGEX"] = @kappiebasicRegex

if !file.nil?
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
#!/usr/local/bin/ruby
# frozen_string_literal: true

require "tomlrb"
require "yaml"
require_relative "ConfigParseErrorLogger"
require_relative "tomlparser-utils"

LOGGING_PREFIX = "pod-annotation-based-scraping"
@configMapMountPath = "/etc/config/settings/pod-annotation-based-scraping"
@podannotationNamespaceRegex = ""

# Use parser to parse the configmap toml file to a ruby structure
def parseConfigMap
begin
# Check to see if config map is created
if (File.file?(@configMapMountPath))
parsedConfig = Tomlrb.load_file(@configMapMountPath, symbolize_keys: true)
return parsedConfig
else
ConfigParseErrorLogger.log(LOGGING_PREFIX, "configmap section not mounted, using defaults")
return nil
end
rescue => errorStr
ConfigParseErrorLogger.logError(LOGGING_PREFIX, "Exception while parsing config map: #{errorStr}, using defaults, please check config map for errors")
return nil
end
end

# Use the ruby structure created after config parsing to set the right values to be used for otel collector settings
def populateSettingValuesFromConfigMap(parsedConfig)
begin
podannotationRegex = parsedConfig[:podannotationnamepsaceregex]
if !podannotationRegex.nil? && podannotationRegex.kind_of?(String) && !podannotationRegex.empty?
if isValidRegex(podannotationRegex) == true
@podannotationNamespaceRegex = podannotationRegex
ConfigParseErrorLogger.log(LOGGING_PREFIX, "Using configmap namepace regex for podannotations")
else
ConfigParseErrorLogger.logError(LOGGING_PREFIX, "Invalid namespace regex for podannotations")
end
else
ConfigParseErrorLogger.logError(LOGGING_PREFIX, "podannotations namespace regex either not specified or not of type string")
end
end
end

ConfigParseErrorLogger.logSection(LOGGING_PREFIX, "Start Processing")
configMapSettings = parseConfigMap
if !configMapSettings.nil?
populateSettingValuesFromConfigMap(configMapSettings)
elsif (File.file?(@configMapMountPath))
ConfigParseErrorLogger.logError(LOGGING_PREFIX, "Error loading configmap section - using defaults")
end

# Write the settings to file, so that they can be set as environment variables
file = File.open("/opt/microsoft/configmapparser/config_def_pod_annotation_based_scraping", "w")

namespaceRegexHash = {}
namespaceRegexHash["POD_ANNOTATION_NAMESPACES_REGEX"] = @podannotationNamespaceRegex

if !file.nil?
# Close file after writing scrape interval list hash
# Writing it as yaml as it is easy to read and write hash
file.write("export AZMON_PROMETHEUS_POD_ANNOTATION_NAMESPACES_REGEX=#{@podannotationNamespaceRegex}\n")
file.close
else
ConfigParseErrorLogger.logError(LOGGING_PREFIX, "Exception while opening file for writing regex config hash")
end
ConfigParseErrorLogger.logSection(LOGGING_PREFIX, "End default-targets-namespace-keep-list-regex-settings Processing")
17 changes: 17 additions & 0 deletions otelcollector/configmapparser/tomlparser-scrape-interval.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
@windowsexporterScrapeInterval = "30s"
@windowskubeproxyScrapeInterval = "30s"
@prometheusCollectorHealthInterval = "30s"
@podannotationScrapeInterval = "30s"
@kappiebasicScrapeInterval = "30s"

# Use parser to parse the configmap toml file to a ruby structure
Expand Down Expand Up @@ -222,6 +223,21 @@ def populateSettingValuesFromConfigMap(parsedConfig)
else
ConfigParseErrorLogger.log(LOGGING_PREFIX, "prometheusCollectorHealthInterval override not specified in configmap")
end

podannotationScrapeInterval = parsedConfig[:podannotations]
if !podannotationScrapeInterval.nil?
matched = MATCHER.match(podannotationScrapeInterval)
if !matched
# set default scrape interval to 30s if its not in the proper format
podannotationScrapeInterval = "30s"
ConfigParseErrorLogger.log(LOGGING_PREFIX, "Incorrect regex pattern for duration, set default scrape interval to 30s")
else
ConfigParseErrorLogger.log(LOGGING_PREFIX, "Using configmap scrape settings for podannotationScrapeInterval")
end
@podannotationScrapeInterval = podannotationScrapeInterval
else
ConfigParseErrorLogger.log(LOGGING_PREFIX, "podannotationScrapeInterval override not specified in configmap")
end
end
end

Expand Down Expand Up @@ -252,6 +268,7 @@ def populateSettingValuesFromConfigMap(parsedConfig)
intervalHash["WINDOWSEXPORTER_SCRAPE_INTERVAL"] = @windowsexporterScrapeInterval
intervalHash["WINDOWSKUBEPROXY_SCRAPE_INTERVAL"] = @windowskubeproxyScrapeInterval
intervalHash["PROMETHEUS_COLLECTOR_HEALTH_SCRAPE_INTERVAL"] = @prometheusCollectorHealthInterval
intervalHash["POD_ANNOTATION_SCRAPE_INTERVAL"] = @podannotationScrapeInterval
intervalHash["KAPPIEBASIC_SCRAPE_INTERVAL"] = @kappiebasicScrapeInterval

if !file.nil?
Expand Down
39 changes: 39 additions & 0 deletions otelcollector/configmapparser/tomlparser-utils.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
#!/usr/local/bin/ruby
# frozen_string_literal: true

require_relative "ConfigParseErrorLogger"

if (!ENV["OS_TYPE"].nil? && ENV["OS_TYPE"].downcase == "linux")
require "re2"
end

# RE2 is not supported for windows
def isValidRegex_linux(str)
begin
# invalid regex example -> 'sel/\\'
re2Regex = RE2::Regexp.new(str)
return re2Regex.ok?
rescue => errorStr
ConfigParseErrorLogger.logError(LOGGING_PREFIX, "Exception while validating regex for target metric keep list - #{errorStr}, regular expression str - #{str}")
return false
end
end

def isValidRegex_windows(str)
begin
# invalid regex example -> 'sel/\\'
re2Regex = Regexp.new(str)
return true
rescue => errorStr
ConfigParseErrorLogger.logError(LOGGING_PREFIX, "Exception while validating regex for target metric keep list - #{errorStr}, regular expression str - #{str}")
return false
end
end

def isValidRegex(str)
if ENV["OS_TYPE"] == "linux"
return isValidRegex_linux(str)
else
return isValidRegex_windows(str)
end
end
8 changes: 7 additions & 1 deletion otelcollector/configmaps/ama-metrics-settings-configmap.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ data:
windowskubeproxy = false
kappiebasic = false
prometheuscollectorhealth = false
# Regex for which namespaces to scrape through pod annotation based scraping.
# This is none by default. Use '.*' to scrape all namespaces of annotated pods.
pod-annotation-based-scraping: |-
podannotationnamepsaceregex = ""
default-targets-metrics-keep-list: |-
kubelet = ""
coredns = ""
Expand All @@ -31,6 +35,7 @@ data:
nodeexporter = ""
windowsexporter = ""
windowskubeproxy = ""
podannotations = ""
kappiebasic = ""
minimalingestionprofile = true
default-targets-scrape-interval-settings: |-
Expand All @@ -44,7 +49,8 @@ data:
windowsexporter = "30s"
windowskubeproxy = "30s"
kappiebasic = "30s"
prometheusCollectorHealth = "30s"
prometheuscollectorhealth = "30s"
podannotations = "30s"
debug-mode: |-
enabled = false
metadata:
Expand Down
Loading

0 comments on commit d84a02b

Please sign in to comment.