> ## Documentation Index
> Fetch the complete documentation index at: https://docs.thoras.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# ArgoCD

> ArgoCD is a declarative, GitOps continuous delivery tool for Kubernetes applications. This section provides considerations for using ArgoCD to manage Thoras-targeted workloads.

#### Using ArgoCD to deploy Thoras

Thoras uses Kubernetes Secrets to share RDBMS passwords between components. Due
to how ArgoCD interprets Helm templates, it may detect these Secrets as
constantly out of sync, resulting in unnecessary updates.

To prevent these updates, add this `spec.ignoreDifferences` configuration to
your ArgoCD `Application` manifest. This tells ArgoCD to ignore changes to the
data fields of thoras Secrets after they are created. It also ignores replica
count changes on the `thoras-forecast-worker` deployment, which Thoras manages
directly.

#### Example Application config

```yaml theme={null}
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: thoras
  namespace: argocd
spec:
  project: default
  source:
    chart: thoras
    helm:
      parameters:
        - name: imageCredentials.password
          value: <Thoras License Key>
    repoURL: https://thoras-ai.github.io/helm-charts
    targetRevision: <Thoras Chart Version>
  destination:
    namespace: thoras
    server: https://kubernetes.default.svc
  syncPolicy:
    automated: {}
  ignoreDifferences:
    - jsonPointers:
        - /data
      kind: Secret
      name: thoras-timescale-password
    - jsonPointers:
        - /data
      kind: Secret
      name: thoras-webhooks-cert
    - group: admissionregistration.k8s.io
      kind: MutatingWebhookConfiguration
      jqPathExpressions:
        - '.webhooks[]?.clientConfig.caBundle'
    - group: admissionregistration.k8s.io
      kind: ValidatingWebhookConfiguration
      jqPathExpressions:
        - '.webhooks[]?.clientConfig.caBundle'
    - jsonPointers:
        - /spec/replicas
      kind: Deployment
      name: thoras-forecast-worker
```

#### Using ArgoCD to manage a Thoras horizontally controlled workload

When Thoras manages horizontal scaling for a workload, it uses a validation
webhook to prevent the default Kubernetes Horizontal Pod Autoscaler (HPA) from
reducing replicas during anticipated usage spikes.

By design, this ensures workloads remain scaled up until Thoras determines it's
safe to scale down. However, ArgoCD interprets these blocked scale-down attempts
as HPA errors. This can cause the Application to appear in a degraded state even
though the workload is healthy.

To prevent this, you can customize ArgoCD's health assessment logic for HPAs so
that these Thoras-specific conditions are handled correctly.

### When Do I Need This?

You only need this customization if all of the following are true:

* The workload is horizontally controlled by Thoras.
* You are using ArgoCD to monitor the workload state.
* You notice ArgoCD incorrectly marking the HPA as **Degraded** when Thoras
  blocks a scale-down.

If your workloads are **not** using Thoras for horizontal scaling, this
customization is unnecessary.

**1. Edit the ArgoCD ConfigMap**:

Open the `argocd-cm` ConfigMap in the `argocd` namespace:

```bash theme={null}
kubectl edit configmap argocd-cm -n argocd
```

**2. Add the following customizations under** `data`:

```
resource.customizations.useOpenLibs.autoscaling_HorizontalPodAutoscaler: "true"
resource.customizations.health.autoscaling_HorizontalPodAutoscaler: |
  hs = {}
  if obj.status ~= nil then
    if obj.status.conditions ~= nil then
      for i, condition in ipairs(obj.status.conditions) do
        -- Mark Degraded only for certain conditions
        if condition.type == "Ready" and condition.status == "False" then
          hs.status = "Degraded"
          hs.message = condition.message
          return hs
        end
        -- Ignore AbleToScale=False with FailedUpdateScale reason caused by Thoras
        if condition.type == "AbleToScale" and condition.status == "False" and condition.reason == "FailedUpdateScale" and string.find(condition.message or "", "target is already at Thoras desired replicas") ~= nil then
          hs.status = "Healthy"
          hs.message = "Target is at Thoras desired replicas"
          return hs
        end
        -- Mark Healthy for Ready=True or ScalingActive=True
        if (condition.type == "Ready" or condition.type == "ScalingActive") and condition.status == "True" then
          hs.status = "Healthy"
          hs.message = condition.message
          return hs
        end
      end
    end
  end

  hs.status = "Progressing"
  hs.message = "Waiting for HPA to become healthy"
  return hs
```

**3. Edit the ArgoCD ConfigMap**:

**4. Restart ArgoCD components** (to apply changes):

```bash theme={null}
kubectl rollout restart deployment argocd-repo-server -n argocd
kubectl rollout restart deployment argocd-applicationset-controller -n argocd
```
