From aa5897105da0a0bcb7d7fa17ece4b116e87709dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Manuel=20=22Kang=22=20P=C3=A9rez?= Date: Mon, 23 Sep 2024 12:17:27 +0200 Subject: [PATCH] [super-agent] Improve helm chart UX (NR-281093) (#1466) #### Is this a new chart No #### What this PR does / why we need it: super-agent chart got the config from a field called `content` that added any arbitrary data to a config map. This is supposed to control this configMap and render it using values from Helm's `values.yaml`. It also adds some protections so a customer is not able to use it on unsupported environments. #### Special notes for your reviewer: This PR is blocked until #1463 is merged. #### Checklist - [x] Chart Version bumped - [x] Variables are documented in the README.md - [x] Title of the PR starts with chart name (e.g. `[mychartname]`) --- charts/super-agent/Chart.lock | 8 +- charts/super-agent/Chart.yaml | 18 +- charts/super-agent/README.md | 36 ++- .../charts/super-agent-deployment/Chart.yaml | 2 +- .../templates/_helpers.tpl | 247 +++++++++++++++--- .../templates/configmap-subagent-configs.yaml | 6 +- .../templates/deployment-superagent.yaml | 59 +++-- ...einstall-job-register-system-identity.yaml | 67 ++++- .../templates/rbac.yaml | 6 +- .../templates/secret-sa-auth.yaml | 13 + .../templates/serviceaccount.yaml | 2 +- .../templates/uninstall-job.yaml | 17 +- .../tests/auth_secret_test.yaml | 111 ++++++++ .../tests/configmap_fleet_configs_test.yaml | 15 +- .../configmap_superagent_config_test.yaml | 80 +++++- .../tests/deployment_superagent_env_test.yaml | 36 +-- ...ment_superagent_subagent_configs_test.yaml | 14 +- charts/super-agent/ci/test-values.yaml | 9 +- charts/super-agent/values.yaml | 115 ++++---- 19 files changed, 673 insertions(+), 188 deletions(-) create mode 100644 charts/super-agent/charts/super-agent-deployment/templates/secret-sa-auth.yaml create mode 100644 charts/super-agent/charts/super-agent-deployment/tests/auth_secret_test.yaml diff --git a/charts/super-agent/Chart.lock b/charts/super-agent/Chart.lock index 5c68948d4..7f169b618 100644 --- a/charts/super-agent/Chart.lock +++ b/charts/super-agent/Chart.lock @@ -4,9 +4,9 @@ dependencies: version: 2.13.0 - name: super-agent-deployment repository: "" - version: 0.0.23-beta + version: 0.0.24-beta - name: common-library repository: https://helm-charts.newrelic.com - version: 1.2.0 -digest: sha256:2d08c8a6be0be9f173c1ddd88fc992e80515e7cc2cb6bb7f93922c4ec96be7c9 -generated: "2024-09-10T23:50:31.41332+02:00" + version: 1.3.0 +digest: sha256:b15bf716a97ac0a42a4908344bf7e145ea63d02e1902f67bfdbd2b16bf74b6f2 +generated: "2024-09-17T10:10:30.582583+02:00" diff --git a/charts/super-agent/Chart.yaml b/charts/super-agent/Chart.yaml index 1ce823f6e..8df400508 100644 --- a/charts/super-agent/Chart.yaml +++ b/charts/super-agent/Chart.yaml @@ -3,7 +3,7 @@ name: super-agent description: Bootstraps New Relic' Super Agent type: application -version: 0.0.19-beta +version: 0.0.20-beta dependencies: - name: flux2 @@ -11,11 +11,11 @@ dependencies: version: 2.13.0 condition: flux2.enabled - name: super-agent-deployment - version: 0.0.23-beta + version: 0.0.24-beta condition: super-agent-deployment.enabled # The following dependency is needed as sub-dependency of super-agent-deployment - name: common-library - version: 1.2.0 + version: 1.3.0 repository: https://helm-charts.newrelic.com keywords: @@ -23,11 +23,15 @@ keywords: - super-agent maintainers: - - name: sigilioso - url: https://github.com/sigilioso + - name: alvarocabanas + url: https://github.com/alvarocabanas + - name: DavSanchez + url: https://github.com/DavSanchez - name: gsanchezgavier url: https://github.com/gsanchezgavier - - name: kang-makes - url: https://github.com/kang-makes - name: paologallinaharbur url: https://github.com/paologallinaharbur + - name: rubenruizdegauna + url: https://github.com/rubenruizdegauna + - name: sigilioso + url: https://github.com/sigilioso diff --git a/charts/super-agent/README.md b/charts/super-agent/README.md index 05f84c58a..356ecb3ba 100644 --- a/charts/super-agent/README.md +++ b/charts/super-agent/README.md @@ -49,17 +49,25 @@ As of the creation of the chart, it has no particularities and this section can | nameOverride | string | `""` | Override the name of the chart | | super-agent-deployment | object | See `values.yaml` | Values related to the super agent's Helm chart release. | | super-agent-deployment.affinity | object | `{}` | Sets pod/node affinities. Can be configured also with `global.affinity` | -| super-agent-deployment.authSecret | object | `{"create":false}` | Settings controlling authentication secret creation. If `create` is true, a Kubernetes secret will be created containing a key named `auth_key`. This secret will be mounted in the deployment pod at the path `/etc/newrelic-super-agent/auth_key` for authentication purposes. | -| super-agent-deployment.cleanupManagedResources | bool | `true` | Enable the cleanup of super-agent managed resources when the chart is uninstalled. If disabled, agents and / or agent configurations managed by the super-agent will not be deleted when the chart is uninstalled. | -| super-agent-deployment.cluster | string | `""` | TODO: Name of the Kubernetes cluster monitored. Can be configured also with `global.cluster`. | +| super-agent-deployment.cleanupManagedResources | bool | `true` | Enable the cleanup of super-agent managed resources when the chart is uninstalled. If disabled, agents and/or agent configurations managed by the super-agent will not be deleted when the chart is uninstalled. | +| super-agent-deployment.cluster | string | `""` | Name of the Kubernetes cluster monitored. Can be configured also with `global.cluster`. | +| super-agent-deployment.config.opamp.auth.organization_id | string | `""` | Organization ID where fleets will live. | +| super-agent-deployment.config.opamp.auth.secret.client_id.base64 | string | `nil` | In case `.config.auth.secret.create` is true, you can set these keys to set client ID directly as base64. This options is mutually exclusive with `plain`. | +| super-agent-deployment.config.opamp.auth.secret.client_id.plain | string | `nil` | In case `.config.auth.secret.create` is true, you can set these keys to set client ID directly as plain text. This options is mutually exclusive with `base64`. | +| super-agent-deployment.config.opamp.auth.secret.client_id.secret_key | string | `client_id` | Key inside the secret containing the client ID. | +| super-agent-deployment.config.opamp.auth.secret.name | string | release name suffixed with "-auth" | Name auth' secret provided by the user. If the creation of this secret is set to `true`, this is the same the secret will have. | +| super-agent-deployment.config.opamp.auth.secret.private_key.base64_pem | string | `nil` | In case `.config.auth.secret.create` is true, you can set these keys to set private key directly as base64. This options is mutually exclusive with `plain_pem`. | +| super-agent-deployment.config.opamp.auth.secret.private_key.plain_pem | string | `nil` | In case `.config.auth.secret.create` is true, you can set these keys to set private key directly as plain text. This options is mutually exclusive with `base64_pem`. | +| super-agent-deployment.config.opamp.auth.secret.private_key.secret_key | string | `private_key` | Key inside the secret containing the private key. | +| super-agent-deployment.config.opamp.enabled | bool | `true` | Enables or disables the auth against fleet control. It implies to disable any fleet communication and running the agent in stand alone mode where only the agents specified on `.config.subAgents` will be launched. | +| super-agent-deployment.config.subAgents | string | `newrelic/io.opentelemetry.collector` (See `values.yaml`) | Values that the fleet is going to have in the deployment. If empty, chart will automatically add `newrelic/io.opentelemetry.collector` subagent. On the other hand, if populated the list of agent created is the one specified overwriting the default. | | super-agent-deployment.config.superAgent | object | See `values.yaml` | Configuration for the Super Agent. | -| super-agent-deployment.config.superAgent.content | object | See `values.yaml` for examples | Here you can set New Relic' Super Agent configuration. | -| super-agent-deployment.config.superAgent.content.server | object | `{"enabled":true}` | And query it as `$ curl localhost:51200/status` | +| super-agent-deployment.config.superAgent.content | object | `{}` | Overrides the configuration that has been created automatically by the chart. This configuration here will be **MERGED** with the configuration specified above. If you need to have you own configuration, disabled the creation of this configMap and create your own. | | super-agent-deployment.config.superAgent.create | bool | `true` | Set if the configMap is going to be created by this chart or the user will provide its own. | | super-agent-deployment.containerSecurityContext | object | `{}` | Sets security context (at container level). Can be configured also with `global.containerSecurityContext` | | super-agent-deployment.customAttributes | object | `{}` | TODO: Adds extra attributes to the cluster and all the metrics emitted to the backend. Can be configured also with `global.customAttributes` | -| super-agent-deployment.customSecretLicenseKey | string | `""` | TODO: In case you don't want to have the license key in you values, this allows you to point to which secret key is the license key located. Can be configured also with `global.customSecretLicenseKey` | -| super-agent-deployment.customSecretName | string | `""` | TODO: In case you don't want to have the license key in you values, this allows you to point to a user created secret to get the key from there. Can be configured also with `global.customSecretName` | +| super-agent-deployment.customSecretLicenseKey | string | `""` | In case you don't want to have the license key in you values, this allows you to point to which secret key is the license key located. Can be configured also with `global.customSecretLicenseKey` | +| super-agent-deployment.customSecretName | string | `""` | In case you don't want to have the license key in you values, this allows you to point to a user created secret to get the key from there. Can be configured also with `global.customSecretName` | | super-agent-deployment.dnsConfig | object | `{}` | Sets pod's dnsConfig. Can be configured also with `global.dnsConfig` | | super-agent-deployment.enabled | bool | `true` | Enable the installation of the Super Agent. This an advanced/debug flag. It should be always be true unless you know what you are going. | | super-agent-deployment.extraEnv | list | `[]` | Add user environment variables to the agent | @@ -71,9 +79,9 @@ As of the creation of the chart, it has no particularities and this section can | super-agent-deployment.image | object | See `values.yaml` | Image for the New Relic Super Agent | | super-agent-deployment.image.pullSecrets | list | `[]` | The secrets that are needed to pull images from a custom registry. | | super-agent-deployment.labels | object | `{}` | Additional labels for chart objects. Can be configured also with `global.labels` | -| super-agent-deployment.licenseKey | string | `""` | TODO: This set this license key to use. Can be configured also with `global.licenseKey` | +| super-agent-deployment.licenseKey | string | `""` | This set this license key to use. Can be configured also with `global.licenseKey` | | super-agent-deployment.nodeSelector | object | `{}` | Sets pod's node selector. Can be configured also with `global.nodeSelector` | -| super-agent-deployment.nrStaging | bool | `false` | Send the metrics to the staging backend. Requires a valid staging license key. Can be configured also with `global.nrStaging` When enabled, in case `authSecret.create` is set to `true`, OpAMP `endpoint` and auth `token_url` need to be updated. | +| super-agent-deployment.nrStaging | bool | `false` | Send the metrics to the staging backend. Requires a valid staging license key. Can be configured also with `global.nrStaging` | | super-agent-deployment.podAnnotations | object | `{}` | Annotations to be added to all pods created by the integration. | | super-agent-deployment.podLabels | object | `{}` | Additional labels for chart pods. Can be configured also with `global.podLabels` | | super-agent-deployment.podSecurityContext | object | `{}` | Sets security context (at pod level). Can be configured also with `global.podSecurityContext` | @@ -83,14 +91,14 @@ As of the creation of the chart, it has no particularities and this section can | super-agent-deployment.resources | object | `{}` | Resource limits to be added to all pods created by the integration. | | super-agent-deployment.serviceAccount | object | See `values.yaml` | Settings controlling ServiceAccount creation. | | super-agent-deployment.serviceAccount.create | bool | `true` | Whether the chart should automatically create the ServiceAccount objects required to run. | -| super-agent-deployment.subAgents | object | See `values.yaml` for examples | Values that the fleet is going to have in the deployment. | | super-agent-deployment.tolerations | list | `[]` | Sets pod's tolerations to node taints. Can be configured also with `global.tolerations` | -| super-agent-deployment.verboseLog | bool | `false` | TODO: Sets the debug logs to this integration or all integrations if it is set globally. Can be configured also with `global.verboseLog` | +| super-agent-deployment.verboseLog | bool | `false` | Sets the debug logs to this integration or all integrations if it is set globally. Can be configured also with `global.verboseLog` | ## Maintainers -* [sigilioso](https://github.com/sigilioso) +* [alvarocabanas](https://github.com/alvarocabanas) +* [DavSanchez](https://github.com/DavSanchez) * [gsanchezgavier](https://github.com/gsanchezgavier) -* [kang-makes](https://github.com/kang-makes) -* [marcsanmi](https://github.com/marcsanmi) * [paologallinaharbur](https://github.com/paologallinaharbur) +* [rubenruizdegauna](https://github.com/rubenruizdegauna) +* [sigilioso](https://github.com/sigilioso) diff --git a/charts/super-agent/charts/super-agent-deployment/Chart.yaml b/charts/super-agent/charts/super-agent-deployment/Chart.yaml index eed9cbd31..f55eaaec9 100644 --- a/charts/super-agent/charts/super-agent-deployment/Chart.yaml +++ b/charts/super-agent/charts/super-agent-deployment/Chart.yaml @@ -4,7 +4,7 @@ description: A Helm chart to install New Relic Super agent on Kubernetes type: application -version: 0.0.23-beta +version: 0.0.24-beta keywords: - newrelic diff --git a/charts/super-agent/charts/super-agent-deployment/templates/_helpers.tpl b/charts/super-agent/charts/super-agent-deployment/templates/_helpers.tpl index 56bd29b08..ede9ef6e9 100644 --- a/charts/super-agent/charts/super-agent-deployment/templates/_helpers.tpl +++ b/charts/super-agent/charts/super-agent-deployment/templates/_helpers.tpl @@ -2,19 +2,80 @@ Return the name of the configMap holding the Super Agent's config. Defaults to release's fill name suffiexed with "-config" */ -}} {{- define "newrelic-super-agent.config.name" -}} -{{- (include "newrelic.common.naming.truncateToDNSWithSuffix" ( dict "name" "local-data" "suffix" "superagent-config" )) -}} +{{- include "newrelic.common.naming.truncateToDNSWithSuffix" ( dict "name" "local-data" "suffix" "superagent-config" ) -}} {{- end -}} + + +{{- /* +Test that the value of `.Values.config.subAgents` exists and its valid. If empty, returns the default. +*/ -}} +{{- define "newrelic-super-agent.config.agents.yaml" -}} +{{- if (.Values.config).subAgents -}} +{{- $agents := dict -}} +{{- range $subAgentName, $subAgentConfig := (.Values.config).subAgents -}} + {{- if not ($subAgentConfig).type -}} + {{- fail (printf "Agent %s does not have agent type" $subAgentName) -}} + {{- end -}} + {{- $agents = mustMerge $agents (dict $subAgentName $subAgentConfig) -}} +{{- end -}} +{{- $agents | toYaml -}} +{{- else -}} +{{- /* Default agents for Kubernetes */ -}} +open-telemetry: + type: newrelic/io.opentelemetry.collector:0.2.0 + content: + chart_values: + global: + licenseKey: ${nr-env:NR_LICENSE_KEY} + cluster: ${nr-env:NR_CLUSTER_NAME} + nrStaging: ${nr-env:NR_STAGING} + verboseLog: ${nr-env:NR_VERBOSE} + region: ${nr-env:NR_REGION} +{{- end -}} +{{- end -}} + + + +{{- /* +Return to which endpoint should the super agent connect to get opamp data +*/ -}} +{{- define "newrelic-super-agent.config.endpoints.opamp" -}} +{{- $region := include "newrelic.common.region" . -}} + +{{- if eq $region "Staging" -}} + https://opamp.staging-service.newrelic.com/v1/opamp +{{- else if eq $region "EU" -}} + https://opamp.service.eu.newrelic.com/v1/opamp +{{- else if eq $region "US" -}} + https://opamp.service.newrelic.com/v1/opamp +{{- else if eq $region "Local" -}} + {{- /* Accessing the value directly without protection. A developer should now how to read the error. */ -}} + {{ .Values.development.backend.opamp }} +{{- else -}} + {{- fail "Unknown/unsupported region set for this chart" -}} +{{- end -}} +{{- end -}} + + + {{- /* Return to which endpoint should the super agent ask to renew its token */ -}} {{- define "newrelic-super-agent.config.endpoints.tokenRenewal" -}} -{{- if include "newrelic.common.nrStaging" . -}} +{{- $region := include "newrelic.common.region" . -}} + +{{- if eq $region "Staging" -}} https://system-identity-oauth.staging-service.newrelic.com/oauth2/token -{{- else if .Values.euEndpoints -}} +{{- else if eq $region "EU" -}} https://system-identity-oauth.service.newrelic.com/oauth2/token -{{- else -}} +{{- else if eq $region "US" -}} https://system-identity-oauth.service.newrelic.com/oauth2/token +{{- else if eq $region "Local" -}} + {{- /* Accessing the value directly without protection. A developer should now how to read the error. */ -}} + {{ .Values.development.backend.tokenRenewal }} +{{- else -}} + {{- fail "Unknown/unsupported region set for this chart" -}} {{- end -}} {{- end -}} @@ -24,12 +85,19 @@ Return to which endpoint should the super agent ask to renew its token Return to which endpoint should the super agent register its system identity */ -}} {{- define "newrelic-super-agent.config.endpoints.systemIdentityRegistration" -}} -{{- if include "newrelic.common.nrStaging" . -}} +{{- $region := include "newrelic.common.region" . -}} + +{{- if eq $region "Staging" -}} https://staging-api.newrelic.com/graphql -{{- else if .Values.euEndpoints -}} +{{- else if eq $region "EU" -}} https://api.eu.newrelic.com/graphql -{{- else -}} +{{- else if eq $region "US" -}} https://api.newrelic.com/graphql +{{- else if eq $region "Local" -}} + {{- /* Accessing the value directly without protection. A developer should now how to read the error. */ -}} + {{ .Values.development.backend.systemIdentityRegistration }} +{{- else -}} + {{- fail "Unknown/unsupported region set for this chart" -}} {{- end -}} {{- end -}} @@ -41,33 +109,43 @@ cluster name, licenses, and custom attributes */ -}} {{- define "newrelic-super-agent.config.content" -}} {{- /* -This snippet should execute always to block all unsupported features from the common-lirary that are not yet supported -by this chart. - -{{- /* -TODO: There are a lot of TODOs to be made in this chart yet and some of them are going to impact the YAML that holds +TODO: There are a lot of TODOs to be made in this chart yet and some of them are going to impact the YAML that holds the config. If you need a list of TODOs, just `grep TODO` on the `values.yaml` and look for things that are yet to be implemented. */ -}} -{{- $config := .Values.config.superAgent.content | default dict -}} -{{- $config = mustMergeOverwrite (dict "k8s" (dict "cluster_name" (include "newrelic.common.cluster" .))) $config -}} -{{- $config = mustMergeOverwrite (dict "k8s" (dict "namespace" .Release.Namespace)) $config -}} -{{- if .Values.config.superAgent.content -}} -{{- if .Values.config.superAgent.content.opamp -}} -{{- if .Values.config.auth }} -{{- if .Values.config.auth.enabled -}} -{{- $opamp := (dict "opamp" (dict "auth_config" (dict "token_url" (include "newrelic-super-agent.config.endpoints.tokenRenewal" .) "provider" "local" "private_key_path" "/etc/newrelic-super-agent/keys/from-secret.key"))) -}} -{{- $_ := $opamp | mustMergeOverwrite $config -}} -{{- end -}} -{{- end -}} +{{- /* config set here so we can populate it as we enable and disable snippets. */ -}} +{{- $config := dict "server" (dict "enabled" true) -}} + +{{- /* Add to config k8s cluster and namespace config */ -}} +{{- $k8s := (dict "cluster_name" (include "newrelic.common.cluster" .) "namespace" .Release.Namespace) -}} +{{- $config = mustMerge $config (dict "k8s" $k8s) -}} + +{{- /* Add opamp if enabled */ -}} +{{- if ((.Values.config).opamp).enabled -}} + {{- $opamp := (dict "endpoint" (include "newrelic-super-agent.config.endpoints.opamp" .)) -}} + + {{- $auth_config := dict "token_url" (include "newrelic-super-agent.config.endpoints.tokenRenewal" .) "provider" "local" "private_key_path" "/etc/newrelic-super-agent/keys/from-secret.key" -}} + {{- $opamp = mustMerge $opamp (dict "auth_config" $auth_config) -}} + + {{- $config = mustMerge $config (dict "opamp" $opamp) -}} {{- end -}} + +{{- /* Add subagents to the config */ -}} +{{- $agents := dict -}} +{{- range $subagent, $object := (include "newrelic-super-agent.config.agents.yaml" . | fromYaml) -}} + {{- $agents = mustMerge $agents (dict $subagent (dict "agent_type" $object.type)) -}} {{- end -}} +{{- $config = mustMerge $config (dict "agents" $agents) -}} +{{- /* Overwrite $config with everything in `config.superAgent.content` if present */ -}} +{{- $config = mustMergeOverwrite $config (deepCopy (((.Values.config).superAgent).content | default dict)) -}} {{- $config | toYaml -}} {{- end -}} + + {{- /* These are the defaults that are used for all the containers in this chart */ -}} {{- define "newrelic-super-agent.securityContext.containerDefaults" -}} runAsUser: 1000 @@ -76,6 +154,8 @@ allowPrivilegeEscalation: false readOnlyRootFilesystem: true {{- end -}} + + {{- /* Allow to change pod defaults dynamically */ -}} {{- define "newrelic-super-agent.securityContext.container" -}} {{- $defaults := fromYaml ( include "newrelic-super-agent.securityContext.containerDefaults" . ) -}} @@ -90,23 +170,130 @@ readOnlyRootFilesystem: true - - {{- /* Return .Values.config.auth.organizationId and fails if it does not exists */ -}} {{- define "newrelic-super-agent.auth.organizationId" -}} -{{- if not ((.Values.config).auth).organizationId -}} - {{- fail ".Values.config.auth.organizationId is required." -}} +{{- if (((.Values.config).opamp).auth).organizationId -}} + {{- .Values.config.auth.organizationId -}} +{{- else -}} + {{- fail ".config.auth.organizationId is required." -}} {{- end -}} -{{- .Values.config.auth.organizationId -}} {{- end -}} {{- /* -Releases with "-auth" suffix. +Check if .Values.config.auth.secret.name exists and use it to name auth' secret. If it does not exist, fallback to the name +of the releases with "-auth" suffix. */ -}} {{- define "newrelic-super-agent.auth.secret.name" -}} - {{- include "newrelic.common.naming.truncateToDNSWithSuffix" (dict "name" (include "newrelic.common.naming.fullname" .) "suffix" "auth") }} +{{- $secretName := (((((.Values.config).opamp).auth).secret).name) -}} +{{- if $secretName -}} + {{- $secretName -}} +{{- else -}} + {{- include "newrelic.common.naming.truncateToDNSWithSuffix" (dict "name" (include "newrelic.common.naming.fullname" .) "suffix" "auth" ) }} +{{- end -}} +{{- end -}} + + + +{{- /* +Helper to toggle the creation of the job that creates and registers the system identity. +*/ -}} +{{- define "newrelic-super-agent.auth.secret.shouldRunJob" -}} +{{- $privateKey := include "newrelic-super-agent.auth.secret.privateKey.data" . -}} +{{- $clientId := include "newrelic-super-agent.auth.secret.clientId.data" . -}} + +{{- if and ((.Values.config).opamp).enabled ((((.Values.config).opamp).auth).secret).create (not $privateKey) (not $clientId) -}} + true +{{- end -}} +{{- end -}} + + + +{{- /* +Helper to toggle the creation of the secret that has the system identity as values. +*/ -}} +{{- define "newrelic-super-agent.auth.secret.shouldTemplate" -}} +{{- if and ((.Values.config).opamp).enabled ((((.Values.config).opamp).auth).secret).create -}} + {{- $privateKey := include "newrelic-super-agent.auth.secret.privateKey.data" . -}} + {{- $clientId := include "newrelic-super-agent.auth.secret.clientId.data" . -}} + + {{- if and $privateKey $clientId -}} + true + {{- else if or $privateKey $clientId -}} + {{- fail "If you provide your own system identity data you have to provide both private key and client id" -}} + {{- end -}} +{{- end -}} +{{- end -}} + + + +{{- /* +Check if .Values.config.auth.secret.private_key.secret_key exists and use it for the key in the secret containing the private +key needed for the system identity. Fallbacks to `private_key`. +*/ -}} +{{- define "newrelic-super-agent.auth.secret.privateKey.key" -}} +{{- $key := ((((((.Values.config).opamp).auth).secret).private_key).secret_key) -}} +{{- if $key -}} + {{- $key -}} +{{- else -}} + private_key +{{- end -}} +{{- end -}} + + + +{{- /* +Check if .Values.config.auth.secret.private_key.(plain_pem or base64_pem) exists and use it for as the private certificate for +auth. If no ceritifcate is provided, it defaults to `""` (empty string) so this helper can be used directly as a test. +*/ -}} +{{- define "newrelic-super-agent.auth.secret.privateKey.data" -}} +{{- $plain_pem := ((((((.Values.config).opamp).auth).secret).private_key).plain_pem) -}} +{{- $base64_pem := ((((((.Values.config).opamp).auth).secret).private_key).base64_pem) -}} +{{- if and $plain_pem $base64_pem -}} + {{- fail "Only one of base64_pem or plain_pem should be provided it you want to provide your own certificate." -}} +{{- else if $base64_pem -}} + {{- $base64_pem }} +{{- else if $plain_pem -}} + {{- $plain_pem | b64enc -}} +{{- else -}} + {{- /* Empty string */ -}} +{{- end -}} +{{- end -}} + + + +{{- /* +Check if .Values.config.auth.secret.client_id.secret_key exists and use it for the key in the secret containing the client id +needed for the system identity. Fallbacks to `client_id`. +*/ -}} +{{- define "newrelic-super-agent.auth.secret.clientId.key" -}} +{{- $key := ((((((.Values.config).opamp).auth).secret).client_id).secret_key) -}} +{{- if $key -}} + {{- $key -}} +{{- else -}} + CLIENT_ID +{{- end -}} +{{- end -}} + + + +{{- /* +Check if .Values.config.auth.secret.client_id.(plain or base64) exists and use it for as the client id for auth. If no +value is provided, it defaults to `""` (empty string) so this helper can be used directly as a test. +*/ -}} +{{- define "newrelic-super-agent.auth.secret.clientId.data" -}} +{{- $plain := ((((((.Values.config).opamp).auth).secret).client_id).plain) -}} +{{- $base64 := ((((((.Values.config).opamp).auth).secret).client_id).base64) -}} +{{- if and $plain $base64 -}} + {{- fail "Only one of base64 or plain should be provided it you want to provide your own client id." -}} +{{- else if $base64 -}} + {{- $base64 }} +{{- else if $plain -}} + {{- $plain | b64enc -}} +{{- else -}} + {{- /* Empty string */ -}} +{{- end -}} {{- end -}} diff --git a/charts/super-agent/charts/super-agent-deployment/templates/configmap-subagent-configs.yaml b/charts/super-agent/charts/super-agent-deployment/templates/configmap-subagent-configs.yaml index ea03ff1c2..cf12cea3e 100644 --- a/charts/super-agent/charts/super-agent-deployment/templates/configmap-subagent-configs.yaml +++ b/charts/super-agent/charts/super-agent-deployment/templates/configmap-subagent-configs.yaml @@ -1,4 +1,4 @@ -{{- range $subAgentName, $subAgentConfig := .Values.config.subAgents -}} +{{- range $subAgentName, $subAgentConfig := (include "newrelic-super-agent.config.agents.yaml" . | fromYaml) -}} {{- $name := include "newrelic.common.naming.truncateToDNSWithSuffix" (dict "name" "local-data" "suffix" $subAgentName) }} --- kind: ConfigMap @@ -10,6 +10,10 @@ metadata: subagent: {{ $subAgentName }} apiVersion: v1 data: +{{- if not $subAgentConfig.content }} + local_config: "" +{{- else }} local_config: | {{- $subAgentConfig.content | toYaml | nindent 4 }} {{- end }} +{{- end }} diff --git a/charts/super-agent/charts/super-agent-deployment/templates/deployment-superagent.yaml b/charts/super-agent/charts/super-agent-deployment/templates/deployment-superagent.yaml index 57fd8554c..2def77735 100644 --- a/charts/super-agent/charts/super-agent-deployment/templates/deployment-superagent.yaml +++ b/charts/super-agent/charts/super-agent-deployment/templates/deployment-superagent.yaml @@ -12,6 +12,15 @@ spec: template: metadata: annotations: + {{/* TODO: This hash is not reliable anymore. The identity is being generated/patched by a job. + With the introduction of this job, this charts is not configurable/instalable with ArgoCD/Flux as the reconcile loop + will empty the secret that the job has filled. + + We need the config to be splitable somehow or leave another orphan object on the cluster. + + This comment (and the mechanisim added in the PR when we left this comment) block the automatic upgrade feature. + + See: charts/super-agent/charts/super-agent-deployment/templates/preinstall-job-register-system-identity.yaml */ -}} checksum/agent-config: {{ include (print $.Template.BasePath "/configmap-superagent-config.yaml") . | sha256sum }} checksum/subagent-config: {{ include (print $.Template.BasePath "/configmap-subagent-configs.yaml") . | sha256sum }} {{- with .Values.podAnnotations }} @@ -55,15 +64,24 @@ spec: imagePullPolicy: {{ .Values.image.pullPolicy }} env: - {{- if .Values.config.auth }} - {{- if .Values.config.auth.enabled }} + {{- if ((.Values.config).opamp).enabled }} - name: NR_SA_OPAMP__AUTH_CONFIG__CLIENT_ID valueFrom: secretKeyRef: name: {{ include "newrelic-super-agent.auth.secret.name" . }} - key: CLIENT_ID + key: {{ include "newrelic-super-agent.auth.secret.clientId.key" . }} + - name: NR_SA_OPAMP__HEADERS__API-KEY + valueFrom: + secretKeyRef: + name: {{ include "newrelic.common.license.secretName" . }} + key: {{ include "newrelic.common.license.secretKeyName" . }} {{- end }} + {{- if include "newrelic.common.verboseLog" . }} + - name: NR_SA_LOG__LEVEL + value: debug {{- end }} + + {{- /* ----- Variables used to send data downstream to subagents */}} - name: NR_LICENSE_KEY valueFrom: secretKeyRef: @@ -71,13 +89,14 @@ spec: key: {{ include "newrelic.common.license.secretKeyName" . }} - name: NR_CLUSTER_NAME value: {{ include "newrelic.common.cluster" . }} - {{- if .Values.config.superAgent.content.opamp }} - - name: NR_SA_OPAMP__HEADERS__API-KEY - valueFrom: - secretKeyRef: - name: {{ include "newrelic.common.license.secretName" . }} - key: {{ include "newrelic.common.license.secretKeyName" . }} - {{- end }} + - name: NR_STAGING + value: {{ include "newrelic.common.nrStaging.value" . | quote }} + - name: NR_VERBOSE + value: {{ include "newrelic.common.verboseLog.valueAsBoolean" . | quote }} + - name: NR_REGION + value: {{ include "newrelic.common.region" . }} + {{- /* ----- Variables used to send data downstream to subagents */}} + {{- with .Values.extraEnv }} {{- toYaml . | nindent 12 }} {{- end }} @@ -85,21 +104,22 @@ spec: envFrom: {{- toYaml . | nindent 12 }} {{- end }} - # TODO: Add probes + + # TODO: Probe the status server. volumeMounts: - name: super-agent-config mountPath: /etc/newrelic-super-agent readOnly: true - # TODO: when releasing we should check if this is still needed and if we need to persist the data. + # TODO: when releasing we should check if this is still needed and/or if we need to persist the data. - mountPath: /var/lib/newrelic-super-agent name: var-lib-newrelic-super-agent readOnly: false - {{- if .Values.config.auth }} - {{- if .Values.config.auth.enabled }} + {{- if ((.Values.config).opamp).enabled }} - name: auth-secret-private-key - mountPath: "/etc/newrelic-super-agent/keys" - {{- end }} + mountPath: "/etc/newrelic-super-agent/keys/from-secret.key" + subPath: {{ include "newrelic-super-agent.auth.secret.privateKey.key" . }} + readOnly: true {{- end }} {{- with .Values.extraVolumeMounts }} {{- toYaml . | nindent 12 }} @@ -116,16 +136,11 @@ spec: path: config.yaml - name: var-lib-newrelic-super-agent emptyDir: {} - {{- if .Values.config.auth }} - {{- if .Values.config.auth.enabled }} + {{- if ((.Values.config).opamp).enabled }} - name: auth-secret-private-key secret: secretName: {{ include "newrelic-super-agent.auth.secret.name" . }} - items: - - key: private_key - path: from-secret.key {{- end }} - {{- end }} {{- with .Values.extraVolumes }} {{- toYaml . | nindent 8 }} {{- end }} diff --git a/charts/super-agent/charts/super-agent-deployment/templates/preinstall-job-register-system-identity.yaml b/charts/super-agent/charts/super-agent-deployment/templates/preinstall-job-register-system-identity.yaml index c916e3d81..68b6f86c3 100644 --- a/charts/super-agent/charts/super-agent-deployment/templates/preinstall-job-register-system-identity.yaml +++ b/charts/super-agent/charts/super-agent-deployment/templates/preinstall-job-register-system-identity.yaml @@ -1,11 +1,33 @@ -{{- if .Values.config.auth -}} -{{- if and .Values.config.auth.enabled .Values.config.auth.secret.create -}} +{{- if include "newrelic-super-agent.auth.secret.shouldRunJob" . -}} +{{- /* +User key secret is used only in the step that create the system identity. +The secret that is created by the common-library does not allow to add annotations so the secret is removed +once the installation hook is finished, so I have to add it as a hook. +*/ -}} +{{- if not (include "newrelic.common.userKey._customSecretName" .) }} +--- +apiVersion: v1 +kind: Secret +metadata: + annotations: + helm.sh/hook: pre-install,pre-upgrade + helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded + helm.sh/hook-weight: "-1010" + labels: + {{- include "newrelic.common.labels" . | nindent 4 }} + name: {{ include "newrelic.common.naming.truncateToDNSWithSuffix" (dict "name" (include "newrelic.common.naming.fullname" .) "suffix" "preinstall-user-key" ) }} + namespace: {{ .Release.Namespace }} +data: + {{ include "newrelic.common.userKey.secretKeyName" . }}: {{ include "newrelic.common.userKey._userKey" . | b64enc }} +{{- end }} +--- apiVersion: batch/v1 kind: Job metadata: annotations: - helm.sh/hook: pre-install # TODO we cannot enable auth after installation, we should add pre-upgrade and check if the secret exists + helm.sh/hook: pre-install,pre-upgrade helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded + helm.sh/hook-weight: "-1005" name: {{ include "newrelic.common.naming.truncateToDNSWithSuffix" (dict "name" (include "newrelic.common.naming.fullname" .) "suffix" "system-identity-installer" ) }} namespace: {{ .Release.Namespace }} spec: @@ -13,18 +35,35 @@ spec: template: spec: restartPolicy: Never - serviceAccountName: {{ include "newrelic.common.serviceAccount.name" . }}-auth + serviceAccountName: {{ include "newrelic.common.naming.truncateToDNSWithSuffix" (dict "name" (include "newrelic.common.serviceAccount.name" .) "suffix" "auth" ) }} containers: - name: register-system-identity image: alpine + env: + - name: USER_KEY + valueFrom: + secretKeyRef: + {{- if include "newrelic.common.userKey._customSecretName" . }} + name: {{ include "newrelic.common.userKey.secretName" . }} + {{- else }} + name: {{ include "newrelic.common.naming.truncateToDNSWithSuffix" (dict "name" (include "newrelic.common.naming.fullname" .) "suffix" "preinstall-user-key" ) }} + {{- end }} + key: {{ include "newrelic.common.userKey.secretKeyName" . }} command: - ash args: - -c - | - set -uo pipefail + set -euo pipefail apk update - apk add curl kubectl jq openssl + apk add kubectl + + if kubectl get secret {{ include "newrelic-super-agent.auth.secret.name" . }}; then + echo System identity already exists. Exiting gracefully... + exit 0 + fi + + apk add curl jq openssl TEMPORAL_FOLDER=gen-folder mkdir $TEMPORAL_FOLDER openssl genrsa -out "$TEMPORAL_FOLDER/key" 4096 @@ -46,7 +85,7 @@ spec: curl \ -s -w "%{http_code}" \ -H "Content-Type: application/json" \ - -H "API-Key: {{ .Values.config.auth.userApiKey }}" \ + -H "API-Key: $USER_KEY" \ -o "$TEMPORAL_FOLDER/response.json" \ --data @- \ "{{ include "newrelic-super-agent.config.endpoints.systemIdentityRegistration" . }}" @@ -62,7 +101,7 @@ spec: ERROR_MESSAGE=$(jq -r '.errors[0].message // "NOERROR"' "$TEMPORAL_FOLDER/response.json") if [ "$ERROR_MESSAGE" != "NOERROR" ]; then - echo "Error creating an identity: $ERROR_MESSAGE" + echo "Failed to create a New Relic System Identity for OpAMP communication authentication. Please verify that your User Key is valid and that your Account Organization has the necessary permissions to create a System Identity: $ERROR_MESSAGE" exit 1 fi @@ -80,6 +119,7 @@ metadata: annotations: helm.sh/hook: pre-install helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded + helm.sh/hook-weight: "-1010" labels: {{- include "newrelic.common.labels" . | nindent 4 }} name: {{ include "newrelic.common.naming.truncateToDNSWithSuffix" (dict "name" (include "newrelic.common.naming.fullname" .) "suffix" "auth") }} @@ -99,6 +139,7 @@ metadata: annotations: helm.sh/hook: pre-install helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded + helm.sh/hook-weight: "-1009" labels: {{- include "newrelic.common.labels" . | nindent 4 }} name: {{ include "newrelic.common.naming.truncateToDNSWithSuffix" (dict "name" (include "newrelic.common.naming.fullname" .) "suffix" "auth") }} @@ -109,11 +150,11 @@ roleRef: name: {{ include "newrelic.common.naming.truncateToDNSWithSuffix" (dict "name" (include "newrelic.common.naming.fullname" .) "suffix" "auth") }} subjects: - kind: ServiceAccount - name: {{ include "newrelic.common.serviceAccount.name" . }}-auth + name: {{ include "newrelic.common.naming.truncateToDNSWithSuffix" (dict "name" (include "newrelic.common.serviceAccount.name" .) "suffix" "auth" ) }} namespace: {{ .Release.Namespace }} -{{- end -}} +{{- end }} -{{ if include "newrelic.common.serviceAccount.create" . }} +{{- if include "newrelic.common.serviceAccount.create" . }} --- apiVersion: v1 kind: ServiceAccount @@ -121,13 +162,13 @@ metadata: annotations: helm.sh/hook: pre-install helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded + helm.sh/hook-weight: "-1010" {{- if include "newrelic.common.serviceAccount.annotations" . }} {{- include "newrelic.common.serviceAccount.annotations" . | nindent 4 }} {{- end }} labels: {{- include "newrelic.common.labels" . | nindent 4 }} - name: {{ include "newrelic.common.serviceAccount.name" . }}-auth + name: {{ include "newrelic.common.naming.truncateToDNSWithSuffix" (dict "name" (include "newrelic.common.serviceAccount.name" .) "suffix" "auth" ) }} namespace: {{ .Release.Namespace }} {{- end -}} {{- end -}} -{{- end -}} diff --git a/charts/super-agent/charts/super-agent-deployment/templates/rbac.yaml b/charts/super-agent/charts/super-agent-deployment/templates/rbac.yaml index b53af418a..cd939c717 100644 --- a/charts/super-agent/charts/super-agent-deployment/templates/rbac.yaml +++ b/charts/super-agent/charts/super-agent-deployment/templates/rbac.yaml @@ -11,7 +11,7 @@ rules: - apiGroups: - source.toolkit.fluxcd.io - helm.toolkit.fluxcd.io - resources: ["*"] + resources: [ "*" ] verbs: - get - list @@ -31,7 +31,7 @@ metadata: namespace: {{ .Release.Namespace }} rules: - apiGroups: [ "" ] - resources: ["configmaps"] + resources: [ "configmaps" ] verbs: - get - list @@ -41,7 +41,7 @@ rules: - patch - update - apiGroups: [ "" ] - resources: ["namespaces"] + resources: [ "namespaces" ] verbs: - get - apiGroups: [ "apps" ] diff --git a/charts/super-agent/charts/super-agent-deployment/templates/secret-sa-auth.yaml b/charts/super-agent/charts/super-agent-deployment/templates/secret-sa-auth.yaml new file mode 100644 index 000000000..206058082 --- /dev/null +++ b/charts/super-agent/charts/super-agent-deployment/templates/secret-sa-auth.yaml @@ -0,0 +1,13 @@ +{{- if include "newrelic-super-agent.auth.secret.shouldTemplate" . -}} +--- +kind: Secret +metadata: + name: {{ include "newrelic-super-agent.auth.secret.name" . }} + namespace: {{ .Release.Namespace }} + labels: + {{- include "newrelic.common.labels" . | nindent 4 }} +apiVersion: v1 +data: + {{ include "newrelic-super-agent.auth.secret.privateKey.key" . }}: {{ include "newrelic-super-agent.auth.secret.privateKey.data" . }} + {{ include "newrelic-super-agent.auth.secret.clientId.key" . }}: {{ include "newrelic-super-agent.auth.secret.clientId.data" . }} +{{- end }} diff --git a/charts/super-agent/charts/super-agent-deployment/templates/serviceaccount.yaml b/charts/super-agent/charts/super-agent-deployment/templates/serviceaccount.yaml index b1e74523e..262350d8a 100644 --- a/charts/super-agent/charts/super-agent-deployment/templates/serviceaccount.yaml +++ b/charts/super-agent/charts/super-agent-deployment/templates/serviceaccount.yaml @@ -1,4 +1,4 @@ -{{- if include "newrelic.common.serviceAccount.create" . -}} +{{- if and (include "newrelic.common.serviceAccount.create" .) .Values.rbac.create -}} apiVersion: v1 kind: ServiceAccount metadata: diff --git a/charts/super-agent/charts/super-agent-deployment/templates/uninstall-job.yaml b/charts/super-agent/charts/super-agent-deployment/templates/uninstall-job.yaml index 6ee715cce..dc2e47318 100644 --- a/charts/super-agent/charts/super-agent-deployment/templates/uninstall-job.yaml +++ b/charts/super-agent/charts/super-agent-deployment/templates/uninstall-job.yaml @@ -25,7 +25,7 @@ spec: serviceAccountName: {{ include "newrelic.common.serviceAccount.name" . }} containers: - name: delete-managed-resources - image: bitnami/kubectl + image: bitnami/kubectl # TODO: Pin version to the latest that we support. command: - bash args: @@ -42,8 +42,17 @@ spec: # Delete the CRs managed by the super-agent if the corresponding CRDs exist {{ range $i, $cr := $saCRList }} if kubectl api-resources -o name |grep {{ $cr }}; then - kubectl delete {{ $cr }} -n {{ $.Release.Namespace }} -l {{ $saResourcesLabelSelector }} + kubectl -n {{ $.Release.Namespace }} delete {{ $cr }} -l {{ $saResourcesLabelSelector }} fi - {{ end -}} - + {{ end }} + {{- if include "newrelic-super-agent.auth.secret.shouldRunJob" . }} + - name: delete-system-identity + image: bitnami/kubectl # TODO: Pin version to the latest that we support. + command: + - bash + args: + - -c + - | + kubectl -n {{ $.Release.Namespace }} delete secret {{ include "newrelic-super-agent.auth.secret.name" . }} + {{- end }} {{- end -}} diff --git a/charts/super-agent/charts/super-agent-deployment/tests/auth_secret_test.yaml b/charts/super-agent/charts/super-agent-deployment/tests/auth_secret_test.yaml new file mode 100644 index 000000000..8a476f74f --- /dev/null +++ b/charts/super-agent/charts/super-agent-deployment/tests/auth_secret_test.yaml @@ -0,0 +1,111 @@ +suite: test super agent deployment's auth configurations +templates: + - templates/secret-sa-auth.yaml + - templates/configmap-superagent-config.yaml + - templates/configmap-subagent-configs.yaml + - templates/deployment-superagent.yaml +release: + name: my-release + namespace: my-namespace + +tests: + - it: authSecret is created and mounted correctly by default + set: + cluster: test + config: + opamp: + auth: + secret: + private_key: + base64_pem: dGVzdC1rZXk= + client_id: + base64: dGVzdC1rZXk= + asserts: + - template: templates/deployment-superagent.yaml + equal: + path: spec.template.spec.containers[0].volumeMounts + value: + - name: super-agent-config + mountPath: /etc/newrelic-super-agent + readOnly: true + - mountPath: /var/lib/newrelic-super-agent + name: var-lib-newrelic-super-agent + readOnly: false + - mountPath: /etc/newrelic-super-agent/keys/from-secret.key + name: auth-secret-private-key + readOnly: true + subPath: private_key + - template: templates/deployment-superagent.yaml + equal: + path: spec.template.spec.volumes + value: + - name: super-agent-config + configMap: + name: local-data-super-agent + items: + - key: local_config + path: config.yaml + - name: var-lib-newrelic-super-agent + emptyDir: {} + - name: auth-secret-private-key + secret: + secretName: my-release-super-agent-deployment-auth + - template: templates/secret-sa-auth.yaml + equal: + path: metadata.name + value: my-release-super-agent-deployment-auth + - template: templates/secret-sa-auth.yaml + equal: + path: data.private_key + value: dGVzdC1rZXk= + - template: templates/secret-sa-auth.yaml + equal: + path: data.CLIENT_ID + value: dGVzdC1rZXk= + + - it: no mount and secret is created when auth is disabled + set: + cluster: test + config: + opamp: + auth: + enable: false + asserts: + - template: templates/deployment-superagent.yaml + notContains: + path: spec.template.spec.containers[0].volumeMounts + content: + name: auth-secret-private-key + - template: templates/deployment-superagent.yaml + notContains: + path: spec.template.spec.volumes + content: + name: auth-secret-private-key + + - it: secre creation fails when you only provide private_key + set: + cluster: test + config: + opamp: + auth: + secret: + private_key: + base64_pem: dGVzdC1rZXk= + asserts: + - template: templates/secret-sa-auth.yaml + failedTemplate: + errorMessage: If you provide your own system identity data you have to provide both private key and client id + + - it: secre creation fails when you only provide CLIENT_ID + set: + cluster: test + config: + opamp: + auth: + secret: + client_id: + base64: dGVzdC1rZXk= + asserts: + - template: templates/secret-sa-auth.yaml + failedTemplate: + errorMessage: If you provide your own system identity data you have to provide both private key and client id diff --git a/charts/super-agent/charts/super-agent-deployment/tests/configmap_fleet_configs_test.yaml b/charts/super-agent/charts/super-agent-deployment/tests/configmap_fleet_configs_test.yaml index 37f04b042..fee54065e 100644 --- a/charts/super-agent/charts/super-agent-deployment/tests/configmap_fleet_configs_test.yaml +++ b/charts/super-agent/charts/super-agent-deployment/tests/configmap_fleet_configs_test.yaml @@ -5,28 +5,31 @@ release: name: my-release namespace: my-namespace tests: - - it: default value can be overridden + - it: A malformed subAgent fail with a useful error message set: config: subAgents: - open-telemetry: null + open-telemetry: ~ asserts: - - hasDocuments: - count: 0 - - it: super agent's config template correctly + - failedTemplate: + errorMessage: Agent open-telemetry does not have agent type + + - it: default config for each subAgent can be overridden set: config: subAgents: - open-telemetry: null test-0: + type: org.newrelic/test:0.0.0 content: a: test value: 0 test-1: + type: org.newrelic/test:0.0.1 content: a: test value: 1 test-2: + type: org.newrelic/test:0.0.2 content: a: test aYAML: diff --git a/charts/super-agent/charts/super-agent-deployment/tests/configmap_superagent_config_test.yaml b/charts/super-agent/charts/super-agent-deployment/tests/configmap_superagent_config_test.yaml index 06b995787..a889a30cc 100644 --- a/charts/super-agent/charts/super-agent-deployment/tests/configmap_superagent_config_test.yaml +++ b/charts/super-agent/charts/super-agent-deployment/tests/configmap_superagent_config_test.yaml @@ -13,6 +13,26 @@ tests: asserts: - hasDocuments: count: 0 + + - it: opamp can be disabled + set: + cluster: my-cluster + config: + opamp: + enabled: false + asserts: + - equal: + path: data["local_config"] + value: | + agents: + open-telemetry: + agent_type: newrelic/io.opentelemetry.collector:0.2.0 + k8s: + cluster_name: my-cluster + namespace: my-namespace + server: + enabled: true + - it: super agent's config always include cluster_name, namespace and defaults set: cluster: my-cluster @@ -28,8 +48,15 @@ tests: k8s: cluster_name: my-cluster namespace: my-namespace + opamp: + auth_config: + private_key_path: /etc/newrelic-super-agent/keys/from-secret.key + provider: local + token_url: https://system-identity-oauth.service.newrelic.com/oauth2/token + endpoint: https://opamp.service.newrelic.com/v1/opamp server: enabled: true + - it: super agent's config templates set: cluster: my-cluster @@ -48,10 +75,17 @@ tests: k8s: cluster_name: my-cluster namespace: my-namespace + opamp: + auth_config: + private_key_path: /etc/newrelic-super-agent/keys/from-secret.key + provider: local + token_url: https://system-identity-oauth.service.newrelic.com/oauth2/token + endpoint: https://opamp.service.newrelic.com/v1/opamp server: enabled: true test: value test2: value2 + - it: cluster_name and namespace from config have precedence set: cluster: my-cluster @@ -73,21 +107,21 @@ tests: k8s: cluster_name: config-cluster namespace: config-namespace + opamp: + auth_config: + private_key_path: /etc/newrelic-super-agent/keys/from-secret.key + provider: local + token_url: https://system-identity-oauth.service.newrelic.com/oauth2/token + endpoint: https://opamp.service.newrelic.com/v1/opamp server: enabled: true test: value test2: value2 - - it: super agent's config always include cluster_name, namespace and defaults + + - it: super agent's config always include cluster_name, namespace, defaults, and honor the EU endpoint. set: cluster: my-cluster - config: - superAgent: - content: - opamp: - endpoint: https://opamp.service.eu.newrelic.com/v1/opamp - auth: - enabled: true - euEndpoints: true + region: eu asserts: - equal: path: data["local_config"] @@ -106,3 +140,31 @@ tests: endpoint: https://opamp.service.eu.newrelic.com/v1/opamp server: enabled: true + + - it: default config for super agent can be overridden + template: templates/configmap-superagent-config.yaml + set: + cluster: my-cluster + region: eu + config: + subAgents: + test-0: + type: org.newrelic/test:0.0.0 + content: + a: test + value: 0 + test-1: + type: org.newrelic/test:0.0.1 + content: + a: test + value: 1 + test-2: + type: org.newrelic/test:0.0.2 + content: + a: test + aYAML: + canI: HaveSomeYAML + asserts: + - matchRegex: + path: data["local_config"] + pattern: "agents:\n test-0:\n agent_type: org.newrelic/test:0.0.0\n test-1:\n agent_type: org.newrelic/test:0.0.1\n test-2:\n agent_type: org.newrelic/test:0.0.2" diff --git a/charts/super-agent/charts/super-agent-deployment/tests/deployment_superagent_env_test.yaml b/charts/super-agent/charts/super-agent-deployment/tests/deployment_superagent_env_test.yaml index a2821bd25..8a937ec24 100644 --- a/charts/super-agent/charts/super-agent-deployment/tests/deployment_superagent_env_test.yaml +++ b/charts/super-agent/charts/super-agent-deployment/tests/deployment_superagent_env_test.yaml @@ -1,4 +1,4 @@ -suite: test super agent deployment's securityContext +suite: test super agent deployment's env vars are injected templates: - templates/deployment-superagent.yaml - templates/configmap-superagent-config.yaml @@ -12,9 +12,9 @@ tests: cluster: test licenseKey: fake-license asserts: - - equal: - path: spec.template.spec.containers[0].env[0] - value: + - contains: + path: spec.template.spec.containers[0].env + content: name: NR_LICENSE_KEY valueFrom: secretKeyRef: @@ -27,10 +27,11 @@ tests: cluster: test customSecretName: "custom-secret" customSecretLicenseKey: "custom-key" + region: us # With a custom secret we cannot know the region so we have to ask for it. asserts: - - equal: - path: spec.template.spec.containers[0].env[0] - value: + - contains: + path: spec.template.spec.containers[0].env + content: name: NR_LICENSE_KEY valueFrom: secretKeyRef: @@ -48,9 +49,9 @@ tests: opamp: endpoint: test asserts: - - equal: - path: spec.template.spec.containers[0].env[2] - value: + - contains: + path: spec.template.spec.containers[0].env + content: name: NR_SA_OPAMP__HEADERS__API-KEY valueFrom: secretKeyRef: @@ -63,15 +64,16 @@ tests: cluster: test customSecretName: "custom-secret" customSecretLicenseKey: "custom-key" + region: us # With a custom secret we cannot know the region so we have to ask for it. config: superAgent: content: opamp: endpoint: test asserts: - - equal: - path: spec.template.spec.containers[0].env[2] - value: + - contains: + path: spec.template.spec.containers[0].env + content: name: NR_SA_OPAMP__HEADERS__API-KEY valueFrom: secretKeyRef: @@ -82,9 +84,9 @@ tests: set: cluster: test asserts: - - equal: - path: spec.template.spec.containers[0].env[1] - value: + - contains: + path: spec.template.spec.containers[0].env + content: name: NR_CLUSTER_NAME value: test - template: templates/deployment-superagent.yaml \ No newline at end of file + template: templates/deployment-superagent.yaml diff --git a/charts/super-agent/charts/super-agent-deployment/tests/deployment_superagent_subagent_configs_test.yaml b/charts/super-agent/charts/super-agent-deployment/tests/deployment_superagent_subagent_configs_test.yaml index a432311de..fb5fec557 100644 --- a/charts/super-agent/charts/super-agent-deployment/tests/deployment_superagent_subagent_configs_test.yaml +++ b/charts/super-agent/charts/super-agent-deployment/tests/deployment_superagent_subagent_configs_test.yaml @@ -7,21 +7,23 @@ release: name: my-release namespace: my-namespace tests: - - it: there is no subagent configuration set: cluster: test config: subAgents: test-0: + type: org.newrelic/test:0.0.0 content: a: test value: 0 test-1: + type: org.newrelic/test:0.0.1 content: a: test value: 1 test-2: + type: org.newrelic/test:0.0.2 content: a: test aYAML: @@ -37,6 +39,10 @@ tests: - mountPath: /var/lib/newrelic-super-agent name: var-lib-newrelic-super-agent readOnly: false + - mountPath: /etc/newrelic-super-agent/keys/from-secret.key + name: auth-secret-private-key + readOnly: true + subPath: private_key - template: templates/deployment-superagent.yaml equal: path: spec.template.spec.volumes @@ -49,6 +55,6 @@ tests: path: config.yaml - name: var-lib-newrelic-super-agent emptyDir: {} - - - + - name: auth-secret-private-key + secret: + secretName: my-release-super-agent-deployment-auth diff --git a/charts/super-agent/ci/test-values.yaml b/charts/super-agent/ci/test-values.yaml index f47bc9af8..fb6384cd2 100644 --- a/charts/super-agent/ci/test-values.yaml +++ b/charts/super-agent/ci/test-values.yaml @@ -1,3 +1,10 @@ -super-agent-deployment: +global: cluster: sa-cluster licenseKey: test + +super-agent-deployment: + config: + auth: + # There is no way to test the auth flow for now. Tests get stuck as the pre-install job cannot succeed to create a new system identity. + # Until we have a better idea or we are able to create a fake oauth server, we have to disable this. + enabled: false diff --git a/charts/super-agent/values.yaml b/charts/super-agent/values.yaml index ed762ac42..7dd851b14 100644 --- a/charts/super-agent/values.yaml +++ b/charts/super-agent/values.yaml @@ -10,13 +10,13 @@ super-agent-deployment: # you know what you are going. enabled: true - # -- TODO: Name of the Kubernetes cluster monitored. Can be configured also with `global.cluster`. + # -- Name of the Kubernetes cluster monitored. Can be configured also with `global.cluster`. cluster: "" - # -- TODO: This set this license key to use. Can be configured also with `global.licenseKey` + # -- This set this license key to use. Can be configured also with `global.licenseKey` licenseKey: "" - # -- TODO: In case you don't want to have the license key in you values, this allows you to point to a user created secret to get the key from there. Can be configured also with `global.customSecretName` + # -- In case you don't want to have the license key in you values, this allows you to point to a user created secret to get the key from there. Can be configured also with `global.customSecretName` customSecretName: "" - # -- TODO: In case you don't want to have the license key in you values, this allows you to point to which secret key is the license key located. Can be configured also with `global.customSecretLicenseKey` + # -- In case you don't want to have the license key in you values, this allows you to point to which secret key is the license key located. Can be configured also with `global.customSecretLicenseKey` customSecretLicenseKey: "" # -- Image for the New Relic Super Agent @@ -94,71 +94,84 @@ super-agent-deployment: # @default -- `false` nrStaging: - # -- (bool) Changes default endpoint to point to EU backend. - # @default -- `false` - euEndpoints: - fedramp: # -- (bool) TODO: Enables FedRAMP. Can be configured also with `global.fedramp.enabled` # @default -- `false` enabled: - # -- (bool) TODO: Sets the debug logs to this integration or all integrations if it is set globally. Can be configured also with `global.verboseLog` + # -- (bool) Sets the debug logs to this integration or all integrations if it is set globally. Can be configured also with `global.verboseLog` # @default -- `false` verboseLog: # -- Enable the cleanup of super-agent managed resources when the chart is uninstalled. - # If disabled, agents and / or agent configurations managed by the super-agent will not be deleted when the chart is uninstalled. + # If disabled, agents and/or agent configurations managed by the super-agent will not be deleted when the chart is uninstalled. cleanupManagedResources: true config: - auth: - enabled: false - organizationId: - userApiKey: - secret: - create: true - # -- Configuration for the Super Agent. # @default -- See `values.yaml` superAgent: # -- Set if the configMap is going to be created by this chart or the user will provide its own. create: true - # -- Here you can set New Relic' Super Agent configuration. - # @default -- See `values.yaml` for examples - content: - agents: - open-telemetry: - agent_type: newrelic/io.opentelemetry.collector:0.2.0 - - # opamp: - # # TODO The endpoint should be set automatically based on the licenseKey and on the nrStaging option if opamp.enable=true - # endpoint: https://opamp.service.newrelic.com/v1/opamp - # endpoint: https://opamp.service.eu.newrelic.com/v1/opamp - - # -- This option enables a status server that can be useful for troubleshooting. - # -- Port-forward it `$ kubectl port-forward pod/{pod-name} 51200:51200` - # -- And query it as `$ curl localhost:51200/status` - server: - enabled: true - # port: 51200 - - - # -- Values that the fleet is going to have in the deployment. - # @default -- See `values.yaml` for examples + # -- Overrides the configuration that has been created automatically by the chart. + # This configuration here will be **MERGED** with the configuration specified above. + # If you need to have you own configuration, disabled the creation of this configMap and create your own. + content: {} + + # -- Values that the fleet is going to have in the deployment. If empty, chart will automatically add `newrelic/io.opentelemetry.collector` subagent. + # On the other hand, if populated the list of agent created is the one specified overwriting the default. + # @default -- `newrelic/io.opentelemetry.collector` (See `values.yaml`) subAgents: - # The values of the fleet depends on the deployment itself. Each subagent has a different set of variables so you have to go to the subagent documentation - # find the configuration needed for the subagent. - # - open-telemetry: - content: - # chart_version: "0.4.0" - chart_values: - licenseKey: ${nr-env:NR_LICENSE_KEY} - cluster: ${nr-env:NR_CLUSTER_NAME} - # TODO the following values are set twice in the config, we have to add some logic to improve UX either in the chart or in the agentType - # customSecretName: "" - # customSecretLicenseKey: "" + # The values of the fleet depends on the deployment itself. Each subagent has a different set of variables so you have to go to the subagent documentation + # find the configuration needed for the subagent. + # + # The example below, open-telemetry, is enabled by default if no subagent is set up. + # open-telemetry: + # type: newrelic/io.opentelemetry.collector:0.2.0 + # content: + # chart_values: + # global: + # licenseKey: ${nr-env:NR_LICENSE_KEY} + # cluster: ${nr-env:NR_CLUSTER_NAME} + # nrStaging: ${nr-env:NR_STAGING} + # verboseLog: ${nr-env:NR_VERBOSE} + # region: ${nr-env:NR_REGION} + # # you can set here modifications to the open telemetry chart + + opamp: + # -- Enables or disables the auth against fleet control. It implies to disable any fleet communication and running the agent + # in stand alone mode where only the agents specified on `.config.subAgents` will be launched. + enabled: true + + auth: + # -- Organization ID where fleets will live. + organization_id: "" + secret: + create: true + # -- Name auth' secret provided by the user. If the creation of this secret is set to `true`, this is the same the secret + # will have. + # @default -- release name suffixed with "-auth" + name: + private_key: + # -- Key inside the secret containing the private key. + # @default -- `private_key` + secret_key: + # -- In case `.config.auth.secret.create` is true, you can set these keys to set private key directly as base64. + # This options is mutually exclusive with `plain_pem`. + base64_pem: + # -- In case `.config.auth.secret.create` is true, you can set these keys to set private key directly as plain text. + # This options is mutually exclusive with `base64_pem`. + plain_pem: + client_id: + # -- Key inside the secret containing the client ID. + # @default -- `client_id` + secret_key: + # -- In case `.config.auth.secret.create` is true, you can set these keys to set client ID directly as base64. + # This options is mutually exclusive with `plain`. + base64: + # -- In case `.config.auth.secret.create` is true, you can set these keys to set client ID directly as plain text. + # This options is mutually exclusive with `base64`. + plain: # -- Values for the Flux chat. Ref.: https://github.com/fluxcd-community/helm-charts/blob/flux2-2.10.2/charts/flux2/values.yaml