From 4ba2510f88b8775501099a943df5e1082cf34815 Mon Sep 17 00:00:00 2001 From: Irfan Paraniya Date: Mon, 15 Jun 2026 04:59:04 +0000 Subject: [PATCH 01/16] docs: Add global OTEL extension and backend service to Argo template --- README.md | 5 +++ argocd.yaml.tpl | 98 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 103 insertions(+) diff --git a/README.md b/README.md index a0dffa2..d555c8f 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,11 @@ wget -O argocd.yaml https://raw.githubusercontent.com/GlueOps/docs-argocd/main/a - Replace `placeholder_tenant_key` with your tenant/company key. Example: `antoniostacos` - Replace `placeholder_cluster_environment` with your cluster_environment name. Example: `nonprod` - The `placeholder_argocd_oidc_client_secret_from_dex` that you specify needs to be the same one you use in the `platform.yaml` for ArgoCD. If they do not match you will not be able to login. + - Global OTEL extension placeholders: + - Replace `placeholder_otel_extension_version` with the extension release tag (example: `v0.1.0`). + - Replace `placeholder_otel_backend_tag` with the backend API image tag. + - Replace `placeholder_tempo_base_url` with your in-cluster Tempo endpoint. + - The OTEL extension is defined in `argocd.yaml` and loaded by ArgoCD itself, so it is global for all Argo applications without changing app templates. - Install ArgoCD diff --git a/argocd.yaml.tpl b/argocd.yaml.tpl index 0c915a7..0fc8267 100644 --- a/argocd.yaml.tpl +++ b/argocd.yaml.tpl @@ -165,6 +165,7 @@ applicationSet: configs: params: server.insecure: true + server.enable.proxy.extension: true cm: # @ignored timeout.reconciliation: 10s @@ -217,6 +218,12 @@ configs: clientID: argocd clientSecret: placeholder_argocd_oidc_client_secret_from_dex redirectURI: https://argocd.placeholder_cluster_environment.placeholder_tenant_key.placeholder_glueops_root_domain/api/dex/callback + extension.config: | + extensions: + - name: otel-extension + backend: + services: + - url: http://otel-extension-api.glueops-core.svc.cluster.local:8000 rbac: # -- A good reference for this is: https://argo-cd.readthedocs.io/en/stable/operator-manual/rbac/ # This default policy is for GlueOps orgs/teams only. Please change it to reflect your own orgs/teams. @@ -224,8 +231,21 @@ configs: # @default -- `''` (See [values.yaml]) policy.csv: | placeholder_argocd_rbac_policies + p, role:readonly, extensions, invoke, otel-extension, allow + p, role:admin, extensions, invoke, otel-extension, allow # @ignored server: + extensions: + enabled: true + extensionList: + - name: otel-extension + env: + - name: EXTENSION_URL + value: "https://github.com/GlueOps/argo-cd-ui-extention/releases/download/placeholder_otel_extension_version/extension.tar.gz" + - name: EXTENSION_VERSION + value: "placeholder_otel_extension_version" + - name: EXTENSION_ENABLED + value: "true" # @ignored affinity: nodeAffinity: @@ -297,6 +317,84 @@ extraObjects: port: number: 80 + - apiVersion: apps/v1 + kind: Deployment + metadata: + name: otel-extension-api + namespace: glueops-core + labels: + app.kubernetes.io/name: otel-extension-api + spec: + replicas: 2 + selector: + matchLabels: + app.kubernetes.io/name: otel-extension-api + template: + metadata: + labels: + app.kubernetes.io/name: otel-extension-api + spec: + nodeSelector: + glueops.dev/role: glueops-platform + tolerations: + - key: "glueops.dev/role" + operator: "Equal" + value: "glueops-platform" + effect: "NoSchedule" + containers: + - name: otel-extension-api + image: "ghcr.repo.gpkg.io/glueops/argocd-otel-extension-api:placeholder_otel_backend_tag" + imagePullPolicy: IfNotPresent + ports: + - name: http + containerPort: 8000 + protocol: TCP + env: + - name: PORT + value: "8000" + - name: PROMETHEUS_BASE_URL + value: "http://kps-prometheus.glueops-core-kube-prometheus-stack.svc.cluster.local:9090" + - name: TEMPO_BASE_URL + value: "placeholder_tempo_base_url" + - name: LOG_LEVEL + value: "INFO" + readinessProbe: + httpGet: + path: /healthz + port: http + initialDelaySeconds: 5 + periodSeconds: 10 + livenessProbe: + httpGet: + path: /healthz + port: http + initialDelaySeconds: 15 + periodSeconds: 20 + resources: + requests: + cpu: 50m + memory: 64Mi + limits: + cpu: 250m + memory: 256Mi + + - apiVersion: v1 + kind: Service + metadata: + name: otel-extension-api + namespace: glueops-core + labels: + app.kubernetes.io/name: otel-extension-api + spec: + type: ClusterIP + selector: + app.kubernetes.io/name: otel-extension-api + ports: + - name: http + port: 8000 + targetPort: http + protocol: TCP + - apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: From 0589ad9ca3671f90af56da3870816abd7e81f0d1 Mon Sep 17 00:00:00 2001 From: Irfan Paraniya Date: Mon, 15 Jun 2026 05:37:16 +0000 Subject: [PATCH 02/16] fix: update OTEL extension version and backend image tag to v0.1.1 --- argocd.yaml.tpl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/argocd.yaml.tpl b/argocd.yaml.tpl index 0fc8267..06e7ef2 100644 --- a/argocd.yaml.tpl +++ b/argocd.yaml.tpl @@ -241,9 +241,9 @@ server: - name: otel-extension env: - name: EXTENSION_URL - value: "https://github.com/GlueOps/argo-cd-ui-extention/releases/download/placeholder_otel_extension_version/extension.tar.gz" + value: "https://github.com/GlueOps/argo-cd-ui-extention/releases/download/v0.1.1/extension.tar.gz" - name: EXTENSION_VERSION - value: "placeholder_otel_extension_version" + value: "0.1.1" - name: EXTENSION_ENABLED value: "true" # @ignored @@ -343,7 +343,7 @@ extraObjects: effect: "NoSchedule" containers: - name: otel-extension-api - image: "ghcr.repo.gpkg.io/glueops/argocd-otel-extension-api:placeholder_otel_backend_tag" + image: "ghcr.repo.gpkg.io/glueops/argocd-otel-extension-api:v0.1.1" imagePullPolicy: IfNotPresent ports: - name: http From 7e3ec12764e3aa20ffad172a3551c92080db1e48 Mon Sep 17 00:00:00 2001 From: Irfan Paraniya Date: Mon, 15 Jun 2026 06:01:00 +0000 Subject: [PATCH 03/16] feat: add global OTEL extension configuration and variables for ArgoCD --- README.md | 13 +++-- argocd.yaml.tpl | 14 +++--- main.tf | 125 ++++++++++++++++++++++++++++++++++++++++++------ 3 files changed, 127 insertions(+), 25 deletions(-) diff --git a/README.md b/README.md index d555c8f..1fdd083 100644 --- a/README.md +++ b/README.md @@ -17,10 +17,11 @@ wget -O argocd.yaml https://raw.githubusercontent.com/GlueOps/docs-argocd/main/a - Replace `placeholder_tenant_key` with your tenant/company key. Example: `antoniostacos` - Replace `placeholder_cluster_environment` with your cluster_environment name. Example: `nonprod` - The `placeholder_argocd_oidc_client_secret_from_dex` that you specify needs to be the same one you use in the `platform.yaml` for ArgoCD. If they do not match you will not be able to login. - - Global OTEL extension placeholders: - - Replace `placeholder_otel_extension_version` with the extension release tag (example: `v0.1.0`). - - Replace `placeholder_otel_backend_tag` with the backend API image tag. - - Replace `placeholder_tempo_base_url` with your in-cluster Tempo endpoint. + - OTEL is tenant-overridable through the Terraform module inputs: + - `otel_enabled` enables or disables the global ArgoCD OTEL extension for the tenant. + - `otel_extension_version` sets the GitHub release tag used for the extension tarball. + - `otel_backend_tag` sets the OTEL backend API image tag. + - `tempo_base_url` sets the in-cluster Tempo endpoint. Leave it empty to disable traces while keeping metrics enabled. - The OTEL extension is defined in `argocd.yaml` and loaded by ArgoCD itself, so it is global for all Argo applications without changing app templates. - Install ArgoCD @@ -48,6 +49,10 @@ module "argocd_helm_values" { cluster_environment = "nonprod" client_secret = "Zsbui/29YEqoGOzuI8snlqGcdaRYPSLocwLXDB5GhZY=" glueops_root_domain = "onglueops.com" + otel_enabled = true + otel_extension_version = "v0.1.1" + otel_backend_tag = "v0.1.1" + tempo_base_url = "http://tempo.glueops-core-tempo.svc.cluster.local:3200" } output "argocd_helm_values" { diff --git a/argocd.yaml.tpl b/argocd.yaml.tpl index 06e7ef2..05a46cb 100644 --- a/argocd.yaml.tpl +++ b/argocd.yaml.tpl @@ -165,7 +165,7 @@ applicationSet: configs: params: server.insecure: true - server.enable.proxy.extension: true + server.enable.proxy.extension: placeholder_otel_enabled cm: # @ignored timeout.reconciliation: 10s @@ -236,16 +236,16 @@ configs: # @ignored server: extensions: - enabled: true + enabled: placeholder_otel_enabled extensionList: - name: otel-extension env: - name: EXTENSION_URL - value: "https://github.com/GlueOps/argo-cd-ui-extention/releases/download/v0.1.1/extension.tar.gz" + value: "https://github.com/GlueOps/argo-cd-ui-extention/releases/download/placeholder_otel_extension_version/extension.tar.gz" - name: EXTENSION_VERSION - value: "0.1.1" + value: "placeholder_otel_extension_semver" - name: EXTENSION_ENABLED - value: "true" + value: "placeholder_otel_enabled" # @ignored affinity: nodeAffinity: @@ -325,7 +325,7 @@ extraObjects: labels: app.kubernetes.io/name: otel-extension-api spec: - replicas: 2 + replicas: placeholder_otel_backend_replicas selector: matchLabels: app.kubernetes.io/name: otel-extension-api @@ -343,7 +343,7 @@ extraObjects: effect: "NoSchedule" containers: - name: otel-extension-api - image: "ghcr.repo.gpkg.io/glueops/argocd-otel-extension-api:v0.1.1" + image: "ghcr.repo.gpkg.io/glueops/argocd-otel-extension-api:placeholder_otel_backend_tag" imagePullPolicy: IfNotPresent ports: - name: http diff --git a/main.tf b/main.tf index 2dbf4d7..124556f 100644 --- a/main.tf +++ b/main.tf @@ -1,10 +1,10 @@ terraform { required_providers { http = { - source = "hashicorp/http" + source = "hashicorp/http" } local = { - source = "hashicorp/local" + source = "hashicorp/local" } } } @@ -56,18 +56,115 @@ variable "gatekeeper_tag" { description = "Image tag (SHA or semver) for ghcr.repo.gpkg.io/glueops/gatekeeper.platform.glueops.dev" } +variable "otel_enabled" { + type = bool + description = "Enable or disable the global ArgoCD OTEL extension and its backend service for this tenant" + default = true +} -output "helm_values" { - value = replace(replace(replace(replace(replace( - replace( - replace( - data.local_file.argocd_template.content, - "placeholder_tenant_key", var.tenant_key), - "placeholder_cluster_environment", var.cluster_environment), - "placeholder_argocd_oidc_client_secret_from_dex", var.client_secret), - "placeholder_glueops_root_domain", var.glueops_root_domain), - " placeholder_argocd_rbac_policies", var.argocd_rbac_policies), - "placeholder_argocd_app_version", var.argocd_app_version), - "placeholder_gatekeeper_tag", var.gatekeeper_tag +variable "otel_extension_version" { + type = string + description = "GitHub release tag for the ArgoCD OTEL extension tarball (example: v0.1.1)" + default = "v0.1.1" +} + +variable "otel_backend_tag" { + type = string + description = "Image tag (SHA or semver) for ghcr.repo.gpkg.io/glueops/argocd-otel-extension-api" + default = "v0.1.1" +} + +variable "tempo_base_url" { + type = string + description = "In-cluster Tempo base URL for trace search. Leave empty to disable traces while keeping metrics enabled." + default = "" +} + +locals { + otel_enabled_string = var.otel_enabled ? "true" : "false" + otel_backend_replicas = var.otel_enabled ? "2" : "0" + otel_extension_semver = trimprefix(var.otel_extension_version, "v") + + rendered_argocd_values_tenant = replace( + data.local_file.argocd_template.content, + "placeholder_tenant_key", + var.tenant_key + ) + + rendered_argocd_values_environment = replace( + local.rendered_argocd_values_tenant, + "placeholder_cluster_environment", + var.cluster_environment + ) + + rendered_argocd_values_secret = replace( + local.rendered_argocd_values_environment, + "placeholder_argocd_oidc_client_secret_from_dex", + var.client_secret + ) + + rendered_argocd_values_domain = replace( + local.rendered_argocd_values_secret, + "placeholder_glueops_root_domain", + var.glueops_root_domain + ) + + rendered_argocd_values_rbac = replace( + local.rendered_argocd_values_domain, + " placeholder_argocd_rbac_policies", + var.argocd_rbac_policies ) + + rendered_argocd_values_app_version = replace( + local.rendered_argocd_values_rbac, + "placeholder_argocd_app_version", + var.argocd_app_version + ) + + rendered_argocd_values_gatekeeper = replace( + local.rendered_argocd_values_app_version, + "placeholder_gatekeeper_tag", + var.gatekeeper_tag + ) + + rendered_argocd_values_otel_enabled = replace( + local.rendered_argocd_values_gatekeeper, + "placeholder_otel_enabled", + local.otel_enabled_string + ) + + rendered_argocd_values_otel_replicas = replace( + local.rendered_argocd_values_otel_enabled, + "placeholder_otel_backend_replicas", + local.otel_backend_replicas + ) + + rendered_argocd_values_otel_version = replace( + local.rendered_argocd_values_otel_replicas, + "placeholder_otel_extension_version", + var.otel_extension_version + ) + + rendered_argocd_values_otel_semver = replace( + local.rendered_argocd_values_otel_version, + "placeholder_otel_extension_semver", + local.otel_extension_semver + ) + + rendered_argocd_values_otel_backend_tag = replace( + local.rendered_argocd_values_otel_semver, + "placeholder_otel_backend_tag", + var.otel_backend_tag + ) + + rendered_argocd_values = replace( + local.rendered_argocd_values_otel_backend_tag, + "placeholder_tempo_base_url", + var.tempo_base_url + ) +} + + +output "helm_values" { + value = local.rendered_argocd_values } From 375ebf0529729bf0e6bd0b574d079269f4a2a708 Mon Sep 17 00:00:00 2001 From: Irfan Paraniya Date: Mon, 15 Jun 2026 07:03:37 +0000 Subject: [PATCH 04/16] feat: update global OTEL extension configuration to be tenant-overridable --- README.md | 2 +- argocd.yaml.tpl | 101 ++-------------------------------- main.tf | 142 ++++++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 141 insertions(+), 104 deletions(-) diff --git a/README.md b/README.md index 1fdd083..bbe7b70 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ wget -O argocd.yaml https://raw.githubusercontent.com/GlueOps/docs-argocd/main/a - Replace `placeholder_cluster_environment` with your cluster_environment name. Example: `nonprod` - The `placeholder_argocd_oidc_client_secret_from_dex` that you specify needs to be the same one you use in the `platform.yaml` for ArgoCD. If they do not match you will not be able to login. - OTEL is tenant-overridable through the Terraform module inputs: - - `otel_enabled` enables or disables the global ArgoCD OTEL extension for the tenant. + - `otel_enabled` enables or disables the global ArgoCD OTEL extension for the tenant. The default is `false`, so tenants must opt in explicitly. - `otel_extension_version` sets the GitHub release tag used for the extension tarball. - `otel_backend_tag` sets the OTEL backend API image tag. - `tempo_base_url` sets the in-cluster Tempo endpoint. Leave it empty to disable traces while keeping metrics enabled. diff --git a/argocd.yaml.tpl b/argocd.yaml.tpl index 05a46cb..816cbca 100644 --- a/argocd.yaml.tpl +++ b/argocd.yaml.tpl @@ -218,12 +218,7 @@ configs: clientID: argocd clientSecret: placeholder_argocd_oidc_client_secret_from_dex redirectURI: https://argocd.placeholder_cluster_environment.placeholder_tenant_key.placeholder_glueops_root_domain/api/dex/callback - extension.config: | - extensions: - - name: otel-extension - backend: - services: - - url: http://otel-extension-api.glueops-core.svc.cluster.local:8000 +placeholder_otel_extension_config rbac: # -- A good reference for this is: https://argo-cd.readthedocs.io/en/stable/operator-manual/rbac/ # This default policy is for GlueOps orgs/teams only. Please change it to reflect your own orgs/teams. @@ -231,21 +226,10 @@ configs: # @default -- `''` (See [values.yaml]) policy.csv: | placeholder_argocd_rbac_policies - p, role:readonly, extensions, invoke, otel-extension, allow - p, role:admin, extensions, invoke, otel-extension, allow +placeholder_otel_rbac_policies # @ignored server: - extensions: - enabled: placeholder_otel_enabled - extensionList: - - name: otel-extension - env: - - name: EXTENSION_URL - value: "https://github.com/GlueOps/argo-cd-ui-extention/releases/download/placeholder_otel_extension_version/extension.tar.gz" - - name: EXTENSION_VERSION - value: "placeholder_otel_extension_semver" - - name: EXTENSION_ENABLED - value: "placeholder_otel_enabled" +placeholder_otel_server_extensions # @ignored affinity: nodeAffinity: @@ -316,84 +300,7 @@ extraObjects: name: argocd-server port: number: 80 - - - apiVersion: apps/v1 - kind: Deployment - metadata: - name: otel-extension-api - namespace: glueops-core - labels: - app.kubernetes.io/name: otel-extension-api - spec: - replicas: placeholder_otel_backend_replicas - selector: - matchLabels: - app.kubernetes.io/name: otel-extension-api - template: - metadata: - labels: - app.kubernetes.io/name: otel-extension-api - spec: - nodeSelector: - glueops.dev/role: glueops-platform - tolerations: - - key: "glueops.dev/role" - operator: "Equal" - value: "glueops-platform" - effect: "NoSchedule" - containers: - - name: otel-extension-api - image: "ghcr.repo.gpkg.io/glueops/argocd-otel-extension-api:placeholder_otel_backend_tag" - imagePullPolicy: IfNotPresent - ports: - - name: http - containerPort: 8000 - protocol: TCP - env: - - name: PORT - value: "8000" - - name: PROMETHEUS_BASE_URL - value: "http://kps-prometheus.glueops-core-kube-prometheus-stack.svc.cluster.local:9090" - - name: TEMPO_BASE_URL - value: "placeholder_tempo_base_url" - - name: LOG_LEVEL - value: "INFO" - readinessProbe: - httpGet: - path: /healthz - port: http - initialDelaySeconds: 5 - periodSeconds: 10 - livenessProbe: - httpGet: - path: /healthz - port: http - initialDelaySeconds: 15 - periodSeconds: 20 - resources: - requests: - cpu: 50m - memory: 64Mi - limits: - cpu: 250m - memory: 256Mi - - - apiVersion: v1 - kind: Service - metadata: - name: otel-extension-api - namespace: glueops-core - labels: - app.kubernetes.io/name: otel-extension-api - spec: - type: ClusterIP - selector: - app.kubernetes.io/name: otel-extension-api - ports: - - name: http - port: 8000 - targetPort: http - protocol: TCP +placeholder_otel_backend_objects - apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition diff --git a/main.tf b/main.tf index 124556f..b7d2bd7 100644 --- a/main.tf +++ b/main.tf @@ -59,7 +59,7 @@ variable "gatekeeper_tag" { variable "otel_enabled" { type = bool description = "Enable or disable the global ArgoCD OTEL extension and its backend service for this tenant" - default = true + default = false } variable "otel_extension_version" { @@ -82,8 +82,120 @@ variable "tempo_base_url" { locals { otel_enabled_string = var.otel_enabled ? "true" : "false" - otel_backend_replicas = var.otel_enabled ? "2" : "0" otel_extension_semver = trimprefix(var.otel_extension_version, "v") + otel_extension_config = var.otel_enabled ? ( + <<-EOT + extension.config: | + extensions: + - name: otel-extension + backend: + services: + - url: http://otel-extension-api.glueops-core.svc.cluster.local:8000 + EOT + ) : "" + otel_rbac_policies = var.otel_enabled ? ( + <<-EOT + p, role:readonly, extensions, invoke, otel-extension, allow + p, role:admin, extensions, invoke, otel-extension, allow + EOT + ) : "" + otel_server_extensions = var.otel_enabled ? ( + <<-EOT + extensions: + enabled: true + extensionList: + - name: otel-extension + env: + - name: EXTENSION_URL + value: "https://github.com/GlueOps/argo-cd-ui-extention/releases/download/placeholder_otel_extension_version/extension.tar.gz" + - name: EXTENSION_VERSION + value: "placeholder_otel_extension_semver" + - name: EXTENSION_ENABLED + value: "true" + EOT + ) : "" + otel_backend_objects = var.otel_enabled ? ( + <<-EOT + + - apiVersion: apps/v1 + kind: Deployment + metadata: + name: otel-extension-api + namespace: glueops-core + labels: + app.kubernetes.io/name: otel-extension-api + spec: + replicas: 2 + selector: + matchLabels: + app.kubernetes.io/name: otel-extension-api + template: + metadata: + labels: + app.kubernetes.io/name: otel-extension-api + spec: + nodeSelector: + glueops.dev/role: glueops-platform + tolerations: + - key: "glueops.dev/role" + operator: "Equal" + value: "glueops-platform" + effect: "NoSchedule" + containers: + - name: otel-extension-api + image: "ghcr.repo.gpkg.io/glueops/argocd-otel-extension-api:placeholder_otel_backend_tag" + imagePullPolicy: IfNotPresent + ports: + - name: http + containerPort: 8000 + protocol: TCP + env: + - name: PORT + value: "8000" + - name: PROMETHEUS_BASE_URL + value: "http://kps-prometheus.glueops-core-kube-prometheus-stack.svc.cluster.local:9090" + - name: TEMPO_BASE_URL + value: "placeholder_tempo_base_url" + - name: LOG_LEVEL + value: "INFO" + readinessProbe: + httpGet: + path: /healthz + port: http + initialDelaySeconds: 5 + periodSeconds: 10 + livenessProbe: + httpGet: + path: /healthz + port: http + initialDelaySeconds: 15 + periodSeconds: 20 + resources: + requests: + cpu: 50m + memory: 64Mi + limits: + cpu: 250m + memory: 256Mi + + - apiVersion: v1 + kind: Service + metadata: + name: otel-extension-api + namespace: glueops-core + labels: + app.kubernetes.io/name: otel-extension-api + spec: + type: ClusterIP + selector: + app.kubernetes.io/name: otel-extension-api + ports: + - name: http + port: 8000 + targetPort: http + protocol: TCP + EOT + ) : "" rendered_argocd_values_tenant = replace( data.local_file.argocd_template.content, @@ -133,14 +245,32 @@ locals { local.otel_enabled_string ) - rendered_argocd_values_otel_replicas = replace( + rendered_argocd_values_otel_extension_config = replace( local.rendered_argocd_values_otel_enabled, - "placeholder_otel_backend_replicas", - local.otel_backend_replicas + "placeholder_otel_extension_config", + local.otel_extension_config + ) + + rendered_argocd_values_otel_rbac = replace( + local.rendered_argocd_values_otel_extension_config, + "placeholder_otel_rbac_policies", + local.otel_rbac_policies + ) + + rendered_argocd_values_otel_server_extensions = replace( + local.rendered_argocd_values_otel_rbac, + "placeholder_otel_server_extensions", + local.otel_server_extensions + ) + + rendered_argocd_values_otel_backend_objects = replace( + local.rendered_argocd_values_otel_server_extensions, + "placeholder_otel_backend_objects", + local.otel_backend_objects ) rendered_argocd_values_otel_version = replace( - local.rendered_argocd_values_otel_replicas, + local.rendered_argocd_values_otel_backend_objects, "placeholder_otel_extension_version", var.otel_extension_version ) From cf3c6cfdf78dcae73496d1e1a2b3fc3aad7c4ad6 Mon Sep 17 00:00:00 2001 From: Irfan Paraniya Date: Mon, 15 Jun 2026 07:16:44 +0000 Subject: [PATCH 05/16] feat: update placeholder comments for OTEL extension configurations in ArgoCD templates --- argocd.yaml.tpl | 8 ++++---- main.tf | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/argocd.yaml.tpl b/argocd.yaml.tpl index 816cbca..b9d43ce 100644 --- a/argocd.yaml.tpl +++ b/argocd.yaml.tpl @@ -218,7 +218,7 @@ configs: clientID: argocd clientSecret: placeholder_argocd_oidc_client_secret_from_dex redirectURI: https://argocd.placeholder_cluster_environment.placeholder_tenant_key.placeholder_glueops_root_domain/api/dex/callback -placeholder_otel_extension_config +# placeholder_otel_extension_config rbac: # -- A good reference for this is: https://argo-cd.readthedocs.io/en/stable/operator-manual/rbac/ # This default policy is for GlueOps orgs/teams only. Please change it to reflect your own orgs/teams. @@ -226,10 +226,10 @@ placeholder_otel_extension_config # @default -- `''` (See [values.yaml]) policy.csv: | placeholder_argocd_rbac_policies -placeholder_otel_rbac_policies +# placeholder_otel_rbac_policies # @ignored server: -placeholder_otel_server_extensions +# placeholder_otel_server_extensions # @ignored affinity: nodeAffinity: @@ -300,7 +300,7 @@ extraObjects: name: argocd-server port: number: 80 -placeholder_otel_backend_objects +# placeholder_otel_backend_objects - apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition diff --git a/main.tf b/main.tf index b7d2bd7..bcc1ba3 100644 --- a/main.tf +++ b/main.tf @@ -247,25 +247,25 @@ locals { rendered_argocd_values_otel_extension_config = replace( local.rendered_argocd_values_otel_enabled, - "placeholder_otel_extension_config", + "# placeholder_otel_extension_config", local.otel_extension_config ) rendered_argocd_values_otel_rbac = replace( local.rendered_argocd_values_otel_extension_config, - "placeholder_otel_rbac_policies", + "# placeholder_otel_rbac_policies", local.otel_rbac_policies ) rendered_argocd_values_otel_server_extensions = replace( local.rendered_argocd_values_otel_rbac, - "placeholder_otel_server_extensions", + "# placeholder_otel_server_extensions", local.otel_server_extensions ) rendered_argocd_values_otel_backend_objects = replace( local.rendered_argocd_values_otel_server_extensions, - "placeholder_otel_backend_objects", + "# placeholder_otel_backend_objects", local.otel_backend_objects ) From 0a309d16965080c7990b24708042ad794e6e38fc Mon Sep 17 00:00:00 2001 From: Irfan Paraniya Date: Mon, 15 Jun 2026 10:03:09 +0000 Subject: [PATCH 06/16] feat: refine OTEL extension configuration and improve formatting in ArgoCD templates --- argocd.yaml.tpl | 6 +- main.tf | 190 ++++++++++++++++++++++++------------------------ 2 files changed, 98 insertions(+), 98 deletions(-) diff --git a/argocd.yaml.tpl b/argocd.yaml.tpl index b9d43ce..8c626b7 100644 --- a/argocd.yaml.tpl +++ b/argocd.yaml.tpl @@ -218,7 +218,7 @@ configs: clientID: argocd clientSecret: placeholder_argocd_oidc_client_secret_from_dex redirectURI: https://argocd.placeholder_cluster_environment.placeholder_tenant_key.placeholder_glueops_root_domain/api/dex/callback -# placeholder_otel_extension_config + # placeholder_otel_extension_config rbac: # -- A good reference for this is: https://argo-cd.readthedocs.io/en/stable/operator-manual/rbac/ # This default policy is for GlueOps orgs/teams only. Please change it to reflect your own orgs/teams. @@ -226,10 +226,10 @@ configs: # @default -- `''` (See [values.yaml]) policy.csv: | placeholder_argocd_rbac_policies -# placeholder_otel_rbac_policies + # placeholder_otel_rbac_policies # @ignored server: -# placeholder_otel_server_extensions + # placeholder_otel_server_extensions # @ignored affinity: nodeAffinity: diff --git a/main.tf b/main.tf index bcc1ba3..fd0c13f 100644 --- a/main.tf +++ b/main.tf @@ -85,115 +85,115 @@ locals { otel_extension_semver = trimprefix(var.otel_extension_version, "v") otel_extension_config = var.otel_enabled ? ( <<-EOT - extension.config: | - extensions: - - name: otel-extension - backend: - services: - - url: http://otel-extension-api.glueops-core.svc.cluster.local:8000 + extension.config: | + extensions: + - name: otel-extension + backend: + services: + - url: http://otel-extension-api.glueops-core.svc.cluster.local:8000 EOT ) : "" otel_rbac_policies = var.otel_enabled ? ( <<-EOT - p, role:readonly, extensions, invoke, otel-extension, allow - p, role:admin, extensions, invoke, otel-extension, allow + p, role:readonly, extensions, invoke, otel-extension, allow + p, role:admin, extensions, invoke, otel-extension, allow EOT ) : "" otel_server_extensions = var.otel_enabled ? ( <<-EOT - extensions: - enabled: true - extensionList: - - name: otel-extension - env: - - name: EXTENSION_URL - value: "https://github.com/GlueOps/argo-cd-ui-extention/releases/download/placeholder_otel_extension_version/extension.tar.gz" - - name: EXTENSION_VERSION - value: "placeholder_otel_extension_semver" - - name: EXTENSION_ENABLED - value: "true" + extensions: + enabled: true + extensionList: + - name: otel-extension + env: + - name: EXTENSION_URL + value: "https://github.com/GlueOps/argo-cd-ui-extention/releases/download/placeholder_otel_extension_version/extension.tar.gz" + - name: EXTENSION_VERSION + value: "placeholder_otel_extension_semver" + - name: EXTENSION_ENABLED + value: "true" EOT ) : "" otel_backend_objects = var.otel_enabled ? ( <<-EOT - - apiVersion: apps/v1 - kind: Deployment - metadata: - name: otel-extension-api - namespace: glueops-core - labels: - app.kubernetes.io/name: otel-extension-api - spec: - replicas: 2 - selector: - matchLabels: - app.kubernetes.io/name: otel-extension-api - template: + - apiVersion: apps/v1 + kind: Deployment metadata: + name: otel-extension-api + namespace: glueops-core labels: app.kubernetes.io/name: otel-extension-api spec: - nodeSelector: - glueops.dev/role: glueops-platform - tolerations: - - key: "glueops.dev/role" - operator: "Equal" - value: "glueops-platform" - effect: "NoSchedule" - containers: - - name: otel-extension-api - image: "ghcr.repo.gpkg.io/glueops/argocd-otel-extension-api:placeholder_otel_backend_tag" - imagePullPolicy: IfNotPresent - ports: - - name: http - containerPort: 8000 - protocol: TCP - env: - - name: PORT - value: "8000" - - name: PROMETHEUS_BASE_URL - value: "http://kps-prometheus.glueops-core-kube-prometheus-stack.svc.cluster.local:9090" - - name: TEMPO_BASE_URL - value: "placeholder_tempo_base_url" - - name: LOG_LEVEL - value: "INFO" - readinessProbe: - httpGet: - path: /healthz - port: http - initialDelaySeconds: 5 - periodSeconds: 10 - livenessProbe: - httpGet: - path: /healthz - port: http - initialDelaySeconds: 15 - periodSeconds: 20 - resources: - requests: - cpu: 50m - memory: 64Mi - limits: - cpu: 250m - memory: 256Mi - - - apiVersion: v1 - kind: Service - metadata: - name: otel-extension-api - namespace: glueops-core - labels: - app.kubernetes.io/name: otel-extension-api - spec: - type: ClusterIP - selector: - app.kubernetes.io/name: otel-extension-api - ports: - - name: http - port: 8000 - targetPort: http - protocol: TCP + replicas: 2 + selector: + matchLabels: + app.kubernetes.io/name: otel-extension-api + template: + metadata: + labels: + app.kubernetes.io/name: otel-extension-api + spec: + nodeSelector: + glueops.dev/role: glueops-platform + tolerations: + - key: "glueops.dev/role" + operator: "Equal" + value: "glueops-platform" + effect: "NoSchedule" + containers: + - name: otel-extension-api + image: "ghcr.repo.gpkg.io/glueops/argocd-otel-extension-api:placeholder_otel_backend_tag" + imagePullPolicy: IfNotPresent + ports: + - name: http + containerPort: 8000 + protocol: TCP + env: + - name: PORT + value: "8000" + - name: PROMETHEUS_BASE_URL + value: "http://kps-prometheus.glueops-core-kube-prometheus-stack.svc.cluster.local:9090" + - name: TEMPO_BASE_URL + value: "placeholder_tempo_base_url" + - name: LOG_LEVEL + value: "INFO" + readinessProbe: + httpGet: + path: /healthz + port: http + initialDelaySeconds: 5 + periodSeconds: 10 + livenessProbe: + httpGet: + path: /healthz + port: http + initialDelaySeconds: 15 + periodSeconds: 20 + resources: + requests: + cpu: 50m + memory: 64Mi + limits: + cpu: 250m + memory: 256Mi + + - apiVersion: v1 + kind: Service + metadata: + name: otel-extension-api + namespace: glueops-core + labels: + app.kubernetes.io/name: otel-extension-api + spec: + type: ClusterIP + selector: + app.kubernetes.io/name: otel-extension-api + ports: + - name: http + port: 8000 + targetPort: http + protocol: TCP EOT ) : "" @@ -247,19 +247,19 @@ locals { rendered_argocd_values_otel_extension_config = replace( local.rendered_argocd_values_otel_enabled, - "# placeholder_otel_extension_config", + " # placeholder_otel_extension_config", local.otel_extension_config ) rendered_argocd_values_otel_rbac = replace( local.rendered_argocd_values_otel_extension_config, - "# placeholder_otel_rbac_policies", + " # placeholder_otel_rbac_policies", local.otel_rbac_policies ) rendered_argocd_values_otel_server_extensions = replace( local.rendered_argocd_values_otel_rbac, - "# placeholder_otel_server_extensions", + " # placeholder_otel_server_extensions", local.otel_server_extensions ) From 58de9b5f43ebc6f4df053bf7e8c2bf8ad4f51d1c Mon Sep 17 00:00:00 2001 From: Irfan Paraniya Date: Thu, 18 Jun 2026 07:56:51 +0000 Subject: [PATCH 07/16] feat: refactor OTEL extension configuration for improved readability and add preconditions for version variables --- main.tf | 228 ++++++++++++++++++++++++++++---------------------------- 1 file changed, 115 insertions(+), 113 deletions(-) diff --git a/main.tf b/main.tf index fd0c13f..eb2ee53 100644 --- a/main.tf +++ b/main.tf @@ -83,119 +83,111 @@ variable "tempo_base_url" { locals { otel_enabled_string = var.otel_enabled ? "true" : "false" otel_extension_semver = trimprefix(var.otel_extension_version, "v") - otel_extension_config = var.otel_enabled ? ( - <<-EOT - extension.config: | - extensions: - - name: otel-extension - backend: - services: - - url: http://otel-extension-api.glueops-core.svc.cluster.local:8000 - EOT - ) : "" - otel_rbac_policies = var.otel_enabled ? ( - <<-EOT - p, role:readonly, extensions, invoke, otel-extension, allow - p, role:admin, extensions, invoke, otel-extension, allow - EOT - ) : "" - otel_server_extensions = var.otel_enabled ? ( - <<-EOT - extensions: - enabled: true - extensionList: - - name: otel-extension - env: - - name: EXTENSION_URL - value: "https://github.com/GlueOps/argo-cd-ui-extention/releases/download/placeholder_otel_extension_version/extension.tar.gz" - - name: EXTENSION_VERSION - value: "placeholder_otel_extension_semver" - - name: EXTENSION_ENABLED - value: "true" - EOT - ) : "" - otel_backend_objects = var.otel_enabled ? ( - <<-EOT - - - apiVersion: apps/v1 - kind: Deployment - metadata: - name: otel-extension-api - namespace: glueops-core - labels: - app.kubernetes.io/name: otel-extension-api - spec: - replicas: 2 - selector: - matchLabels: - app.kubernetes.io/name: otel-extension-api - template: - metadata: - labels: - app.kubernetes.io/name: otel-extension-api - spec: - nodeSelector: - glueops.dev/role: glueops-platform - tolerations: - - key: "glueops.dev/role" - operator: "Equal" - value: "glueops-platform" - effect: "NoSchedule" - containers: - - name: otel-extension-api - image: "ghcr.repo.gpkg.io/glueops/argocd-otel-extension-api:placeholder_otel_backend_tag" - imagePullPolicy: IfNotPresent - ports: - - name: http - containerPort: 8000 - protocol: TCP - env: - - name: PORT - value: "8000" - - name: PROMETHEUS_BASE_URL - value: "http://kps-prometheus.glueops-core-kube-prometheus-stack.svc.cluster.local:9090" - - name: TEMPO_BASE_URL - value: "placeholder_tempo_base_url" - - name: LOG_LEVEL - value: "INFO" - readinessProbe: - httpGet: - path: /healthz - port: http - initialDelaySeconds: 5 - periodSeconds: 10 - livenessProbe: - httpGet: - path: /healthz - port: http - initialDelaySeconds: 15 - periodSeconds: 20 - resources: - requests: - cpu: 50m - memory: 64Mi - limits: - cpu: 250m - memory: 256Mi - - - apiVersion: v1 - kind: Service - metadata: - name: otel-extension-api - namespace: glueops-core - labels: - app.kubernetes.io/name: otel-extension-api - spec: - type: ClusterIP - selector: - app.kubernetes.io/name: otel-extension-api - ports: - - name: http - port: 8000 - targetPort: http - protocol: TCP - EOT - ) : "" + otel_extension_config = var.otel_enabled ? join("\n", [ + " extension.config: |", + " extensions:", + " - name: otel-extension", + " backend:", + " services:", + " - url: http://otel-extension-api.glueops-core.svc.cluster.local:8000", + ]) : "" + otel_rbac_policies = var.otel_enabled ? join("\n", [ + " p, role:readonly, extensions, invoke, otel-extension, allow", + " p, role:admin, extensions, invoke, otel-extension, allow", + ]) : "" + otel_server_extensions = var.otel_enabled ? join("\n", [ + " extensions:", + " enabled: true", + " extensionList:", + " - name: otel-extension", + " env:", + " - name: EXTENSION_URL", + " value: \"https://github.com/GlueOps/argo-cd-ui-extention/releases/download/placeholder_otel_extension_version/extension.tar.gz\"", + " - name: EXTENSION_VERSION", + " value: \"placeholder_otel_extension_semver\"", + " - name: EXTENSION_ENABLED", + " value: \"true\"", + ]) : "" + otel_backend_objects = var.otel_enabled ? join("\n", [ + "", + " - apiVersion: apps/v1", + " kind: Deployment", + " metadata:", + " name: otel-extension-api", + " namespace: glueops-core", + " labels:", + " app.kubernetes.io/name: otel-extension-api", + " spec:", + " replicas: 2", + " selector:", + " matchLabels:", + " app.kubernetes.io/name: otel-extension-api", + " template:", + " metadata:", + " labels:", + " app.kubernetes.io/name: otel-extension-api", + " spec:", + " nodeSelector:", + " glueops.dev/role: glueops-platform", + " tolerations:", + " - key: \"glueops.dev/role\"", + " operator: \"Equal\"", + " value: \"glueops-platform\"", + " effect: \"NoSchedule\"", + " containers:", + " - name: otel-extension-api", + " image: \"ghcr.repo.gpkg.io/glueops/argocd-otel-extension-api:placeholder_otel_backend_tag\"", + " imagePullPolicy: IfNotPresent", + " ports:", + " - name: http", + " containerPort: 8000", + " protocol: TCP", + " env:", + " - name: PORT", + " value: \"8000\"", + " - name: PROMETHEUS_BASE_URL", + " value: \"http://kps-prometheus.glueops-core-kube-prometheus-stack.svc.cluster.local:9090\"", + " - name: TEMPO_BASE_URL", + " value: \"placeholder_tempo_base_url\"", + " - name: LOG_LEVEL", + " value: \"INFO\"", + " readinessProbe:", + " httpGet:", + " path: /healthz", + " port: http", + " initialDelaySeconds: 5", + " periodSeconds: 10", + " livenessProbe:", + " httpGet:", + " path: /healthz", + " port: http", + " initialDelaySeconds: 15", + " periodSeconds: 20", + " resources:", + " requests:", + " cpu: 50m", + " memory: 64Mi", + " limits:", + " cpu: 250m", + " memory: 256Mi", + "", + " - apiVersion: v1", + " kind: Service", + " metadata:", + " name: otel-extension-api", + " namespace: glueops-core", + " labels:", + " app.kubernetes.io/name: otel-extension-api", + " spec:", + " type: ClusterIP", + " selector:", + " app.kubernetes.io/name: otel-extension-api", + " ports:", + " - name: http", + " port: 8000", + " targetPort: http", + " protocol: TCP", + ]) : "" rendered_argocd_values_tenant = replace( data.local_file.argocd_template.content, @@ -297,4 +289,14 @@ locals { output "helm_values" { value = local.rendered_argocd_values + + precondition { + condition = !var.otel_enabled || trimspace(var.otel_extension_version) != "" + error_message = "otel_extension_version must be non-empty when otel_enabled is true" + } + + precondition { + condition = !var.otel_enabled || trimspace(var.otel_backend_tag) != "" + error_message = "otel_backend_tag must be non-empty when otel_enabled is true" + } } From d5406c8f447c8f0969ce18a34b202633c209ca45 Mon Sep 17 00:00:00 2001 From: Irfan Paraniya Date: Thu, 18 Jun 2026 08:03:35 +0000 Subject: [PATCH 08/16] feat: update required Terraform version in main.tf for compatibility --- main.tf | 2 ++ 1 file changed, 2 insertions(+) diff --git a/main.tf b/main.tf index eb2ee53..d9910d0 100644 --- a/main.tf +++ b/main.tf @@ -1,4 +1,6 @@ terraform { + required_version = ">= 1.2.0" + required_providers { http = { source = "hashicorp/http" From aca9d8e207206d099ba75efbc888be132451421d Mon Sep 17 00:00:00 2001 From: Irfan Paraniya Date: Thu, 18 Jun 2026 08:22:31 +0000 Subject: [PATCH 09/16] feat: trim whitespace from OTEL extension version and backend tag variables in locals --- main.tf | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/main.tf b/main.tf index d9910d0..c0b9dd3 100644 --- a/main.tf +++ b/main.tf @@ -84,7 +84,10 @@ variable "tempo_base_url" { locals { otel_enabled_string = var.otel_enabled ? "true" : "false" - otel_extension_semver = trimprefix(var.otel_extension_version, "v") + otel_extension_version_trimmed = trimspace(var.otel_extension_version) + otel_backend_tag_trimmed = trimspace(var.otel_backend_tag) + tempo_base_url_trimmed = trimspace(var.tempo_base_url) + otel_extension_semver = trimprefix(local.otel_extension_version_trimmed, "v") otel_extension_config = var.otel_enabled ? join("\n", [ " extension.config: |", " extensions:", @@ -266,7 +269,7 @@ locals { rendered_argocd_values_otel_version = replace( local.rendered_argocd_values_otel_backend_objects, "placeholder_otel_extension_version", - var.otel_extension_version + local.otel_extension_version_trimmed ) rendered_argocd_values_otel_semver = replace( @@ -278,13 +281,13 @@ locals { rendered_argocd_values_otel_backend_tag = replace( local.rendered_argocd_values_otel_semver, "placeholder_otel_backend_tag", - var.otel_backend_tag + local.otel_backend_tag_trimmed ) rendered_argocd_values = replace( local.rendered_argocd_values_otel_backend_tag, "placeholder_tempo_base_url", - var.tempo_base_url + local.tempo_base_url_trimmed ) } From ba63f8f48bc1d72744c5de3cfd4ffae8bf05bf28 Mon Sep 17 00:00:00 2001 From: Irfan Paraniya Date: Thu, 18 Jun 2026 08:29:19 +0000 Subject: [PATCH 10/16] feat: add instructions for installing OTEL directly from argocd.yaml.tpl --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index bbe7b70..43775ca 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,7 @@ wget -O argocd.yaml https://raw.githubusercontent.com/GlueOps/docs-argocd/main/a - `otel_extension_version` sets the GitHub release tag used for the extension tarball. - `otel_backend_tag` sets the OTEL backend API image tag. - `tempo_base_url` sets the in-cluster Tempo endpoint. Leave it empty to disable traces while keeping metrics enabled. + - If you are installing from the downloaded `argocd.yaml.tpl` directly instead of using Terraform, replace `placeholder_otel_enabled` with `true` or `false` before running Helm. Leave the OTEL placeholder comments in place to keep OTEL disabled, or replace those placeholder comments with concrete OTEL config, RBAC, server extension, and backend object blocks if you want OTEL enabled without Terraform. - The OTEL extension is defined in `argocd.yaml` and loaded by ArgoCD itself, so it is global for all Argo applications without changing app templates. - Install ArgoCD From ed14832e19b2cddb3f3e0149be49189bc0384f7b Mon Sep 17 00:00:00 2001 From: Irfan Paraniya Date: Thu, 18 Jun 2026 08:34:31 +0000 Subject: [PATCH 11/16] feat: add preconditions for OTEL extension variables to prevent whitespace --- main.tf | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/main.tf b/main.tf index c0b9dd3..991c36b 100644 --- a/main.tf +++ b/main.tf @@ -300,8 +300,23 @@ output "helm_values" { error_message = "otel_extension_version must be non-empty when otel_enabled is true" } + precondition { + condition = !var.otel_enabled || length(regexall("\\s", local.otel_extension_version_trimmed)) == 0 + error_message = "otel_extension_version must not contain whitespace when otel_enabled is true" + } + precondition { condition = !var.otel_enabled || trimspace(var.otel_backend_tag) != "" error_message = "otel_backend_tag must be non-empty when otel_enabled is true" } + + precondition { + condition = !var.otel_enabled || length(regexall("\\s", local.otel_backend_tag_trimmed)) == 0 + error_message = "otel_backend_tag must not contain whitespace when otel_enabled is true" + } + + precondition { + condition = !var.otel_enabled || local.tempo_base_url_trimmed == "" || length(regexall("\\s", local.tempo_base_url_trimmed)) == 0 + error_message = "tempo_base_url must not contain whitespace when otel_enabled is true" + } } From 9b85769d0918ac00df63d20697b7dc2d2adcff5a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 19 Jun 2026 05:15:30 +0000 Subject: [PATCH 12/16] docs: fix README OTEL usage examples --- README.md | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 43775ca..6386eec 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ wget -O argocd.yaml https://raw.githubusercontent.com/GlueOps/docs-argocd/main/a - `otel_extension_version` sets the GitHub release tag used for the extension tarball. - `otel_backend_tag` sets the OTEL backend API image tag. - `tempo_base_url` sets the in-cluster Tempo endpoint. Leave it empty to disable traces while keeping metrics enabled. - - If you are installing from the downloaded `argocd.yaml.tpl` directly instead of using Terraform, replace `placeholder_otel_enabled` with `true` or `false` before running Helm. Leave the OTEL placeholder comments in place to keep OTEL disabled, or replace those placeholder comments with concrete OTEL config, RBAC, server extension, and backend object blocks if you want OTEL enabled without Terraform. + - If you are installing from the downloaded `argocd.yaml` directly instead of using Terraform, replace `placeholder_otel_enabled` with `true` or `false` before running Helm. Leave the OTEL placeholder comments in place to keep OTEL disabled, or replace those placeholder comments with concrete OTEL config, RBAC, server extension, and backend object blocks if you want OTEL enabled without Terraform. - The OTEL extension is defined in `argocd.yaml` and loaded by ArgoCD itself, so it is global for all Argo applications without changing app templates. - Install ArgoCD @@ -45,18 +45,20 @@ kubectl get pods -n glueops-core ```hcl module "argocd_helm_values" { - source = "git::https://github.com/GlueOps/docs-argocd.git" - tenant_key = "antoniostacos" - cluster_environment = "nonprod" - client_secret = "Zsbui/29YEqoGOzuI8snlqGcdaRYPSLocwLXDB5GhZY=" - glueops_root_domain = "onglueops.com" - otel_enabled = true - otel_extension_version = "v0.1.1" - otel_backend_tag = "v0.1.1" - tempo_base_url = "http://tempo.glueops-core-tempo.svc.cluster.local:3200" + source = "git::https://github.com/GlueOps/docs-argocd.git" + tenant_key = "antoniostacos" + cluster_environment = "nonprod" + client_secret = "Zsbui/29YEqoGOzuI8snlqGcdaRYPSLocwLXDB5GhZY=" + glueops_root_domain = "onglueops.com" + argocd_app_version = "v2.8.6" + gatekeeper_tag = "v1.0.0" + otel_enabled = true + otel_extension_version = "v0.1.1" + otel_backend_tag = "v0.1.1" + tempo_base_url = "http://tempo.glueops-core-tempo.svc.cluster.local:3200" } output "argocd_helm_values" { - value = module.argocd_yaml.argocd + value = module.argocd_helm_values.helm_values } ``` From fabab4dd6f82dad154e5538248de15c6e446d80d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 19 Jun 2026 05:43:03 +0000 Subject: [PATCH 13/16] feat: add otel-extension-api backend service and release workflow --- .github/workflows/release.yml | 42 ++ .gitignore | 1 + backend/.dockerignore | 3 + backend/Dockerfile | 8 + backend/README.md | 46 ++ backend/package-lock.json | 1041 +++++++++++++++++++++++++++++++++ backend/package.json | 16 + backend/src/server.js | 72 +++ 8 files changed, 1229 insertions(+) create mode 100644 .github/workflows/release.yml create mode 100644 .gitignore create mode 100644 backend/.dockerignore create mode 100644 backend/Dockerfile create mode 100644 backend/README.md create mode 100644 backend/package-lock.json create mode 100644 backend/package.json create mode 100644 backend/src/server.js diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..929454a --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,42 @@ +name: Release + +on: + release: + types: [published] + +permissions: + contents: read + packages: write + +jobs: + build-and-push-backend: + name: Build and push backend image + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Log in to GHCR + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Docker meta + id: meta + uses: docker/metadata-action@v5 + with: + images: ghcr.io/glueops/argocd-otel-extension-api + tags: | + type=semver,pattern={{version}} + type=semver,pattern={{major}}.{{minor}} + type=sha + + - name: Build and push + uses: docker/build-push-action@v6 + with: + context: ./backend + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..baf1908 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +backend/node_modules/ diff --git a/backend/.dockerignore b/backend/.dockerignore new file mode 100644 index 0000000..f4100b6 --- /dev/null +++ b/backend/.dockerignore @@ -0,0 +1,3 @@ +node_modules +npm-debug.log +.npm diff --git a/backend/Dockerfile b/backend/Dockerfile new file mode 100644 index 0000000..75399ff --- /dev/null +++ b/backend/Dockerfile @@ -0,0 +1,8 @@ +FROM node:20-alpine +WORKDIR /app +COPY package*.json ./ +RUN npm ci --only=production +COPY src/ ./src/ +EXPOSE 8000 +USER node +CMD ["node", "src/server.js"] diff --git a/backend/README.md b/backend/README.md new file mode 100644 index 0000000..058b098 --- /dev/null +++ b/backend/README.md @@ -0,0 +1,46 @@ +# argocd-otel-extension-api + +Backend service for the ArgoCD OTEL UI extension. It proxies Prometheus and Tempo endpoints so the extension frontend can query metrics and traces without direct cluster network access. + +## Endpoints + +| Path | Proxied to | +|------|------------| +| `GET /healthz` | Local health check — returns `{"status":"ok"}` | +| `ANY /prometheus/*` | `PROMETHEUS_BASE_URL/*` (path prefix stripped) | +| `ANY /tempo/*` | `TEMPO_BASE_URL/*` (path prefix stripped) | + +### Prometheus example +``` +GET /prometheus/api/v1/query?query=up +``` +Proxied to `$PROMETHEUS_BASE_URL/api/v1/query?query=up`. + +### Tempo example +``` +GET /tempo/api/search?tags=service.name%3Dmyapp +``` +Proxied to `$TEMPO_BASE_URL/api/search?tags=service.name%3Dmyapp`. + +## Environment variables + +| Variable | Required | Default | Description | +|----------|----------|---------|-------------| +| `PORT` | No | `8000` | Port the server listens on | +| `PROMETHEUS_BASE_URL` | Yes (for metrics) | `""` | In-cluster Prometheus base URL, e.g. `http://kps-prometheus.glueops-core-kube-prometheus-stack.svc.cluster.local:9090` | +| `TEMPO_BASE_URL` | No | `""` | In-cluster Tempo base URL, e.g. `http://tempo.glueops-core-tempo.svc.cluster.local:3200`. Leave empty to disable trace proxying. | +| `LOG_LEVEL` | No | `INFO` | Log verbosity: `DEBUG`, `INFO`, `WARN`, or `ERROR` | + +## Running locally + +```bash +npm install +PROMETHEUS_BASE_URL=http://localhost:9090 node src/server.js +``` + +## Container image + +The image is published to GHCR on every release: +``` +ghcr.io/glueops/argocd-otel-extension-api: +``` diff --git a/backend/package-lock.json b/backend/package-lock.json new file mode 100644 index 0000000..5254517 --- /dev/null +++ b/backend/package-lock.json @@ -0,0 +1,1041 @@ +{ + "name": "argocd-otel-extension-api", + "version": "0.1.1", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "argocd-otel-extension-api", + "version": "0.1.1", + "dependencies": { + "express": "^4.21.2", + "http-proxy-middleware": "^3.0.7" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/@types/http-proxy": { + "version": "1.17.17", + "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.17.tgz", + "integrity": "sha512-ED6LB+Z1AVylNTu7hdzuBqOgMnvG/ld6wGCG8wFnAzKX5uyW2K3WD52v0gnLCTK/VLpXtKckgWuyScYK6cSPaw==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/node": { + "version": "25.9.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.9.3.tgz", + "integrity": "sha512-603BddQMv3pUcr4U2dhujk83N2tTDVr/34wII2B6bJy6g+8WD6yUb11jszNs0gdi4PesVWl7ABt8nYMVpnLUcg==", + "license": "MIT", + "dependencies": { + "undici-types": ">=7.24.0 <7.24.7" + } + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "license": "MIT", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", + "license": "MIT" + }, + "node_modules/body-parser": { + "version": "1.20.5", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.5.tgz", + "integrity": "sha512-3grm+/2tUOvu2cjJkvsIxrv/wVpfXQW4PsQHYm7yk4vfpu7Ekl6nEsYBoJUL6qDwZUx8wUhQ8tR2qz+ad9c9OA==", + "license": "MIT", + "dependencies": { + "bytes": "~3.1.2", + "content-type": "~1.0.5", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "~1.2.0", + "http-errors": "~2.0.1", + "iconv-lite": "~0.4.24", + "on-finished": "~2.4.1", + "qs": "~6.15.1", + "raw-body": "~2.5.3", + "type-is": "~1.6.18", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "license": "MIT", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.7.tgz", + "integrity": "sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA==", + "license": "MIT" + }, + "node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "license": "MIT", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "license": "MIT" + }, + "node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.2.tgz", + "integrity": "sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "license": "MIT" + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", + "license": "MIT" + }, + "node_modules/express": { + "version": "4.22.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.22.2.tgz", + "integrity": "sha512-IuL+Elrou2ZvCFHs18/CIzy2Nzvo25nZ1/D2eIZlz7c+QUayAcYoiM2BthCjs+EBHVpjYjcuLDAiCWgeIX3X1Q==", + "license": "MIT", + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "~1.20.5", + "content-disposition": "~0.5.4", + "content-type": "~1.0.4", + "cookie": "~0.7.1", + "cookie-signature": "~1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "~1.3.1", + "fresh": "~0.5.2", + "http-errors": "~2.0.0", + "merge-descriptors": "1.0.3", + "methods": "~1.1.2", + "on-finished": "~2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "~0.1.12", + "proxy-addr": "~2.0.7", + "qs": "~6.15.1", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "~0.19.0", + "serve-static": "~1.16.2", + "setprototypeof": "1.2.0", + "statuses": "~2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/finalhandler": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.2.tgz", + "integrity": "sha512-aA4RyPcd3badbdABGDuTXCMTtOneUCAYH/gxoYRTZlIJdF0YPWuGqiAsIrhNnnqdXGswYk6dGujem4w80UJFhg==", + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "on-finished": "~2.4.1", + "parseurl": "~1.3.3", + "statuses": "~2.0.2", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/follow-redirects": { + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.16.0.tgz", + "integrity": "sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz", + "integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/http-errors": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", + "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", + "license": "MIT", + "dependencies": { + "depd": "~2.0.0", + "inherits": "~2.0.4", + "setprototypeof": "~1.2.0", + "statuses": "~2.0.2", + "toidentifier": "~1.0.1" + }, + "engines": { + "node": ">= 0.8" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/http-proxy": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", + "license": "MIT", + "dependencies": { + "eventemitter3": "^4.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/http-proxy-middleware": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-3.0.7.tgz", + "integrity": "sha512-iwbQltVlx8bCrqePUM8C+hllHvdawVhQJaLrj1X7qllkvFQdXFsr16pW/mo9+JDVjN+QO2XUx9jd8SmoFkE5qw==", + "license": "MIT", + "dependencies": { + "@types/http-proxy": "^1.17.15", + "debug": "^4.3.6", + "http-proxy": "^1.18.1", + "is-glob": "^4.0.3", + "is-plain-object": "^5.0.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": "^14.18.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/http-proxy-middleware/node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/http-proxy-middleware/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-plain-object": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", + "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", + "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "license": "MIT", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/path-to-regexp": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.13.tgz", + "integrity": "sha512-A/AGNMFN3c8bOlvV9RreMdrv7jsmF9XIfDeCd87+I8RNg6s78BhJxMu69NEMHBSJFxKidViTEdruRwEk/WIKqA==", + "license": "MIT" + }, + "node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "license": "MIT", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/qs": { + "version": "6.15.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.2.tgz", + "integrity": "sha512-Rzq0KEyX/w/tEybncDgdkZrJgVUsUMk3xjh3t5bv3S1HTAtg+uOYt72+ZfwiQwKdysThkTBdL/rTi6HDmX9Ddw==", + "license": "BSD-3-Clause", + "dependencies": { + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.3.tgz", + "integrity": "sha512-s4VSOf6yN0rvbRZGxs8Om5CWj6seneMwK3oDb4lWDH0UPhWcxwOWw5+qk24bxq87szX1ydrwylIOp2uG1ojUpA==", + "license": "MIT", + "dependencies": { + "bytes": "~3.1.2", + "http-errors": "~2.0.1", + "iconv-lite": "~0.4.24", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", + "license": "MIT" + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" + }, + "node_modules/send": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.2.tgz", + "integrity": "sha512-VMbMxbDeehAxpOtWJXlcUS5E8iXh6QmN+BkRX1GARS3wRaXEEgzCcB10gTQazO42tpNIya8xIyNx8fll1OFPrg==", + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "~0.5.2", + "http-errors": "~2.0.1", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "~2.4.1", + "range-parser": "~1.2.1", + "statuses": "~2.0.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/serve-static": { + "version": "1.16.3", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.3.tgz", + "integrity": "sha512-x0RTqQel6g5SY7Lg6ZreMmsOzncHFU7nhnRWkKgWuMTu5NN0DR5oruckMqRvacAN9d5w6ARnRBXl9xhDCgfMeA==", + "license": "MIT", + "dependencies": { + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "~0.19.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "license": "ISC" + }, + "node_modules/side-channel": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.1.tgz", + "integrity": "sha512-6x6dK6zJdpTzF4sQeNYxwtvBzf6Eg4GtlesS94HOvTudUeyK2WXAaIfmDgsyslYrRBeFIlsi54AYsFGUuhmvrQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.4", + "side-channel-list": "^1.0.1", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.1.tgz", + "integrity": "sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/statuses": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", + "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "license": "MIT", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "license": "MIT", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/undici-types": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.24.6.tgz", + "integrity": "sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg==", + "license": "MIT" + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "license": "MIT", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + } + } +} diff --git a/backend/package.json b/backend/package.json new file mode 100644 index 0000000..c91692e --- /dev/null +++ b/backend/package.json @@ -0,0 +1,16 @@ +{ + "name": "argocd-otel-extension-api", + "version": "0.1.1", + "description": "Backend API service for ArgoCD OTEL extension - proxies Prometheus and Tempo endpoints", + "main": "src/server.js", + "scripts": { + "start": "node src/server.js" + }, + "dependencies": { + "express": "^4.21.2", + "http-proxy-middleware": "^3.0.7" + }, + "engines": { + "node": ">=20" + } +} diff --git a/backend/src/server.js b/backend/src/server.js new file mode 100644 index 0000000..ff05af0 --- /dev/null +++ b/backend/src/server.js @@ -0,0 +1,72 @@ +'use strict'; + +const express = require('express'); +const { createProxyMiddleware } = require('http-proxy-middleware'); + +const PORT = parseInt(process.env.PORT || '8000', 10); +const PROMETHEUS_BASE_URL = process.env.PROMETHEUS_BASE_URL || ''; +const TEMPO_BASE_URL = process.env.TEMPO_BASE_URL || ''; +const LOG_LEVEL = (process.env.LOG_LEVEL || 'INFO').toUpperCase(); + +const app = express(); + +function log(level, message) { + const levels = { DEBUG: 0, INFO: 1, WARN: 2, ERROR: 3 }; + if ((levels[level] || 0) >= (levels[LOG_LEVEL] || 1)) { + console.log(JSON.stringify({ time: new Date().toISOString(), level, message })); + } +} + +app.get('/healthz', (_req, res) => { + res.json({ status: 'ok' }); +}); + +if (PROMETHEUS_BASE_URL) { + app.use( + '/prometheus', + createProxyMiddleware({ + target: PROMETHEUS_BASE_URL, + changeOrigin: true, + pathRewrite: { '^/prometheus': '' }, + on: { + error: (err, _req, res) => { + log('ERROR', `Prometheus proxy error: ${err.message}`); + res.status(502).json({ error: 'Bad Gateway', detail: err.message }); + }, + }, + }) + ); + log('INFO', `Prometheus proxy enabled → ${PROMETHEUS_BASE_URL}`); +} else { + app.use('/prometheus', (_req, res) => { + res.status(503).json({ error: 'PROMETHEUS_BASE_URL not configured' }); + }); + log('WARN', 'PROMETHEUS_BASE_URL not set; /prometheus routes will return 503'); +} + +if (TEMPO_BASE_URL) { + app.use( + '/tempo', + createProxyMiddleware({ + target: TEMPO_BASE_URL, + changeOrigin: true, + pathRewrite: { '^/tempo': '' }, + on: { + error: (err, _req, res) => { + log('ERROR', `Tempo proxy error: ${err.message}`); + res.status(502).json({ error: 'Bad Gateway', detail: err.message }); + }, + }, + }) + ); + log('INFO', `Tempo proxy enabled → ${TEMPO_BASE_URL}`); +} else { + app.use('/tempo', (_req, res) => { + res.status(503).json({ error: 'TEMPO_BASE_URL not configured' }); + }); + log('WARN', 'TEMPO_BASE_URL not set; /tempo routes will return 503'); +} + +app.listen(PORT, () => { + log('INFO', `argocd-otel-extension-api listening on port ${PORT}`); +}); From 1e9fea9def1193053df357965048292b04fb3d30 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 19 Jun 2026 05:44:23 +0000 Subject: [PATCH 14/16] fix: remove internal error details from proxy error responses; use npm --omit=dev --- backend/Dockerfile | 2 +- backend/src/server.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/backend/Dockerfile b/backend/Dockerfile index 75399ff..27739fc 100644 --- a/backend/Dockerfile +++ b/backend/Dockerfile @@ -1,7 +1,7 @@ FROM node:20-alpine WORKDIR /app COPY package*.json ./ -RUN npm ci --only=production +RUN npm ci --omit=dev COPY src/ ./src/ EXPOSE 8000 USER node diff --git a/backend/src/server.js b/backend/src/server.js index ff05af0..9c94a6d 100644 --- a/backend/src/server.js +++ b/backend/src/server.js @@ -31,7 +31,7 @@ if (PROMETHEUS_BASE_URL) { on: { error: (err, _req, res) => { log('ERROR', `Prometheus proxy error: ${err.message}`); - res.status(502).json({ error: 'Bad Gateway', detail: err.message }); + res.status(502).json({ error: 'Bad Gateway' }); }, }, }) @@ -54,7 +54,7 @@ if (TEMPO_BASE_URL) { on: { error: (err, _req, res) => { log('ERROR', `Tempo proxy error: ${err.message}`); - res.status(502).json({ error: 'Bad Gateway', detail: err.message }); + res.status(502).json({ error: 'Bad Gateway' }); }, }, }) From a512b7e8b032082baffe926fa1ff0792d6d33bec Mon Sep 17 00:00:00 2001 From: Irfan Paraniya Date: Tue, 23 Jun 2026 05:27:54 +0000 Subject: [PATCH 15/16] feat: update OTEL backend references to use new image and service names --- main.tf | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/main.tf b/main.tf index 991c36b..9322340 100644 --- a/main.tf +++ b/main.tf @@ -72,7 +72,7 @@ variable "otel_extension_version" { variable "otel_backend_tag" { type = string - description = "Image tag (SHA or semver) for ghcr.repo.gpkg.io/glueops/argocd-otel-extension-api" + description = "Image tag (SHA or semver) for ghcr.io/glueops/argocd-extension-backend-api" default = "v0.1.1" } @@ -94,7 +94,7 @@ locals { " - name: otel-extension", " backend:", " services:", - " - url: http://otel-extension-api.glueops-core.svc.cluster.local:8000", + " - url: http://argocd-extension-backend-api.glueops-core.svc.cluster.local:8000", ]) : "" otel_rbac_policies = var.otel_enabled ? join("\n", [ " p, role:readonly, extensions, invoke, otel-extension, allow", @@ -110,27 +110,25 @@ locals { " value: \"https://github.com/GlueOps/argo-cd-ui-extention/releases/download/placeholder_otel_extension_version/extension.tar.gz\"", " - name: EXTENSION_VERSION", " value: \"placeholder_otel_extension_semver\"", - " - name: EXTENSION_ENABLED", - " value: \"true\"", ]) : "" otel_backend_objects = var.otel_enabled ? join("\n", [ "", " - apiVersion: apps/v1", " kind: Deployment", " metadata:", - " name: otel-extension-api", + " name: argocd-extension-backend-api", " namespace: glueops-core", " labels:", - " app.kubernetes.io/name: otel-extension-api", + " app.kubernetes.io/name: argocd-extension-backend-api", " spec:", " replicas: 2", " selector:", " matchLabels:", - " app.kubernetes.io/name: otel-extension-api", + " app.kubernetes.io/name: argocd-extension-backend-api", " template:", " metadata:", " labels:", - " app.kubernetes.io/name: otel-extension-api", + " app.kubernetes.io/name: argocd-extension-backend-api", " spec:", " nodeSelector:", " glueops.dev/role: glueops-platform", @@ -140,8 +138,8 @@ locals { " value: \"glueops-platform\"", " effect: \"NoSchedule\"", " containers:", - " - name: otel-extension-api", - " image: \"ghcr.repo.gpkg.io/glueops/argocd-otel-extension-api:placeholder_otel_backend_tag\"", + " - name: argocd-extension-backend-api", + " image: \"ghcr.io/glueops/argocd-extension-backend-api:placeholder_otel_backend_tag\"", " imagePullPolicy: IfNotPresent", " ports:", " - name: http", @@ -179,14 +177,14 @@ locals { " - apiVersion: v1", " kind: Service", " metadata:", - " name: otel-extension-api", + " name: argocd-extension-backend-api", " namespace: glueops-core", " labels:", - " app.kubernetes.io/name: otel-extension-api", + " app.kubernetes.io/name: argocd-extension-backend-api", " spec:", " type: ClusterIP", " selector:", - " app.kubernetes.io/name: otel-extension-api", + " app.kubernetes.io/name: argocd-extension-backend-api", " ports:", " - name: http", " port: 8000", From 6875002c74e930fa4dd8f0d8a0ef83b7eff0f3f9 Mon Sep 17 00:00:00 2001 From: Irfan Paraniya Date: Tue, 23 Jun 2026 11:21:27 +0000 Subject: [PATCH 16/16] feat: update OTEL extension and backend version to v0.1.2 --- README.md | 4 ++-- main.tf | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 6386eec..656a75d 100644 --- a/README.md +++ b/README.md @@ -53,8 +53,8 @@ module "argocd_helm_values" { argocd_app_version = "v2.8.6" gatekeeper_tag = "v1.0.0" otel_enabled = true - otel_extension_version = "v0.1.1" - otel_backend_tag = "v0.1.1" + otel_extension_version = "v0.1.2" + otel_backend_tag = "v0.1.2" tempo_base_url = "http://tempo.glueops-core-tempo.svc.cluster.local:3200" } diff --git a/main.tf b/main.tf index 9322340..9bc1b14 100644 --- a/main.tf +++ b/main.tf @@ -66,8 +66,8 @@ variable "otel_enabled" { variable "otel_extension_version" { type = string - description = "GitHub release tag for the ArgoCD OTEL extension tarball (example: v0.1.1)" - default = "v0.1.1" + description = "GitHub release tag for the ArgoCD OTEL extension tarball (example: v0.1.2)" + default = "v0.1.2" } variable "otel_backend_tag" {