diff --git a/.github/configs/helmValues-helm-validation-kubecost.yaml b/.github/configs/helmValues-helm-validation-kubecost.yaml new file mode 100644 index 0000000..e604cc3 --- /dev/null +++ b/.github/configs/helmValues-helm-validation-kubecost.yaml @@ -0,0 +1,65 @@ +global: + clusterId: chart-testing + federatedStorage: + config: |- + type: cluster + config: + host: kubecost-local-store.finops-agent-chart-test + port: 9006 + http_config: + tls_config: + insecure_skip_verify: true +persistence: + enabled: false +extraObjects: +- apiVersion: apps/v1 + kind: Deployment + metadata: + labels: + app: kubecost-local-store + name: kubecost-local-store + namespace: finops-agent-chart-test + spec: + selector: + matchLabels: + app: kubecost-local-store + template: + metadata: + labels: + app: kubecost-local-store + spec: + containers: + - name: local-object-store + args: + - cluster-storage + env: + - name: CONFIG_PATH + value: /var/configs/ + - name: RESOLUTION_10M_RETENTION + value: "1" + - name: RESOLUTION_1H_RETENTION + value: "1" + - name: RESOLUTION_1D_RETENTION + value: "1" + image: gcr.io/kubecost1/cost-model-nightly:latest + imagePullPolicy: Always + ports: + - containerPort: 9006 + name: tcp-api + protocol: TCP + readinessProbe: + failureThreshold: 200 + httpGet: + path: /healthz + port: 9006 + scheme: HTTP + initialDelaySeconds: 10 + periodSeconds: 10 + successThreshold: 1 + timeoutSeconds: 1 + volumeMounts: + - mountPath: /var/configs + name: file-storage + volumes: + - name: file-storage + emptyDir: {} diff --git a/.github/workflows/helm-validation.yaml b/.github/workflows/helm-validation.yaml new file mode 100644 index 0000000..dd616e5 --- /dev/null +++ b/.github/workflows/helm-validation.yaml @@ -0,0 +1,89 @@ +name: Helm Validation +permissions: + contents: read + +on: + workflow_dispatch: {} + pull_request_target: + types: [opened, synchronize, reopened, ready_for_review] + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true # cancel if new commits are pushed to the same branch + +jobs: + chart-test: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v5 + with: + fetch-depth: 0 + + - name: Set up Helm + uses: azure/setup-helm@v4 + with: + version: latest # latest version + + - uses: actions/setup-python@v5 + with: + python-version: '3.13' + check-latest: true + + - name: Set up chart-testing + uses: helm/chart-testing-action@v2.7.0 + + - name: Run chart-testing (list-changed) + id: list-changed + run: | + changed=$(ct list-changed --target-branch ${{ github.event.repository.default_branch }}) + if [[ -n "$changed" ]]; then + echo "changed=true" >> "$GITHUB_OUTPUT" + fi + + - name: Run chart-testing (lint) + if: steps.list-changed.outputs.changed == 'true' + run: | + ct lint \ + --all \ + --validate-maintainers=false \ + --target-branch ${{ github.event.repository.default_branch }} + + - name: Create kind cluster + if: steps.list-changed.outputs.changed == 'true' + uses: helm/kind-action@v1 + + - name: Run chart-testing (kubecost specific) + if: steps.list-changed.outputs.changed == 'true' + run: | + helm install finops-agent-chart-test \ + --namespace finops-agent-chart-test --create-namespace \ + --wait --wait-for-jobs --timeout 300s \ + ./charts/finops-agent \ + -f .github/configs/helmValues-helm-validation-kubecost.yaml + + - name: Wait for ready + if: steps.list-changed.outputs.changed == 'true' + run: | + kubectl wait -n finops-agent-chart-test \ + --for=condition=ready pod \ + --selector app.kubernetes.io/instance=finops-agent-chart-test \ + --timeout=120s + + whitespace-check: + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v5 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.13' + + - name: Check for trailing whitespace in all files + run: | + if grep -r --include="*.*" "[[:blank:]]$" charts/; then + echo "Error: Found trailing whitespace in .md or .tpl files" + exit 1 + fi diff --git a/charts/finops-agent/README.md b/charts/finops-agent/README.md index 8e25bbc..ba0275d 100644 --- a/charts/finops-agent/README.md +++ b/charts/finops-agent/README.md @@ -324,6 +324,7 @@ A default `StorageClass` is needed in the Kubernetes cluster to dynamically prov | `rbac.create` | Whether to create & use RBAC resources or not | `true` | | `rbac.clusterRole.create` | Whether to create & use ClusterRole resources or not | `true` | | `localStoreEnabled` | this values is only used by the Kubecost main chart, it must be set to false for the FinOps Agent to work when deployed by the FinOps Agent chart | `false` | +| `extraObjects` | Additional custom objects to deploy with the chart | `[]` | ## License diff --git a/charts/finops-agent/ci/helmValues-chart-testing-values.yaml b/charts/finops-agent/ci/helmValues-chart-testing-values.yaml new file mode 100644 index 0000000..78eb35a --- /dev/null +++ b/charts/finops-agent/ci/helmValues-chart-testing-values.yaml @@ -0,0 +1,2 @@ +global: + clusterId: chart-testing diff --git a/charts/finops-agent/templates/extra-manifests.yaml b/charts/finops-agent/templates/extra-manifests.yaml new file mode 100644 index 0000000..edad397 --- /dev/null +++ b/charts/finops-agent/templates/extra-manifests.yaml @@ -0,0 +1,8 @@ +{{ range .Values.extraObjects }} +--- +{{- if typeIs "string" . }} + {{- tpl . $ }} +{{- else }} + {{- tpl (toYaml .) $ }} +{{- end }} +{{ end }} \ No newline at end of file diff --git a/charts/finops-agent/values.yaml b/charts/finops-agent/values.yaml index bb8a050..fadbc73 100644 --- a/charts/finops-agent/values.yaml +++ b/charts/finops-agent/values.yaml @@ -32,7 +32,7 @@ global: # secret_key: xxx existingSecret: "" # If you want to use a different file name for the federated storage config, you can set the fileName value. - fileName: federated-store.yaml # set this value to change what the file name for the yaml config is + fileName: federated-store.yaml # set this value to change what the file name for the yaml config is ## @param cspPricingApiKey.existingSecret The name of an existing secret containing a GCP API key. If set, this existing secret will be used instead of creating a new one. ## @param cspPricingApiKey.apiKey The GCP API key value used to access pricing data. Required for GCP clusters to fetch on-demand pricing. ## If set, a new secret will be created with this API key. Leave empty if using an existing secret via cspPricingApiKey.existingSecret. @@ -136,7 +136,6 @@ useHelmHooks: true ## @param image.digest IBM FinOps Agent image digest in the way sha256:aa.... Please note this parameter, if set, will override the tag ## @param image.pullPolicy IBM FinOps Agent image pull policy ## @param image.pullSecrets Specify docker-registry secret names as an array -## @param image.debug Specify if debug logs should be enabled ## image: registry: icr.io @@ -152,7 +151,6 @@ image: ## - myRegistryKeySecretName ## pullSecrets: [] - debug: false ## @param fullImageName If set, this will override the image name and tag. fullImageName: "" @@ -332,7 +330,7 @@ containerSecurityContext: readOnlyRootFilesystem: true allowPrivilegeEscalation: false capabilities: - drop: [ "ALL" ] + drop: ["ALL"] seccompProfile: type: "RuntimeDefault" ## Configure extra options for the FinOps Agent container's liveness, readiness and startup probes @@ -652,3 +650,25 @@ rbac: create: true clusterRole: create: true +extraObjects: [] +# - apiVersion: external-secrets.io/v1 +# kind: ExternalSecret +# metadata: +# name: example +# spec: +# refreshInterval: 1h +# secretStoreRef: +# name: secretstore-sample +# kind: SecretStore +# target: +# name: secret-to-be-created +# creationPolicy: Owner +# data: +# - secretKey: secret-key-to-be-managed +# remoteRef: +# key: provider-key +# version: provider-key-version +# property: provider-key-property +# dataFrom: +# - extract: +# key: remote-key-in-the-provider