diff --git a/.pipelines/azure-pipeline-config-tests.yaml b/.pipelines/azure-pipeline-config-tests.yaml index 16a28ec71..1661b836c 100644 --- a/.pipelines/azure-pipeline-config-tests.yaml +++ b/.pipelines/azure-pipeline-config-tests.yaml @@ -1,4 +1,7 @@ -# ConfigMap Testing Pipeline for ama-logs (stub - full implementation in zane/configmap-testing-pipeline) +# ConfigMap Testing Pipeline for ama-logs +# Applies different ConfigMap variants, restarts pods, and runs scenario-specific Ginkgo tests via TestKube. +# Manual trigger only. + trigger: none pr: none @@ -6,16 +9,221 @@ parameters: - name: clusterName displayName: 'AKS Cluster Name' type: string + default: 'ci-logs-dev-aks-std-prof-config-test1' - name: clusterResourceGroup displayName: 'AKS Cluster Resource Group' type: string + default: 'ci-logs-dev-aks-configmap-test' + - name: branch + displayName: 'Git branch for TestKube workflows' + type: string + default: 'zane/configmap-testing-pipeline' + # Case names must match the 'name' field in test/testkube/configmap-test-matrix.yaml + - name: cases + displayName: 'Test cases to run' + type: object + default: + - process-metrics-enabled + - process-metrics-default stages: - stage: ConfigMapTests jobs: - - job: Placeholder + - job: RunConfigMapTests + timeoutInMinutes: 120 + displayName: "ConfigMap Processing Tests" pool: name: Azure-Pipelines-CI-Test-EO + variables: + skipComponentGovernanceDetection: true steps: - - script: echo "Pipeline created. Point to branch zane/configmap-testing-pipeline for full implementation." - displayName: 'Placeholder' + - checkout: self + persistCredentials: true + + # === Setup === + + - script: | + curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash + displayName: 'Install Azure CLI' + + - script: | + set -euo pipefail + echo "Ensuring kubectl & helm are installed" + if ! command -v az >/dev/null 2>&1; then + echo "Azure CLI not found; aborting" >&2 + exit 1 + fi + if ! command -v kubectl >/dev/null 2>&1; then + echo "kubectl not found. Installing via 'az aks install-cli' with sudo" + sudo az aks install-cli + else + echo "kubectl already installed: $(kubectl version --client --short || true)" + fi + if ! command -v helm >/dev/null 2>&1; then + echo "Helm not found. Installing Helm 3" + curl -fsSL https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash + else + echo "Helm already installed: $(helm version --short || true)" + fi + displayName: 'Install kubectl and Helm' + + - task: AzureCLI@2 + displayName: Get kubeconfig + inputs: + azureSubscription: 'ContainerInsights_Build_Subscription_CI' + scriptLocation: 'inlineScript' + scriptType: 'bash' + inlineScript: 'az aks get-credentials -g ${{ parameters.clusterResourceGroup }} -n ${{ parameters.clusterName }}' + + - script: | + echo "Install testkube CLI" + wget -qO - https://repo.testkube.io/key.pub | sudo apt-key add - + echo "deb https://repo.testkube.io/linux linux main" | sudo tee -a /etc/apt/sources.list + sudo apt-get update + sudo apt-get install -y testkube + displayName: 'Install Testkube CLI' + + - bash: | + set -euo pipefail + + # Remove stale CRDs that block Helm ownership + stale_crds=( + "testworkflowexecutions.testworkflows.testkube.io" + "testworkflows.testkube.io" + "testworkflows.testworkflows.testkube.io" + "testworkflowtemplates.testworkflows.testkube.io" + ) + echo "Checking for stale Testkube CRDs" + for crd in "${stale_crds[@]}"; do + if kubectl get crd "$crd" >/dev/null 2>&1; then + owner=$(kubectl get crd "$crd" -o jsonpath='{.metadata.labels.app\.kubernetes\.io/managed-by}') + if [[ "$owner" != "Helm" ]]; then + echo "Deleting CRD $crd with unmanaged owner: ${owner:-none}" + kubectl delete crd "$crd" --wait=true || true + fi + fi + done + + # Clean up existing TestKube installation if present + if helm list -n testkube 2>/dev/null | grep -q testkube; then + echo "Found existing Testkube installation. Cleaning up..." + helm uninstall testkube -n testkube || true + kubectl delete namespace testkube --wait=true --timeout=120s || true + sleep 30 + fi + + # Add Helm repo + helm repo add kubeshop https://kubeshop.github.io/helm-charts + helm repo update + + # Pre-install CRDs from the chart so post-install hooks can create + # TestWorkflowTemplate resources. The operator is disabled in values + # (existing CI clusters already have CRDs from prior installs). + echo "Pre-installing TestKube CRDs from chart..." + helm template testkube kubeshop/testkube -n testkube \ + -f ./helm-testkube-values.yaml \ + --set testkube-operator.enabled=true \ + --set testkube-operator.installCRD=true \ + --show-only charts/testkube-operator/templates/crds.yaml \ + | kubectl apply --server-side -f - + + # Label/annotate CRDs so Helm adopts them as part of the "testkube" release + echo "Labeling CRDs for Helm ownership..." + for crd in $(kubectl get crds -o name | grep testkube); do + kubectl label "$crd" app.kubernetes.io/managed-by=Helm --overwrite + kubectl annotate "$crd" meta.helm.sh/release-name=testkube --overwrite + kubectl annotate "$crd" meta.helm.sh/release-namespace=testkube --overwrite + done + + echo "Waiting for CRDs to be established..." + for crd in testworkflows.testworkflows.testkube.io testworkflowtemplates.testworkflows.testkube.io testworkflowexecutions.testworkflows.testkube.io; do + kubectl wait --for=condition=Established crd/"$crd" --timeout=60s || echo "Warning: CRD $crd not yet established" + done + + # Install TestKube (operator stays DISABLED — CRDs already in place) + helm upgrade --install --create-namespace testkube kubeshop/testkube -n testkube \ + -f ./helm-testkube-values.yaml + + # Apply RBAC + kubectl apply -f ./api-server-permissions.yaml + + echo "Waiting for TestKube API server to be ready..." + kubectl rollout status deployment/testkube-api-server -n testkube --timeout=300s + # Give the API server a moment to finish initialization after pod is ready + sleep 15 + workingDirectory: $(Build.SourcesDirectory)/test/testkube + displayName: 'Install TestKube on cluster' + + # Apply TestWorkflow CRs (includes countprocess and others) + - bash: | + kubectl apply -f ./testkube-test-crs.yaml + echo "Waiting for TestWorkflows to be registered..." + sleep 10 + workingDirectory: $(Build.SourcesDirectory)/test/testkube + displayName: 'Apply TestWorkflow CRs' + + # === Validate cases match matrix === + - bash: | + set -euo pipefail + + # Install yq if not present + if ! command -v yq &> /dev/null; then + curl -sL https://github.com/mikefarah/yq/releases/latest/download/yq_linux_amd64 -o /tmp/yq + chmod +x /tmp/yq + yq="/tmp/yq" + else + yq="yq" + fi + + # Cases from pipeline parameter + echo "$PIPELINE_CASES" | tr ',' '\n' | sed 's/^ *//;s/ *$//' | sort > /tmp/pipeline.txt + + # Cases from matrix YAML + $yq '.cases[].name' ./configmap-test-matrix.yaml | sort > /tmp/matrix.txt + + echo "Pipeline cases:" + cat /tmp/pipeline.txt + echo "" + echo "Matrix cases:" + cat /tmp/matrix.txt + echo "" + + if ! diff /tmp/pipeline.txt /tmp/matrix.txt; then + echo "##[error]Pipeline cases and matrix cases are out of sync!" + echo "Update the 'cases' parameter in azure-pipeline-config-tests.yaml to match configmap-test-matrix.yaml" + exit 1 + fi + + echo "Pipeline cases match matrix cases." + workingDirectory: $(Build.SourcesDirectory)/test/testkube + displayName: 'Validate cases match matrix' + env: + PIPELINE_CASES: ${{ join(',', parameters.cases) }} + + # === Run test cases (one step per case) === + - ${{ each caseName in parameters.cases }}: + - bash: | + chmod +x ./run-configmap-test-case.sh + ./run-configmap-test-case.sh \ + --case "${{ caseName }}" \ + --repo-root "$(Build.SourcesDirectory)" + workingDirectory: $(Build.SourcesDirectory)/test/testkube + displayName: "ConfigTest: ${{ caseName }}" + continueOnError: true + env: + AZURE_TENANT_ID: $(AZURE_TENANT_ID) + AZURE_CLIENT_ID: $(AZURE_CLIENT_ID) + GENEVA_INTEGRATION: false + + # === Cleanup === + - bash: | + echo "Restoring original configmap..." + kubectl apply -f $(Build.SourcesDirectory)/kubernetes/container-azm-ms-agentconfig.yaml || true + + echo "Cleaning up Testkube installation..." + helm uninstall testkube -n testkube || true + kubectl delete namespace testkube --wait=true --timeout=120s || true + echo "Cleanup complete." + workingDirectory: $(Build.SourcesDirectory)/test/testkube + displayName: 'Cleanup' + condition: always() diff --git a/test/configmaps/config-tests/container-azm-ms-agentconfig-process-metrics-enabled.yaml b/test/configmaps/config-tests/container-azm-ms-agentconfig-process-metrics-enabled.yaml new file mode 100644 index 000000000..ff30b4547 --- /dev/null +++ b/test/configmaps/config-tests/container-azm-ms-agentconfig-process-metrics-enabled.yaml @@ -0,0 +1,268 @@ +kind: ConfigMap +apiVersion: v1 +data: + schema-version: + #string.used by agent to parse config. supported versions are {v1}. Configs with other schema versions will be rejected by the agent. + v1 + config-version: + #string.used by customer to keep track of this config file's version in their source control/repository (max allowed 10 chars, other chars will be truncated) + ver1 + log-data-collection-settings: |- + # Log data collection settings + # Any errors related to config map settings can be found in the KubeMonAgentEvents table in the Log Analytics workspace that the cluster is sending data to. + + [log_collection_settings] + [log_collection_settings.multi_tenancy] + enabled = false # High log scale MUST be enabled to use this feature. Refer to https://aka.ms/cihsmode for more details on high log scale mode + disable_fallback_ingestion = false # If enabled, logs of the k8s namespaces for which ContainerLogV2Extension DCR is not configured will not be ingested to the default DCR. + + [log_collection_settings.stdout] + # In the absense of this configmap, default value for enabled is true + enabled = true + # exclude_namespaces setting holds good only if enabled is set to true + # kube-system,gatekeeper-system log collection are disabled by default in the absence of 'log_collection_settings.stdout' setting. If you want to enable kube-system,gatekeeper-system, remove them from the following setting. + # If you want to continue to disable kube-system,gatekeeper-system log collection keep the namespaces in the following setting and add any other namespace you want to disable log collection to the array. + # In the absense of this configmap, default value for exclude_namespaces = ["kube-system","gatekeeper-system"] + exclude_namespaces = ["kube-system","gatekeeper-system"] + # If you want to collect logs from only selective pods inside system namespaces add them to the following setting. Provide namepace:controllerName of the system pod. NOTE: this setting is only for pods in system namespaces + # Valid values for system namespaces are: kube-system, azure-arc, gatekeeper-system, kube-public, kube-node-lease, calico-system. The system namespace used should not be present in exclude_namespaces + # collect_system_pod_logs = ["kube-system:coredns"] + + [log_collection_settings.stderr] + # Default value for enabled is true + enabled = true + # exclude_namespaces setting holds good only if enabled is set to true + # kube-system,gatekeeper-system log collection are disabled by default in the absence of 'log_collection_settings.stderr' setting. If you want to enable kube-system,gatekeeper-system, remove them from the following setting. + # If you want to continue to disable kube-system,gatekeeper-system log collection keep the namespaces in the following setting and add any other namespace you want to disable log collection to the array. + # In the absense of this configmap, default value for exclude_namespaces = ["kube-system","gatekeeper-system"] + exclude_namespaces = ["kube-system","gatekeeper-system"] + # If you want to collect logs from only selective pods inside system namespaces add them to the following setting. Provide namepace:controllerName of the system pod. NOTE: this setting is only for pods in system namespaces + # Valid values for system namespaces are: kube-system, azure-arc, gatekeeper-system, kube-public, kube-node-lease, calico-system. The system namespace used should not be present in exclude_namespaces + # collect_system_pod_logs = ["kube-system:coredns"] + + [log_collection_settings.env_var] + # In the absense of this configmap, default value for enabled is true + enabled = true + [log_collection_settings.enrich_container_logs] + # In the absense of this configmap, default value for enrich_container_logs is false + enabled = false + # When this is enabled (enabled = true), every container log entry (both stdout & stderr) will be enriched with container Name & container Image + [log_collection_settings.collect_all_kube_events] + # In the absense of this configmap, default value for collect_all_kube_events is false + # When the setting is set to false, only the kube events with !normal event type will be collected + enabled = false + # When this is enabled (enabled = true), all kube events including normal events will be collected + [log_collection_settings.schema] + # In the absence of this configmap, default value for containerlog_schema_version is "v1" if "v2" is not enabled while onboarding + # Supported values for this setting are "v1","v2" + # See documentation at https://aka.ms/ContainerLogv2 for benefits of v2 schema over v1 schema + containerlog_schema_version = "v2" + #[log_collection_settings.enable_multiline_logs] + # fluent-bit based multiline log collection for .NET, Go, Java, and Python stacktraces. Update stacktrace_languages to specificy which languages to collect stacktraces for(valid inputs: "go", "java", "python", "dotnet"). + # NOTE: for better performance consider enabling only for languages that are needed. Dotnet is experimental and may not work in all cases. + # If enabled will also stitch together container logs split by docker/cri due to size limits(16KB per log line) up to 64 KB. + # Requires ContainerLogV2 schema to be enabled. See https://aka.ms/ContainerLogv2 for more details. + # enabled = "false" + # stacktrace_languages = [] + #[log_collection_settings.metadata_collection] + # kube_meta_cache_ttl_secs is a configurable option for K8s cached metadata. Default is 60s. You may adjust it in below section [agent_settings.k8s_metadata_config]. Reference link: https://docs.fluentbit.io/manual/pipeline/filters/kubernetes#configuration-parameters + # if enabled will collect kubernetes metadata for ContainerLogv2 schema. Default is false. + # enabled = false + # if include_fields commented out or empty, all fields will be included. If include_fields is set, only the fields listed will be included. + # include_fields = ["podLabels","podAnnotations","podUid","image","imageID","imageRepo","imageTag"] + #[log_collection_settings.filter_using_annotations] + # if enabled will exclude logs from pods with annotations fluentbit.io/exclude: "true". + # Read more: https://docs.fluentbit.io/manual/pipeline/filters/kubernetes#kubernetes-annotations + # enabled = false + + prometheus-data-collection-settings: |- + # Custom Prometheus metrics data collection settings + [prometheus_data_collection_settings.cluster] + # Cluster level scrape endpoint(s). These metrics will be scraped from agent's Replicaset (singleton) + # Any errors related to prometheus scraping can be found in the KubeMonAgentEvents table in the Log Analytics workspace that the cluster is sending data to. + + #Interval specifying how often to scrape for metrics. This is duration of time and can be specified for supporting settings by combining an integer value and time unit as a string value. Valid time units are ns, us (or µs), ms, s, m, h. + interval = "1m" + + ## Uncomment the following settings with valid string arrays for prometheus scraping + #fieldpass = ["metric_to_pass1", "metric_to_pass12"] + + #fielddrop = ["metric_to_drop"] + + # An array of urls to scrape metrics from. + # urls = ["http://myurl:9101/metrics"] + + # An array of Kubernetes services to scrape metrics from. + # kubernetes_services = ["http://my-service-dns.my-namespace:9102/metrics"] + + # When monitor_kubernetes_pods = true, prometheus sidecar container will scrape Kubernetes pods for the following prometheus annotations: + # - prometheus.io/scrape: Enable scraping for this pod + # - prometheus.io/scheme: Default is http + # - prometheus.io/path: If the metrics path is not /metrics, define it with this annotation. + # - prometheus.io/port: If port is not 9102 use this annotation + monitor_kubernetes_pods = false + + ## Restricts Kubernetes monitoring to namespaces for pods that have annotations set and are scraped using the monitor_kubernetes_pods setting. + ## This will take effect when monitor_kubernetes_pods is set to true + ## ex: monitor_kubernetes_pods_namespaces = ["default1", "default2", "default3"] + # monitor_kubernetes_pods_namespaces = ["default1"] + + ## Label selector to target pods which have the specified label + ## This will take effect when monitor_kubernetes_pods is set to true + ## Reference the docs at https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#label-selectors + # kubernetes_label_selector = "env=dev,app=nginx" + + ## Field selector to target pods which have the specified field + ## This will take effect when monitor_kubernetes_pods is set to true + ## Reference the docs at https://kubernetes.io/docs/concepts/overview/working-with-objects/field-selectors/ + ## eg. To scrape pods on a specific node + # kubernetes_field_selector = "spec.nodeName=$HOSTNAME" + + [prometheus_data_collection_settings.node] + # Node level scrape endpoint(s). These metrics will be scraped from agent's DaemonSet running in every node in the cluster + # Any errors related to prometheus scraping can be found in the KubeMonAgentEvents table in the Log Analytics workspace that the cluster is sending data to. + + #Interval specifying how often to scrape for metrics. This is duration of time and can be specified for supporting settings by combining an integer value and time unit as a string value. Valid time units are ns, us (or µs), ms, s, m, h. + interval = "1m" + + ## Uncomment the following settings with valid string arrays for prometheus scraping + + # An array of urls to scrape metrics from. $NODE_IP (all upper case) will substitute of running Node's IP address + # urls = ["http://$NODE_IP:9103/metrics"] + + #fieldpass = ["metric_to_pass1", "metric_to_pass12"] + + #fielddrop = ["metric_to_drop"] + + metric_collection_settings: |- + # Metrics collection settings for metrics sent to Log Analytics and MDM + [metric_collection_settings.collect_kube_system_pv_metrics] + # In the absense of this configmap, default value for collect_kube_system_pv_metrics is false + # When the setting is set to false, only the persistent volume metrics outside the kube-system namespace will be collected + enabled = false + # When this is enabled (enabled = true), persistent volume metrics including those in the kube-system namespace will be collected + + alertable-metrics-configuration-settings: |- + # Alertable metrics configuration settings for container resource utilization + [alertable_metrics_configuration_settings.container_resource_utilization_thresholds] + # The threshold(Type Float) will be rounded off to 2 decimal points + # Threshold for container cpu, metric will be sent only when cpu utilization exceeds or becomes equal to the following percentage + container_cpu_threshold_percentage = 95.0 + # Threshold for container memoryRss, metric will be sent only when memory rss exceeds or becomes equal to the following percentage + container_memory_rss_threshold_percentage = 95.0 + # Threshold for container memoryWorkingSet, metric will be sent only when memory working set exceeds or becomes equal to the following percentage + container_memory_working_set_threshold_percentage = 95.0 + + # Alertable metrics configuration settings for persistent volume utilization + [alertable_metrics_configuration_settings.pv_utilization_thresholds] + # Threshold for persistent volume usage bytes, metric will be sent only when persistent volume utilization exceeds or becomes equal to the following percentage + pv_usage_threshold_percentage = 60.0 + + # Alertable metrics configuration settings for completed jobs count + [alertable_metrics_configuration_settings.job_completion_threshold] + # Threshold for completed job count , metric will be sent only for those jobs which were completed earlier than the following threshold + job_completion_threshold_time_minutes = 360 + integrations: |- + [integrations.azure_network_policy_manager] + collect_basic_metrics = false + collect_advanced_metrics = false + [integrations.azure_subnet_ip_usage] + enabled = false + +# Doc - https://github.com/microsoft/Docker-Provider/blob/ci_prod/Documentation/AgentSettings/ReadMe.md + agent-settings: |- + # High log scale option for container logs high log volume scenarios. This mode is optimized for high log volume scenarios and have little higher resource utilization on low scale which will be addressed in subsequent agent releases. + # Refer to public documentation for more details - https://aka.ms/cihsmode before enabling this setting as this setting has additional dependencies such as Data Collection endpoint and Microsoft-ContainerLogV2-HighScale stream instead of Microsoft-ContainerLogV2. + [agent_settings.high_log_scale] + enabled = false + + # Retina Network Flow Logs throttle settings + # Controls the rate at which network flow log messages are processed. + # [agent_settings.networkflow_logs_config] + # throttle_enabled = true # By default is true and adjust this to control whether to enable or disable network flow log messages. + # throttle_rate = 5000 # By default is 5000 and range from 1 to 25,000 and adjust this to control the amount of messages for the time. + # throttle_window = 300 # By default is 300 and adjust this to control the amount of intervals to calculate average over. + # throttle_interval = "1s" # By default is 1s and adjust this to control time interval, expressed in "sleep" format. e.g 3s, 1.5m, 0.5h etc.. + # throttle_print = false # By default is false and adjust this to control whether to print status messages with current rate and the limits to information logs. + + # prometheus scrape fluent bit settings for high scale + # buffer size should be greater than or equal to chunk size else we set it to chunk size. + # settings scoped to prometheus sidecar container. all values in mb + [agent_settings.prometheus_fbit_settings] + tcp_listener_chunk_size = 10 + tcp_listener_buffer_size = 10 + tcp_listener_mem_buf_limit = 200 + + # prometheus scrape fluent bit settings for high scale + # buffer size should be greater than or equal to chunk size else we set it to chunk size. + # settings scoped to daemonset container. all values in mb + # [agent_settings.node_prometheus_fbit_settings] + # tcp_listener_chunk_size = 1 + # tcp_listener_buffer_size = 1 + # tcp_listener_mem_buf_limit = 10 + + # prometheus scrape fluent bit settings for high scale + # buffer size should be greater than or equal to chunk size else we set it to chunk size. + # settings scoped to replicaset container. all values in mb + # [agent_settings.cluster_prometheus_fbit_settings] + # tcp_listener_chunk_size = 1 + # tcp_listener_buffer_size = 1 + # tcp_listener_mem_buf_limit = 10 + + # The following settings are "undocumented", we don't recommend uncommenting them unless directed by Microsoft. + # They increase the maximum stdout/stderr log collection rate but will also cause higher cpu/memory usage. + ## Ref for more details about Ignore_Older - https://docs.fluentbit.io/manual/v/1.7/pipeline/inputs/tail + # [agent_settings.fbit_config] + # log_flush_interval_secs = "1" # default value is 15 + # tail_mem_buf_limit_megabytes = "10" # default value is 10 + # tail_buf_chunksize_megabytes = "1" # default value is 32kb (comment out this line for default) + # tail_buf_maxsize_megabytes = "1" # default value is 32kb (comment out this line for default) + # enable_internal_metrics = "true" # default value is false + # tail_ignore_older = "5m" # default value same as fluent-bit default i.e.0m + + # On both AKS & Arc K8s enviornments, if Cluster has configured with Forward Proxy then Proxy settings automatically applied and used for the agent + # Certain configurations, proxy config should be ignored for example Cluster with AMPLS + Proxy + # in such scenarios, use the following config to ignore proxy settings + # [agent_settings.proxy_config] + # ignore_proxy_settings = "true" # if this is not applied, default value is false + + # Disables fluent-bit for perf and container inventory for Windows + #[agent_settings.windows_fluent_bit] + # disabled = "true" + + # The following settings are "undocumented", we don't recommend uncommenting them unless directed by Microsoft. + # Configuration settings for the waittime for the network listeners to be available + # [agent_settings.network_listener_waittime] + # tcp_port_25226 = 45 # Port 25226 is used for telegraf to fluent-bit data in ReplicaSet + # tcp_port_25228 = 60 # Port 25228 is used for telegraf to fluentd data + # tcp_port_25229 = 45 # Port 25229 is used for telegraf to fluent-bit data in DaemonSet + + # The following settings are "undocumented", we don't recommend uncommenting them unless directed by Microsoft. + # [agent_settings.mdsd_config] + # monitoring_max_event_rate = "50000" # default 20K eps + # backpressure_memory_threshold_in_mb = "1500" # default 3500MB + # upload_max_size_in_mb = "20" # default 2MB + # upload_frequency_seconds = "1" # default 60 upload_frequency_seconds + # compression_level = "0" # supported levels 0 to 9 and 0 means no compression + + # Disables fluentd and uses fluent-bit for all data collection + # [agent_settings.resource_optimization] + # enabled = false # if this is not applied, default value is false + + # The following settings are "undocumented", we don't recommend uncommenting them unless directed by Microsoft. + # [agent_settings.telemetry_config] + # disable_telemetry = false # if this is not applied, default value is false + + # The following setting is for KubernetesMetadata CacheTTL Settings. + # [agent_settings.k8s_metadata_config] + # kube_meta_cache_ttl_secs = 60 # if this is not applied, default value is 60s + + # [agent_settings.chunk_config] + # PODS_CHUNK_SIZE = 10 # default value is 1000 and for large clusters with high number of pods, this can reduced to smaller value if the gaps in KubePodInventory/KubeNodeInventory data. + + [agent_settings.collect_ama_logs_process_metrics] + enabled = true + +metadata: + name: container-azm-ms-agentconfig + namespace: kube-system diff --git a/test/ginkgo-e2e/configmap/count_telegraf_process_test.go b/test/ginkgo-e2e/configmap/count_telegraf_process_test.go new file mode 100644 index 000000000..cdbc9ac3b --- /dev/null +++ b/test/ginkgo-e2e/configmap/count_telegraf_process_test.go @@ -0,0 +1,73 @@ +package configmap_test + +import ( + "fmt" + "os" + "strconv" + + "docker-provider/test/utils" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" +) + +// envInt reads an integer from an environment variable, returning defaultVal if unset or invalid. +func envInt(key string, defaultVal int) int { + v := os.Getenv(key) + if v == "" { + return defaultVal + } + n, err := strconv.Atoi(v) + if err != nil { + return defaultVal + } + return n +} + +var _ = Describe("Process count validation", Label(utils.CountTelegrafProcessLabel), func() { + var ( + expectedTelegrafDS int + expectedTelegrafRS int + expectedTelegrafPrometheus int + expectedTelegrafWindows int + ) + + BeforeEach(func() { + expectedTelegrafDS = envInt("EXPECTED_TELEGRAF_DS", 1) + expectedTelegrafRS = envInt("EXPECTED_TELEGRAF_RS", 0) + expectedTelegrafPrometheus = envInt("EXPECTED_TELEGRAF_PROMETHEUS", 0) + expectedTelegrafWindows = envInt("EXPECTED_TELEGRAF_WINDOWS", 0) + }) + + It("ama-logs DS has expected telegraf count", func() { + count, err := utils.CountProcessInstances(K8sClient, Cfg, "kube-system", + "component", "ama-logs-agent", "ama-logs", "telegraf") + Expect(err).NotTo(HaveOccurred()) + Expect(count).To(Equal(expectedTelegrafDS), + fmt.Sprintf("expected %d telegraf in ama-logs DS, got %d", expectedTelegrafDS, count)) + }) + + It("ama-logs-rs has expected telegraf count", func() { + count, err := utils.CountProcessInstances(K8sClient, Cfg, "kube-system", + "rsName", "ama-logs-rs", "ama-logs", "telegraf") + Expect(err).NotTo(HaveOccurred()) + Expect(count).To(Equal(expectedTelegrafRS), + fmt.Sprintf("expected %d telegraf in ama-logs-rs, got %d", expectedTelegrafRS, count)) + }) + + It("ama-logs-prometheus has expected telegraf count", func() { + count, err := utils.CountProcessInstances(K8sClient, Cfg, "kube-system", + "component", "ama-logs-agent", "ama-logs-prometheus", "telegraf") + Expect(err).NotTo(HaveOccurred()) + Expect(count).To(Equal(expectedTelegrafPrometheus), + fmt.Sprintf("expected %d telegraf in ama-logs-prometheus, got %d", expectedTelegrafPrometheus, count)) + }) + + It("ama-logs-windows has expected telegraf count", func() { + count, err := utils.CountWindowsProcessInstances(K8sClient, Cfg, "kube-system", + "component", "ama-logs-agent-windows", "ama-logs-windows", "telegraf") + Expect(err).NotTo(HaveOccurred()) + Expect(count).To(Equal(expectedTelegrafWindows), + fmt.Sprintf("expected %d telegraf in ama-logs-windows, got %d", expectedTelegrafWindows, count)) + }) +}) diff --git a/test/ginkgo-e2e/configmap/go.mod b/test/ginkgo-e2e/configmap/go.mod new file mode 100644 index 000000000..82cc717dd --- /dev/null +++ b/test/ginkgo-e2e/configmap/go.mod @@ -0,0 +1,74 @@ +module docker-provider/test/configmap + +go 1.26.1 + +replace docker-provider/test/utils => ../utils + +require ( + docker-provider/test/utils v0.0.0 + github.com/onsi/ginkgo/v2 v2.27.2 + github.com/onsi/gomega v1.38.2 + k8s.io/client-go v0.35.3 +) + +require ( + github.com/Azure/azure-sdk-for-go/sdk/azcore v1.17.0 // indirect + github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.2 // indirect + github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 // indirect + github.com/Azure/azure-sdk-for-go/sdk/monitor/azquery v1.1.0 // indirect + github.com/AzureAD/microsoft-authentication-library-for-go v1.3.3 // indirect + github.com/Masterminds/semver/v3 v3.4.0 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/emicklei/go-restful/v3 v3.12.2 // indirect + github.com/fxamacker/cbor/v2 v2.9.0 // indirect + github.com/ghodss/yaml v1.0.0 // indirect + github.com/go-logr/logr v1.4.3 // indirect + github.com/go-openapi/jsonpointer v0.21.0 // indirect + github.com/go-openapi/jsonreference v0.20.2 // indirect + github.com/go-openapi/swag v0.23.0 // indirect + github.com/go-task/slim-sprig/v3 v3.0.0 // indirect + github.com/golang-jwt/jwt/v5 v5.2.2 // indirect + github.com/google/gnostic-models v0.7.0 // indirect + github.com/google/go-cmp v0.7.0 // indirect + github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 // indirect + github.com/google/uuid v1.6.0 // indirect + github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 // indirect + github.com/josharian/intern v1.0.0 // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/kylelemons/godebug v1.1.0 // indirect + github.com/mailru/easyjson v0.7.7 // indirect + github.com/moby/spdystream v0.5.0 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect + github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect + github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect + github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect + github.com/spf13/pflag v1.0.9 // indirect + github.com/x448/float16 v0.8.4 // indirect + go.yaml.in/yaml/v2 v2.4.3 // indirect + go.yaml.in/yaml/v3 v3.0.4 // indirect + golang.org/x/crypto v0.44.0 // indirect + golang.org/x/mod v0.29.0 // indirect + golang.org/x/net v0.47.0 // indirect + golang.org/x/oauth2 v0.30.0 // indirect + golang.org/x/sync v0.18.0 // indirect + golang.org/x/sys v0.38.0 // indirect + golang.org/x/term v0.37.0 // indirect + golang.org/x/text v0.31.0 // indirect + golang.org/x/time v0.9.0 // indirect + golang.org/x/tools v0.38.0 // indirect + google.golang.org/protobuf v1.36.8 // indirect + gopkg.in/evanphx/json-patch.v4 v4.13.0 // indirect + gopkg.in/inf.v0 v0.9.1 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + k8s.io/api v0.35.3 // indirect + k8s.io/apimachinery v0.35.3 // indirect + k8s.io/klog/v2 v2.130.1 // indirect + k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912 // indirect + k8s.io/utils v0.0.0-20251002143259-bc988d571ff4 // indirect + sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect + sigs.k8s.io/randfill v1.0.0 // indirect + sigs.k8s.io/structured-merge-diff/v6 v6.3.0 // indirect + sigs.k8s.io/yaml v1.6.0 // indirect +) diff --git a/test/ginkgo-e2e/configmap/go.sum b/test/ginkgo-e2e/configmap/go.sum new file mode 100644 index 000000000..1a4d6f2c2 --- /dev/null +++ b/test/ginkgo-e2e/configmap/go.sum @@ -0,0 +1,194 @@ +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.17.0 h1:g0EZJwz7xkXQiZAI5xi9f3WWFYBlX1CPTrR+NDToRkQ= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.17.0/go.mod h1:XCW7KnZet0Opnr7HccfUw1PLc4CjHqpcaxW8DHklNkQ= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.2 h1:F0gBpfdPLGsw+nsgk6aqqkZS1jiixa5WwFe3fk/T3Ys= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.2/go.mod h1:SqINnQ9lVVdRlyC8cd1lCI0SdX4n2paeABd2K8ggfnE= +github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.2 h1:yz1bePFlP5Vws5+8ez6T3HWXPmwOK7Yvq8QxDBD3SKY= +github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.2/go.mod h1:Pa9ZNPuoNu/GztvBSKk9J1cDJW6vk/n0zLtV4mgd8N8= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 h1:ywEEhmNahHBihViHepv3xPBn1663uRv2t2q/ESv9seY= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0/go.mod h1:iZDifYGJTIgIIkYRNWPENUnqx6bJ2xnSDFI2tjwZNuY= +github.com/Azure/azure-sdk-for-go/sdk/monitor/azquery v1.1.0 h1:l+LIDHsZkFBiipIKhOn3m5/2MX4bwNwHYWyNulPaTis= +github.com/Azure/azure-sdk-for-go/sdk/monitor/azquery v1.1.0/go.mod h1:BjVVBLUiZ/qR2a4PAhjs8uGXNfStD0tSxgxCMfcVRT8= +github.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1 h1:WJTmL004Abzc5wDB5VtZG2PJk5ndYDgVacGqfirKxjM= +github.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1/go.mod h1:tCcJZ0uHAmvjsVYzEFivsRTN00oz5BEsRgQHu5JZ9WE= +github.com/AzureAD/microsoft-authentication-library-for-go v1.3.3 h1:H5xDQaE3XowWfhZRUpnfC+rGZMEVoSiji+b+/HFAPU4= +github.com/AzureAD/microsoft-authentication-library-for-go v1.3.3/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI= +github.com/Masterminds/semver/v3 v3.4.0 h1:Zog+i5UMtVoCU8oKka5P7i9q9HgrJeGzI9SA1Xbatp0= +github.com/Masterminds/semver/v3 v3.4.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM= +github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= +github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= +github.com/emicklei/go-restful/v3 v3.12.2 h1:DhwDP0vY3k8ZzE0RunuJy8GhNpPL6zqLkDf9B/a0/xU= +github.com/emicklei/go-restful/v3 v3.12.2/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= +github.com/fxamacker/cbor/v2 v2.9.0 h1:NpKPmjDBgUfBms6tr6JZkTHtfFGcMKsw3eGcmD/sapM= +github.com/fxamacker/cbor/v2 v2.9.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ= +github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/gkampitakis/ciinfo v0.3.2 h1:JcuOPk8ZU7nZQjdUhctuhQofk7BGHuIy0c9Ez8BNhXs= +github.com/gkampitakis/ciinfo v0.3.2/go.mod h1:1NIwaOcFChN4fa/B0hEBdAb6npDlFL8Bwx4dfRLRqAo= +github.com/gkampitakis/go-diff v1.3.2 h1:Qyn0J9XJSDTgnsgHRdz9Zp24RaJeKMUHg2+PDZZdC4M= +github.com/gkampitakis/go-diff v1.3.2/go.mod h1:LLgOrpqleQe26cte8s36HTWcTmMEur6OPYerdAAS9tk= +github.com/gkampitakis/go-snaps v0.5.15 h1:amyJrvM1D33cPHwVrjo9jQxX8g/7E2wYdZ+01KS3zGE= +github.com/gkampitakis/go-snaps v0.5.15/go.mod h1:HNpx/9GoKisdhw9AFOBT1N7DBs9DiHo/hGheFGBZ+mc= +github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= +github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= +github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ= +github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY= +github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE= +github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= +github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= +github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE= +github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= +github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= +github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= +github.com/goccy/go-yaml v1.18.0 h1:8W7wMFS12Pcas7KU+VVkaiCng+kG8QiFeFwzFb+rwuw= +github.com/goccy/go-yaml v1.18.0/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA= +github.com/golang-jwt/jwt/v5 v5.2.2 h1:Rl4B7itRWVtYIHFrSNd7vhTiz9UpLdi6gZhZ3wEeDy8= +github.com/golang-jwt/jwt/v5 v5.2.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= +github.com/google/gnostic-models v0.7.0 h1:qwTtogB15McXDaNqTZdzPJRHvaVJlAl+HVQnLmJEJxo= +github.com/google/gnostic-models v0.7.0/go.mod h1:whL5G0m6dmc5cPxKc5bdKdEN3UjI7OUGxBlw57miDrQ= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 h1:BHT72Gu3keYf3ZEu2J0b1vyeLSOYI8bm5wbJM/8yDe8= +github.com/google/pprof v0.0.0-20250403155104-27863c87afa6/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 h1:JeSE6pjso5THxAzdVpqr6/geYxZytqFMBCOtn/ujyeo= +github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674/go.mod h1:r4w70xmWCQKmi1ONH4KIaBptdivuRPyosB9RmPlGEwA= +github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= +github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= +github.com/joshdk/go-junit v1.0.0 h1:S86cUKIdwBHWwA6xCmFlf3RTLfVXYQfvanM5Uh+K6GE= +github.com/joshdk/go-junit v1.0.0/go.mod h1:TiiV0PqkaNfFXjEiyjWM3XXrhVyCa1K4Zfga6W52ung= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/keybase/go-keychain v0.0.0-20231219164618-57a3676c3af6 h1:IsMZxCuZqKuao2vNdfD82fjjgPLfyHLpR41Z88viRWs= +github.com/keybase/go-keychain v0.0.0-20231219164618-57a3676c3af6/go.mod h1:3VeWNIJaW+O5xpRQbPp0Ybqu1vJd/pm7s2F473HRrkw= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= +github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= +github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= +github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/maruel/natural v1.1.1 h1:Hja7XhhmvEFhcByqDoHz9QZbkWey+COd9xWfCfn1ioo= +github.com/maruel/natural v1.1.1/go.mod h1:v+Rfd79xlw1AgVBjbO0BEQmptqb5HvL/k9GRHB7ZKEg= +github.com/mfridman/tparse v0.18.0 h1:wh6dzOKaIwkUGyKgOntDW4liXSo37qg5AXbIhkMV3vE= +github.com/mfridman/tparse v0.18.0/go.mod h1:gEvqZTuCgEhPbYk/2lS3Kcxg1GmTxxU7kTC8DvP0i/A= +github.com/moby/spdystream v0.5.0 h1:7r0J1Si3QO/kjRitvSLVVFUjxMEb/YLj6S9FF62JBCU= +github.com/moby/spdystream v0.5.0/go.mod h1:xBAYlnt/ay+11ShkdFKNAG7LsyK/tmNBVvVOwrfMgdI= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8= +github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f h1:y5//uYreIhSUg3J1GEMiLbxo1LJaP8RfCpH6pymGZus= +github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= +github.com/onsi/ginkgo/v2 v2.27.2 h1:LzwLj0b89qtIy6SSASkzlNvX6WktqurSHwkk2ipF/Ns= +github.com/onsi/ginkgo/v2 v2.27.2/go.mod h1:ArE1D/XhNXBXCBkKOLkbsb2c81dQHCRcF5zwn/ykDRo= +github.com/onsi/gomega v1.38.2 h1:eZCjf2xjZAqe+LeWvKb5weQ+NcPwX84kqJ0cZNxok2A= +github.com/onsi/gomega v1.38.2/go.mod h1:W2MJcYxRGV63b418Ai34Ud0hEdTVXq9NW9+Sx6uXf3k= +github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ= +github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/redis/go-redis/v9 v9.7.0 h1:HhLSs+B6O021gwzl+locl0zEDnyNkxMtf/Z3NNBMa9E= +github.com/redis/go-redis/v9 v9.7.0/go.mod h1:f6zhXITC7JUJIlPEiBOTXxJgPLdZcA93GewI7inzyWw= +github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= +github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= +github.com/spf13/pflag v1.0.9 h1:9exaQaMOCwffKiiiYk6/BndUBv+iRViNW+4lEMi0PvY= +github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= +github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= +github.com/tidwall/gjson v1.18.0 h1:FIDeeyB800efLX89e5a8Y0BNH+LOngJyGrIWxG2FKQY= +github.com/tidwall/gjson v1.18.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= +github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= +github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4= +github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= +github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY= +github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28= +github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= +github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= +go.yaml.in/yaml/v2 v2.4.3 h1:6gvOSjQoTB3vt1l+CU+tSyi/HOjfOjRLJ4YwYZGwRO0= +go.yaml.in/yaml/v2 v2.4.3/go.mod h1:zSxWcmIDjOzPXpjlTTbAsKokqkDNAVtZO0WOMiT90s8= +go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= +go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= +golang.org/x/crypto v0.44.0 h1:A97SsFvM3AIwEEmTBiaxPPTYpDC47w720rdiiUvgoAU= +golang.org/x/crypto v0.44.0/go.mod h1:013i+Nw79BMiQiMsOPcVCB5ZIJbYkerPrGnOa00tvmc= +golang.org/x/mod v0.29.0 h1:HV8lRxZC4l2cr3Zq1LvtOsi/ThTgWnUk/y64QSs8GwA= +golang.org/x/mod v0.29.0/go.mod h1:NyhrlYXJ2H4eJiRy/WDBO6HMqZQ6q9nk4JzS3NuCK+w= +golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY= +golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU= +golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI= +golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU= +golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I= +golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= +golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc= +golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/term v0.37.0 h1:8EGAD0qCmHYZg6J17DvsMy9/wJ7/D/4pV/wfnld5lTU= +golang.org/x/term v0.37.0/go.mod h1:5pB4lxRNYYVZuTLmy8oR2BH8dflOR+IbTYFD8fi3254= +golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM= +golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM= +golang.org/x/time v0.9.0 h1:EsRrnYcQiGH+5FfbgvV4AP7qEZstoyrHB0DzarOQ4ZY= +golang.org/x/time v0.9.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/tools v0.38.0 h1:Hx2Xv8hISq8Lm16jvBZ2VQf+RLmbd7wVUsALibYI/IQ= +golang.org/x/tools v0.38.0/go.mod h1:yEsQ/d/YK8cjh0L6rZlY8tgtlKiBNTL14pGDJPJpYQs= +google.golang.org/protobuf v1.36.8 h1:xHScyCOEuuwZEc6UtSOvPbAT4zRh0xcNRYekJwfqyMc= +google.golang.org/protobuf v1.36.8/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/evanphx/json-patch.v4 v4.13.0 h1:czT3CmqEaQ1aanPc5SdlgQrrEIb8w/wwCvWWnfEbYzo= +gopkg.in/evanphx/json-patch.v4 v4.13.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M= +gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= +gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +k8s.io/api v0.35.3 h1:pA2fiBc6+N9PDf7SAiluKGEBuScsTzd2uYBkA5RzNWQ= +k8s.io/api v0.35.3/go.mod h1:9Y9tkBcFwKNq2sxwZTQh1Njh9qHl81D0As56tu42GA4= +k8s.io/apimachinery v0.35.3 h1:MeaUwQCV3tjKP4bcwWGgZ/cp/vpsRnQzqO6J6tJyoF8= +k8s.io/apimachinery v0.35.3/go.mod h1:jQCgFZFR1F4Ik7hvr2g84RTJSZegBc8yHgFWKn//hns= +k8s.io/client-go v0.35.3 h1:s1lZbpN4uI6IxeTM2cpdtrwHcSOBML1ODNTCCfsP1pg= +k8s.io/client-go v0.35.3/go.mod h1:RzoXkc0mzpWIDvBrRnD+VlfXP+lRzqQjCmKtiwZ8Q9c= +k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk= +k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= +k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912 h1:Y3gxNAuB0OBLImH611+UDZcmKS3g6CthxToOb37KgwE= +k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912/go.mod h1:kdmbQkyfwUagLfXIad1y2TdrjPFWp2Q89B3qkRwf/pQ= +k8s.io/utils v0.0.0-20251002143259-bc988d571ff4 h1:SjGebBtkBqHFOli+05xYbK8YF1Dzkbzn+gDM4X9T4Ck= +k8s.io/utils v0.0.0-20251002143259-bc988d571ff4/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 h1:IpInykpT6ceI+QxKBbEflcR5EXP7sU1kvOlxwZh5txg= +sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg= +sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU= +sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= +sigs.k8s.io/structured-merge-diff/v6 v6.3.0 h1:jTijUJbW353oVOd9oTlifJqOGEkUw2jB/fXCbTiQEco= +sigs.k8s.io/structured-merge-diff/v6 v6.3.0/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE= +sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs= +sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4= diff --git a/test/ginkgo-e2e/configmap/suite_test.go b/test/ginkgo-e2e/configmap/suite_test.go new file mode 100644 index 000000000..254820ccd --- /dev/null +++ b/test/ginkgo-e2e/configmap/suite_test.go @@ -0,0 +1,26 @@ +package configmap_test + +import ( + "testing" + + "docker-provider/test/utils" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "k8s.io/client-go/kubernetes" + "k8s.io/client-go/rest" +) + +var K8sClient *kubernetes.Clientset +var Cfg *rest.Config + +func TestConfigmap(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "Configmap Test Suite") +} + +var _ = BeforeSuite(func() { + var err error + K8sClient, Cfg, err = utils.SetupKubernetesClient() + Expect(err).NotTo(HaveOccurred()) +}) diff --git a/test/ginkgo-e2e/utils/constants.go b/test/ginkgo-e2e/utils/constants.go index a5bb73f86..ca8a1e9f5 100644 --- a/test/ginkgo-e2e/utils/constants.go +++ b/test/ginkgo-e2e/utils/constants.go @@ -18,9 +18,10 @@ var ( ) const ( - WindowsLabel = "windows" - ARM64Label = "arm64" - FIPSLabel = "fips" + WindowsLabel = "windows" + ARM64Label = "arm64" + FIPSLabel = "fips" + CountTelegrafProcessLabel = "count-telegraf-process" // also referenced in testkube-test-crs.yaml // IntermittentErrorThreshold is the maximum number of occurrences allowed for expected intermittent errors IntermittentErrorThreshold = 10 diff --git a/test/ginkgo-e2e/utils/kubernetes_api_utils.go b/test/ginkgo-e2e/utils/kubernetes_api_utils.go index ae795e989..a87c59f67 100644 --- a/test/ginkgo-e2e/utils/kubernetes_api_utils.go +++ b/test/ginkgo-e2e/utils/kubernetes_api_utils.go @@ -548,6 +548,68 @@ func GetAllNodes(clientset *kubernetes.Clientset) ([]corev1.Node, error) { return nodes.Items, nil } +// getFirstRunningPod returns the first pod in Running phase from the list. +func getFirstRunningPod(pods []corev1.Pod) (corev1.Pod, error) { + for _, pod := range pods { + if pod.Status.Phase == corev1.PodRunning { + return pod, nil + } + } + return corev1.Pod{}, fmt.Errorf("no running pods found (total pods: %d)", len(pods)) +} + +// CountProcessInstances counts instances of a process in a Linux container. +// Returns the count from the first running pod. +func CountProcessInstances(client *kubernetes.Clientset, config *rest.Config, + namespace, labelName, labelValue, containerName, processName string) (int, error) { + + pods, err := GetPodsWithLabel(client, namespace, labelName, labelValue) + if err != nil { + return 0, err + } + pod, err := getFirstRunningPod(pods) + if err != nil { + return 0, err + } + + command := []string{"bash", "-c", + fmt.Sprintf("ps aux | grep '%s' | grep -v grep | wc -l", processName)} + stdout, _, err := ExecCmd(client, config, pod.Name, containerName, namespace, command) + if err != nil { + return 0, err + } + + count := 0 + fmt.Sscanf(strings.TrimSpace(stdout), "%d", &count) + return count, nil +} + +// CountWindowsProcessInstances counts instances of a process in a Windows container using PowerShell. +// Returns the count from the first running pod. +func CountWindowsProcessInstances(client *kubernetes.Clientset, config *rest.Config, + namespace, labelName, labelValue, containerName, processName string) (int, error) { + + pods, err := GetPodsWithLabel(client, namespace, labelName, labelValue) + if err != nil { + return 0, err + } + pod, err := getFirstRunningPod(pods) + if err != nil { + return 0, err + } + + command := []string{"powershell", "-Command", + fmt.Sprintf("@(Get-Process -Name '%s' -ErrorAction SilentlyContinue).Count", processName)} + stdout, _, err := ExecCmd(client, config, pod.Name, containerName, namespace, command) + if err != nil { + return 0, err + } + + count := 0 + fmt.Sscanf(strings.TrimSpace(stdout), "%d", &count) + return count, nil +} + // CheckFileForErrors checks if a specific file in a linux container contains errors. // It tolerates intermittent errors up to 10 occurrences per pattern. func CheckFileForErrors(clientset *kubernetes.Clientset, Cfg *rest.Config, namespace, labelName, labelValue, containerName, filePath string) error { diff --git a/test/testkube/configmap-test-matrix.yaml b/test/testkube/configmap-test-matrix.yaml new file mode 100644 index 000000000..89de232ac --- /dev/null +++ b/test/testkube/configmap-test-matrix.yaml @@ -0,0 +1,52 @@ +# configmap-test-matrix.yaml +# Declarative test matrix for ama-logs ConfigMap tests. +# Each case: apply a configmap, then run workflows with specified params. +# +# Schema: +# defaults.params — merged into every workflow (lowest priority) +# defaults. — reusable workflow groups, included via "- name: " +# case-level params — merged into all workflows in that case (overrides defaults) +# workflow params — merged last (highest priority) +# configmap — path relative to repo root; kubectl apply -f then wait +# defaults.wait_seconds — global wait time after applying configmap (default: 60) +# case-level wait_seconds — per-case override + +defaults: + wait_seconds: 600 + params: + GOTOOLCHAIN: "auto" + common_workflows: + - name: querylogs + params: + AZURE_TENANT_ID: ${AZURE_TENANT_ID} + AZURE_CLIENT_ID: ${AZURE_CLIENT_ID} + GENEVA_INTEGRATION: false + - name: containerstatus-linux + common_workflows_test_only: + - name: containerstatus-windows + + +cases: + - name: process-metrics-enabled + configmap: test/configmaps/config-tests/container-azm-ms-agentconfig-process-metrics-enabled.yaml + workflows: + - name: count-telegraf-process + params: + EXPECTED_TELEGRAF_DS: "2" + EXPECTED_TELEGRAF_RS: "1" + EXPECTED_TELEGRAF_PROMETHEUS: "1" + EXPECTED_TELEGRAF_WINDOWS: "1" + - name: common_workflows + - name: common_workflows_test_only + + - name: process-metrics-default + configmap: kubernetes/container-azm-ms-agentconfig.yaml + workflows: + - name: count-telegraf-process + params: + EXPECTED_TELEGRAF_DS: "1" + EXPECTED_TELEGRAF_RS: "0" + EXPECTED_TELEGRAF_PROMETHEUS: "0" + EXPECTED_TELEGRAF_WINDOWS: "0" + - name: common_workflows + - name: common_workflows_test_only diff --git a/test/testkube/run-configmap-test-case.sh b/test/testkube/run-configmap-test-case.sh new file mode 100644 index 000000000..c00bbccfe --- /dev/null +++ b/test/testkube/run-configmap-test-case.sh @@ -0,0 +1,156 @@ +#!/bin/bash +# run-matrix-tests.sh +# Reads a single case from configmap-test-matrix.yaml, applies its configmap, +# and runs all workflows for that case with merged params. +# +# Usage: ./run-matrix-tests.sh --case [--matrix ] [--repo-root ] + +set -euo pipefail + +MATRIX_FILE="./configmap-test-matrix.yaml" +REPO_ROOT="${BUILD_SOURCESDIRECTORY:-$(cd ../.. && pwd)}" +CASE_NAME="" + +# ── Parse arguments ────────────────────────────────────────── +while [[ $# -gt 0 ]]; do + case "$1" in + --matrix) MATRIX_FILE="$2"; shift 2 ;; + --repo-root) REPO_ROOT="$2"; shift 2 ;; + --case) CASE_NAME="$2"; shift 2 ;; + *) echo "Unknown argument: $1"; exit 1 ;; + esac +done + +if [[ -z "$CASE_NAME" ]]; then + echo "Error: --case is required" + exit 1 +fi + +# ── Ensure yq is available ─────────────────────────────────── +if ! command -v yq &>/dev/null; then + echo "Installing yq..." + sudo wget -qO /usr/local/bin/yq \ + https://github.com/mikefarah/yq/releases/download/v4.44.1/yq_linux_amd64 + sudo chmod +x /usr/local/bin/yq +fi + +echo "Matrix file: ${MATRIX_FILE}" +echo "Repo root: ${REPO_ROOT}" +echo "Case: ${CASE_NAME}" +echo "" + +# ── Find the case ─────────────────────────────────────────── +case_index=$(yq ".cases | to_entries | .[] | select(.value.name == \"${CASE_NAME}\") | .key" "$MATRIX_FILE") +if [[ -z "$case_index" ]]; then + echo "Error: case '${CASE_NAME}' not found in ${MATRIX_FILE}" + echo "Available cases:" + yq '.cases[].name' "$MATRIX_FILE" + exit 1 +fi + +# ── Read case data ────────────────────────────────────────── +default_params=$(yq -o=json '.defaults.params // {}' "$MATRIX_FILE") +default_wait=$(yq '.defaults.wait_seconds // 60' "$MATRIX_FILE") +configmap=$(yq ".cases[${case_index}].configmap // \"\"" "$MATRIX_FILE") +case_params=$(yq -o=json ".cases[${case_index}].params // {}" "$MATRIX_FILE") +wait_seconds=$(yq ".cases[${case_index}].wait_seconds // ${default_wait}" "$MATRIX_FILE") + +# Expand workflow groups: any workflow name matching a key under "defaults" gets replaced +case_workflows=$(yq -o=json ".cases[${case_index}].workflows // []" "$MATRIX_FILE") +defaults_json=$(yq -o=json '.defaults // {}' "$MATRIX_FILE") +all_workflows=$(jq -n --argjson wfs "$case_workflows" --argjson defaults "$defaults_json" ' + [($wfs[] | if $defaults[.name] then $defaults[.name][] else . end)] +') +wf_count=$(echo "$all_workflows" | jq 'length') + +echo "==========================================" +echo "Case: ${CASE_NAME}" +echo "==========================================" +echo "Workflows to run (${wf_count}):" +for (( i=0; i actual value) + val=$(echo "$val" | envsubst) + config_flags+=" --config ${key}=${val}" + done < <(echo "$merged" | jq -r 'keys[]') + + echo "" + echo " Running workflow: ${wf_name}" + echo " Config: ${config_flags}" + kubectl testkube run testworkflow "${wf_name}" ${config_flags} --verbose + + echo " Waiting for execution to be created..." + sleep 5 + + execution_id=$(kubectl testkube get testworkflowexecution | grep -i "${wf_name}" | head -n 1 | awk '{print $1}') + echo " Execution ID: ${execution_id}" + + if [[ -z "${execution_id}" ]]; then + echo " Error: Could not find execution ID for ${wf_name}" + failed+=("$wf_name") + continue + fi + + kubectl testkube watch testworkflowexecution "${execution_id}" + kubectl testkube get testworkflowexecution "${execution_id}" --output json > "testkube-results-${wf_name}.json" + + if ! jq empty "testkube-results-${wf_name}.json" 2>/dev/null; then + echo " Error: Failed to get valid JSON results for ${wf_name}" + cat "testkube-results-${wf_name}.json" + failed+=("$wf_name") + continue + fi + + result_status=$(jq -r '.result.status' "testkube-results-${wf_name}.json") + if [[ "${result_status}" == "failed" ]]; then + echo " FAILED: ${wf_name} (execution: ${execution_id})" + kubectl testkube get testworkflowexecution "${execution_id}" --logs-only || true + failed+=("$wf_name") + else + echo " PASSED: ${wf_name} (execution: ${execution_id})" + passed+=("$wf_name") + fi +done + +# ── Summary ───────────────────────────────────────────────── +echo "" +echo "==========================================" +echo "${CASE_NAME} Summary (${#passed[@]} passed, ${#failed[@]} failed out of ${wf_count})" +echo "==========================================" +if [[ ${#passed[@]} -gt 0 ]]; then + echo "Passed:" + for wf in "${passed[@]}"; do echo " - $wf"; done +fi +if [[ ${#failed[@]} -gt 0 ]]; then + echo "Failed:" + for wf in "${failed[@]}"; do echo " - $wf"; done + exit 1 +fi +echo "All workflows passed." diff --git a/test/testkube/testkube-test-crs.yaml b/test/testkube/testkube-test-crs.yaml index f3ce2d65e..ee2a038aa 100644 --- a/test/testkube/testkube-test-crs.yaml +++ b/test/testkube/testkube-test-crs.yaml @@ -148,6 +148,58 @@ spec: - name: GOTOOLCHAIN value: "{{config.GOTOOLCHAIN}}" shell: ginkgo ./querylogs + pod: + nodeSelector: + kubernetes.io/os: linux + kubernetes.io/arch: amd64 +--- +apiVersion: testworkflows.testkube.io/v1 +kind: TestWorkflow +metadata: + name: count-telegraf-process + namespace: testkube + labels: + test-type: ginkgo-test +spec: + config: + EXPECTED_TELEGRAF_DS: + type: string + default: "1" + EXPECTED_TELEGRAF_RS: + type: string + default: "0" + EXPECTED_TELEGRAF_PROMETHEUS: + type: string + default: "0" + EXPECTED_TELEGRAF_WINDOWS: + type: string + default: "0" + GOTOOLCHAIN: + type: string + default: "" + content: + git: + uri: https://github.com/microsoft/Docker-Provider/ + revision: zane/configmap-testing-pipeline + paths: + - test/ginkgo-e2e + steps: + - name: Run test + container: + workingDir: /data/repo/test/ginkgo-e2e + image: cerebro31/ginkgo-test:latest + env: + - name: EXPECTED_TELEGRAF_DS + value: "{{config.EXPECTED_TELEGRAF_DS}}" + - name: EXPECTED_TELEGRAF_RS + value: "{{config.EXPECTED_TELEGRAF_RS}}" + - name: EXPECTED_TELEGRAF_PROMETHEUS + value: "{{config.EXPECTED_TELEGRAF_PROMETHEUS}}" + - name: EXPECTED_TELEGRAF_WINDOWS + value: "{{config.EXPECTED_TELEGRAF_WINDOWS}}" + - name: GOTOOLCHAIN + value: "{{config.GOTOOLCHAIN}}" + shell: ginkgo --label-filter="count-telegraf-process" ./configmap pod: nodeSelector: kubernetes.io/os: linux