> For the complete documentation index, see [llms.txt](https://docs.cybus.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.cybus.io/2-4-1/documentation/installation-and-upgrades/upgrading-connectware/upgrading-connectware-kubernetes/upgrading-connectware-helm-charts-to-3-0-0.md).

# Upgrading Connectware Helm Charts to 3.0.0

{% hint style="info" %}
Chart 3.0.0 marks the first release of the Cybus Helm charts as a standalone update, separate from a Connectware release. The 3.0.0 Helm chart upgrade only affects the chart; your Connectware version is unchanged.
{% endhint %}

Chart versioning and Connectware versioning are now decoupled. This means that improvements to the Cybus Helm chart can be released independently of Connectware releases. The [compatibility matrix](/2-4-1/cybus-helm-charts/compatibility-matrix.md) shows which chart versions work with which Connectware versions. This makes it easy to plan upgrades for each type on its own schedule.

For a full list of new features and improvements in this release, see the [changelog](/2-4-1/changelog.md).

## Switching to an OCI Registry

Starting with chart 3.0.0, charts are distributed via an [OCI registry](https://helm.sh/docs/topics/registries/) instead of a [Helm chart repository](https://helm.sh/docs/topics/chart_repository/).

Each chart version is now pulled directly by its exact version tag from an OCI registry, similar to how container images are handled. You do not have to manage a registered repo or run `helm repo update` before installing a new version anymore.

Especially for offline installations, this is a significant simplification: charts and container images can now be mirrored to the same registry, removing the need to host the chart separately. Use `oci://repo.cybus.io` as the registry. Make sure any proxies or network access rules allow traffic to that address.

Helm version 4 is required.

## Before You Begin

Chart 3.0.0 restructures the `values.yaml` file for both the `connectware` chart and the `connectware-agent` chart. Many keys are renamed, several components have been moved from `global.*` into top-level blocks, and resource defaults have been reduced for most components.

This guide is split into two parts so that you can follow only the parts that apply to your installation:

* **Part A**: changes to the `connectware` chart `values.yaml` file.
* **Part B**: changes to the `connectware-agent` chart `values.yaml` file. Applies whether the agent chart runs standalone or as a subchart of the `connectware` chart.

Make sure to read the entire guide before you start. Some changes, such as security context overrides and protocol-mapper agent migration, require careful hand-merging to avoid stripping defaults or orphaning agents.

### Prerequisites

* A working installation of one or both of the following:
  * `connectware` Helm chart versions 2.1.0 to 2.4.0
  * `connectware-agent` Helm chart versions 2.1.0 to 2.4.0
* Chart 2.1.0 is the minimum supported starting point. If you are on an older version, [upgrade to 2.1.0](/2-4-1/documentation/installation-and-upgrades/upgrading-connectware/upgrading-connectware-kubernetes/upgrading-connectware-to-2-1-0-kubernetes.md) first.
* Access to your current `values.yaml` file or files.
* Backups of your [Connectware database](/2-4-1/documentation/installation-and-upgrades/backing-up-the-connectware-database.md), Persistent Volumes, `values.yaml` file or files, and all service commissioning files.
* [Helm version 4](https://helm.sh/docs/intro/quickstart/#install-helm) is installed on your system.
* [kubectl](https://kubernetes.io/docs/tasks/tools/#kubectl) is installed on your system.
* You know the name and namespace of your installations. See [Obtaining the Name, Namespace, and Version of Your Installation](/2-4-1/cybus-helm-charts/working-with-cybus-helm-charts.md#obtaining-the-name-namespace-and-version-of-your-installation).
* Access to OCI registry `oci://repo.cybus.io`, or the Helm charts [copied locally](/2-4-1/cybus-helm-charts/working-with-cybus-helm-charts/registries-and-pull-secrets.md#using-a-custom-registry).
* Kubernetes version >= 1.25: These new chart versions will not deploy on Kubernetes lower than 1.25.

{% hint style="info" %}

## A note on quoting strings

YAML interprets certain unquoted values as numbers, booleans, or dates. To avoid accidental type coercion, wrap string values in single or double quotes whenever they contain digits, punctuation, or look like a boolean. The examples in this guide follow this convention.
{% endhint %}

## AI-Assisted Migration

You can migrate your `values.yaml` file using AI or manually. If you prefer the manual approach, skip this section and follow [Part A](#part-a-connectware-chart-migration) and [Part B](#part-b-connectware-agent-chart-migration) instead. If you use the AI approach, it handles the key renames and structural moves in your `values.yaml` file. However, you still need to perform additional manual actions, as described below.

<details>

<summary><strong>1. Migrating the values.yaml File</strong></summary>

Download the skill below and run it with a [tool supporting the Agent Skills format](https://agentskills.io/clients) against your existing `values.yaml` file to automate the key renames and moves. The better the model's reasoning, the more reliable the output.

{% hint style="warning" %}
Always review the output before applying it.
{% endhint %}

{% file src="/files/fAU060C6ZVi0pyJyJOHj" %}

The skill covers `values.yaml` key changes; work through the items in the next step for everything else.

</details>

<details>

<summary><strong>2. Before Running helm upgrade</strong></summary>

* **Recreate the image pull secret if you used a different value for `global.registryUser` than `license`.** Create a pull secret manually and reference it through `global.image.pullSecrets`, or pods will fail with `ImagePullBackOff`. See [A1. License Values Changes](#a1.-license-values-changes).
* **Verify customized security contexts after migration.** Overrides replace chart defaults and do not merge — the migrated output may be missing defaults. See [A3. Security Contexts](#a3.-security-contexts) and [B3. Security Contexts](#b3.-security-contexts).
* **Decide whether to keep the previous resource defaults.** If your `values.yaml` does not set resource requests and limits, the new lower defaults apply after the upgrade. See [A8. Resources Moved to Per-Component](#a8.-resources-moved-to-per-component) and [B7. Resource Defaults](#b7.-resource-defaults).
* **Set `authServer.replicas: 1` if you want the old single-replica behavior.** The default changed from `1` to `2`. See [A10. Auth-Server Default Replicas](#a10.-auth-server-default-replicas).
* **Detect cluster resource renames for `connectware-agent` installations with affected names.** If your release is named `connectware`, or combined release-plus-agent names exceed 52 characters, run `helm diff upgrade` first. See [B8. Cluster Resource Name Changes](#b8.-cluster-resource-name-changes).
* **Re-add TCP ports for `Cybus::IngressRoute` resources.** The ingress LoadBalancer Service no longer exposes ports `40000` to `40009` by default. If you have `Cybus::IngressRoute` resources of type `tcp`, add their `connectwarePort` to `connectwareIngress.service.ports` or they become unreachable. See [A13. Ingress Service Ports for TCP IngressRoutes](#a13.-ingress-service-ports-for-tcp-ingressroutes).
* **Review the Container Manager RBAC change if your cluster restricts RBAC manifests.** The chart replaces the `pod-manager` Role with a `connectware-${INSTALLATION_NAME}-pod-reader` Role that only grants `get`, `list`, and `watch` on `pods` and `pods/log`, and binds a dedicated ServiceAccount instead of the namespace `default` ServiceAccount. If your cluster requires approval for changes to Roles, RoleBindings, or ServiceAccounts, share the diff with the team that approves RBAC manifests before running `helm upgrade`.

</details>

<details>

<summary><strong>3. Running helm upgrade</strong></summary>

Follow the [Upgrade Procedure](#upgrade-procedure) to run `helm upgrade`. Then continue to the next step for post-upgrade actions.

</details>

<details>

<summary><strong>4. After Running helm upgrade</strong></summary>

None of these items require changes to `values.yaml`.

* **Update external selectors that reference the `app` label.** The label changed from `app=<component>` to `app.kubernetes.io/name=<component>`. See [A12. Workload Label Rename](#a12.-workload-label-rename).
* **Update references to the renamed ingress Deployment.** The Deployment `connectware` is now `connectware-ingress`. See [A7. Components Moved Out of global](#a7.-components-moved-out-of-global).
* **Re-register migrated protocol-mapper agents.** Connectware treats agents migrated from the `connectware` chart as new entities. See [Post-Upgrade Actions](#post-upgrade-actions).
* **Review resource usage and set production limits.** See [Post-Upgrade Actions](#post-upgrade-actions).

</details>

## Upgrade Procedure

The procedure is divided into the following parts:

* **Part A — Connectware Chart Migration**: Update the `connectware` chart `values.yaml` file to match the new chart schema.
* **Part B — Connectware-Agent Chart Migration**: Update the `connectware-agent` chart `values.yaml` file. Applies to both standalone and subchart deployments.
* **Running the Upgrade**: Apply the updated values using `helm upgrade`.
* **Post-Upgrade Actions**: Re-register protocol-mapper agents and review resource requests.

{% hint style="warning" %}
As part of this upgrade, you will need to fully stop Connectware and any standalone `connectware-agent` releases, since some of the changes cannot be done in a rolling restart.
{% endhint %}

<details>

<summary><strong>Overview of Mandatory Migration Steps</strong></summary>

`connectware` chart steps:

1. [**License Keys**](#a1.-license-values-changes)
2. [**Image Version**](#a2.-image-version)
3. [**Security Contexts**](#a3.-security-contexts)
4. [**Storage to Persistence**](#a4.-storage-to-persistence)
5. [**User Management to Authentication**](#a5.-user-management-to-authentication)
6. [**Other Global Value Changes**](#a6.-other-global-value-changes)
7. [**Components Moved Out of global**](#a7.-components-moved-out-of-global)
8. [**Resources Moved to Per-Component**](#a8.-resources-moved-to-per-component)
9. [**CybusMQ Broker Value Changes**](#a9.-cybusmq-broker-value-changes)
10. [**Auth-Server Default Replicas**](#a10.-auth-server-default-replicas)
11. [**Reserved MFA Environment Variables**](#a11.-reserved-mfa-environment-variables)
12. [**Workload Label Rename**](#a12.-workload-label-rename)
13. [**Ingress Service Ports for TCP IngressRoutes**](#a13.-ingress-service-ports-for-tcp-ingressroutes)
14. [**NATS Metrics Path Change**](#a14.-nats-metrics-path-change)

`connectware-agent` chart steps:

1. [**Protocol-Mapper Agents Structure**](#b1.-protocol-mapper-agents-structure)
2. [**Image Version**](#b2.-image-version)
3. [**Security Contexts**](#b3.-security-contexts)
4. [**Storage to Persistence**](#b4.-storage-to-persistence)
5. [**TLS CA Configuration Renames**](#b5.-tls-ca-configuration-renames)
6. [**Reserved Environment Variables**](#b6.-reserved-environment-variables)
7. [**Resource Defaults**](#b7.-resource-defaults)
8. [**Cluster Resource Name Changes**](#b8.-cluster-resource-name-changes)

</details>

## Part A: Connectware Chart Migration

Apply the following changes to your `connectware` chart `values.yaml` file. If you only want to update the `connectware-agent` chart standalone, skip to [Part B](#part-b-connectware-agent-chart-migration).

### A1. License Values Changes

#### Why the Change?

Normalizing value names and capitalization to avoid future confusion.

#### What You Need to Do

<details>

<summary><strong>Updating the License Values</strong></summary>

* Delete `global.registryUser`. If you authenticated against the image registry with a custom user, create a pull secret manually and reference it via `global.image.pullSecrets`. See [Configuring Registries and Pull Secrets](/2-4-1/cybus-helm-charts/working-with-cybus-helm-charts/registries-and-pull-secrets.md).
* Rename `global.licensekey` to `global.licenseKey` (capital K).
* If `global.licenseFile` is set to `online`, change it to `""` (empty string) or remove it. Real license file bodies used for offline installations remain unchanged. If you do not have this key in your `values.yaml`, you do not need to add it.

**Before**

{% code lineNumbers="true" %}

```yaml
global:
  registryUser: license
  licensekey: xxxxxxxxxx
  licenseFile: online
```

{% endcode %}

**After**

{% code lineNumbers="true" %}

```yaml
global:
  licenseKey: 'xxxxxxxxxx'
  licenseFile: ''
```

{% endcode %}

</details>

### A2. Image Version

#### Why the Change?

The value controls the container image tag used, not necessarily a version. It is now aligned with the Kubernetes convention.

#### What You Need to Do

<details>

<summary><strong>Renaming the Image Key</strong></summary>

* Rename `global.image.version` to `global.image.tag`.

**Before**

{% code lineNumbers="true" %}

```yaml
global:
  image:
    version: 2.3.0
```

{% endcode %}

**After**

{% code lineNumbers="true" %}

```yaml
global:
  image:
    tag: '2.3.0'
```

{% endcode %}

</details>

### A3. Security Contexts

#### Why the Change?

Security context values now use `Override` suffixes to signal that they replace the chart defaults rather than merge with them.

We renamed `securityContext` to `podSecurityContextOverride`, to be consistent and explicit in the naming.

{% hint style="warning" %}

## Override values replace defaults, they do not merge

A partial override strips any default it does not redeclare. If you customized a security context, your migrated output must include both the new 3.0.0 defaults and your customizations, merged by hand.
{% endhint %}

The same rename applies to per-agent security contexts in the `connectware-agent` chart. See [B3. Security Contexts](#b3.-security-contexts).

#### Key Changes

<details>

<summary><strong>1. Pod and Container Security Context Renames</strong></summary>

Both keys are available as a global default under `global.*` and as a per-component override. The per-component value takes precedence over the global one.

* `securityContext` → `podSecurityContextOverride`
* `containerSecurityContext` → `containerSecurityContextOverride`

This applies to `global.*` and every component.

</details>

<details>

<summary><strong>2. Chart 3.0.0 Defaults to Merge Into Your Override</strong></summary>

For your reference, these are the default security contexts our Helm charts apply. If you have customized a security context, merge your customization with these defaults and set them in the respective `podSecurityContextOverride` or `containerSecurityContextOverride`. You will find examples in the next steps. If you never customized a security context, delete any security context block from your `values.yaml` file and the defaults will apply.

**Default pod security context**

{% code lineNumbers="true" %}

```yaml
runAsNonRoot: true
seccompProfile:
  type: RuntimeDefault
fsGroup: 1000
```

{% endcode %}

**Default container security context**

{% code lineNumbers="true" %}

```yaml
allowPrivilegeEscalation: false
capabilities:
  drop:
    - ALL
```

{% endcode %}

</details>

<details>

<summary><strong>3. Merge Example (Pod Security Context)</strong></summary>

This example adds `runAsUser: 1000` on top of the defaults.

**Before**

{% code lineNumbers="true" %}

```yaml
global:
  securityContext:
    runAsUser: 1000
```

{% endcode %}

**After (defaults merged with your value)**

{% code lineNumbers="true" %}

```yaml
global:
  podSecurityContextOverride:
    runAsNonRoot: true
    seccompProfile:
      type: RuntimeDefault
    fsGroup: 1000
    runAsUser: 1000
```

{% endcode %}

</details>

<details>

<summary><strong>4. Merge Example (Container Security Context)</strong></summary>

This example sets the container to run as a specific user ID (`runAsUser: 1000`) on top of the defaults.

**Before**

{% code lineNumbers="true" %}

```yaml
broker:
  containerSecurityContext:
    runAsUser: 1000
```

{% endcode %}

**After (defaults merged with your value)**

{% code lineNumbers="true" %}

```yaml
broker:
  containerSecurityContextOverride:
    allowPrivilegeEscalation: false
    capabilities:
      drop:
        - ALL
    runAsUser: 1000
```

{% endcode %}

</details>

<details>

<summary><strong>5. Dropping Exact-Default Blocks</strong></summary>

The former defaults and the 3.0.0 defaults listed above are identical. If your source security context block matches them exactly, drop the block entirely instead of emitting an override. The 3.0.0 defaults already cover it.

</details>

### A4. Storage to Persistence

#### Why the Change?

The `storage` key was renamed to `persistence` across the chart, and several storage-related keys were adjusted to use uppercase initialisms. This aligns the naming with common Kubernetes conventions and keeps it consistent across the chart.

The same rename applies to per-agent storage in the `connectware-agent` chart. See [B4. Storage to Persistence](#b4.-storage-to-persistence).

#### What You Need to Do

<details>

<summary><strong>Renaming Storage Keys</strong></summary>

| Old                                                                              | New                                        |
| -------------------------------------------------------------------------------- | ------------------------------------------ |
| `global.storage`                                                                 | `global.persistence`                       |
| `<component>.storage` (broker, nats, postgresql, systemControlServer, workbench) | `<component>.persistence`                  |
| `postgresql.persistence.preprovisionedNfs`                                       | `postgresql.persistence.preprovisionedNFS` |

Inner keys (`size`, `storageClassName`, `data`, `log`, `accessMode`) are unchanged.

**Before**

{% code lineNumbers="true" %}

```yaml
global:
  storage:
    storageClassName: 'standard'
    certs:
      storageClassName: 'standard'
  postgresql:
    storage:
      size: 50Gi
      storageClassName: 'ssd'
      preprovisionedNfs:
        enabled: false
        server: ''
        path: /nfs_data/postgresql
```

{% endcode %}

**After**

{% code lineNumbers="true" %}

```yaml
global:
  persistence:
    storageClassName: 'standard'
    certs:
      storageClassName: 'standard'
postgresql:
  persistence:
    size: 50Gi
    storageClassName: 'ssd'
    preprovisionedNFS:
      enabled: false
      server: ''
      path: /nfs_data/postgresql
```

{% endcode %}

</details>

### A5. User Management to Authentication

#### Why the Change?

The user management section is not different from the authentication section, so to simplify, they have been merged. The admin user password format was also simplified from base64 to plain text, which follows a common theme: literal Helm values take plain-text values. Base64 encoding is not a security measure to keep values secret. For more secure operations, use Helm values which take references to existing Kubernetes Secrets, in this case `global.authentication.adminUser.existingSecret`. The initial admin password has no effect during an upgrade, since it will never override an existing admin user.

The `mTLS` configuration block was removed a few versions back, since mTLS is now always enabled. If you still have it in your `values.yaml`, now is a good chance to remove it.

#### What You Need to Do

<details>

<summary><strong>Migrating Authentication Values</strong></summary>

* Rename `global.userManagement.adminUser` to `global.authentication.adminUser`.
* Change `adminUser.enabled` from the string `"true"` or `"false"` to the boolean `true` or `false`.
* Change `adminUser.initialPassword` from base64 or the sentinel `"automatic"` to plain text. Decode any base64 value. Replace `"automatic"` with an empty string `""` to auto-generate a password.
* Rename `global.userManagement.passwordPolicyRules` to `global.authentication.passwordPolicyRules`.
* Delete `global.authentication.mTLS` if present. mTLS has been auto-enabled for several Connectware versions and the value no longer has any effect.

**Before**

{% code lineNumbers="true" %}

```yaml
global:
  userManagement:
    adminUser:
      enabled: 'true'
      initialPassword: Y2hhbmdlbWU=
    passwordPolicyRules: 'default'
  authentication:
    mTLS:
      enabled: false
```

{% endcode %}

**After**

{% code lineNumbers="true" %}

```yaml
global:
  authentication:
    adminUser:
      enabled: true
      initialPassword: 'changeme'
    passwordPolicyRules: 'default'
```

{% endcode %}

</details>

### A6. Other Global Value Changes

#### Why the Change?

Some global values are no longer needed, the MetalLB address pool configuration moved to the ingress service annotations, and the ingress DNS names key was renamed to use the uppercase initialism.

#### What You Need to Do

<details>

<summary><strong>Removing, Replacing, and Renaming Global Values</strong></summary>

* Delete `global.setImmutableLabels`. Labels on immutable objects are now always set.
* If you use MetalLB, replace `global.loadBalancer.metalLB.addressPoolName` with an annotation on `connectwareIngress.service.annotations` as explained in the [MetalLB documentation](https://metallb.io/usage/#requesting-specific-ips). You can then remove the `global.loadBalancer` section.
* Rename `global.ingressDnsNames` to `global.ingressDNSNames` (uppercase DNS).

**Before**

{% code lineNumbers="true" %}

```yaml
global:
  setImmutableLabels: true
  loadBalancer:
    metalLB:
      addressPoolName: my-pool
  ingressDnsNames:
    - connectware.example.com
```

{% endcode %}

**After**

{% code lineNumbers="true" %}

```yaml
global:
  ingressDNSNames:
    - connectware.example.com
connectwareIngress:
  service:
    annotations:
      metallb.universe.tf/address-pool: my-pool
```

{% endcode %}

</details>

### A7. Components Moved Out of global

#### Why the Change?

Component configuration blocks were lifted out of `global.*` to their own top-level keys to follow Helm best practices and avoid confusion with subcharts being introduced into the `connectware` chart.

The "connectware" Deployment used the `global.ingress` section. The name of the Deployment and the name of the section were confusing, so they were both renamed. The Deployment is now named "connectware-ingress" and uses the matching Helm value section `connectwareIngress`. This conveys more clearly that this is an ingress proxy for Connectware, and has nothing to do with a Kubernetes Ingress. Instead it is exposed using a `LoadBalancer` Service by default.

#### What You Need to Do

<details>

<summary><strong>Moving Component Blocks to the Top Level</strong></summary>

Move every `global.<component>` block to the top-level `<component>` key. Use the mapping below.

| Old                             | New                      |
| ------------------------------- | ------------------------ |
| `global.adminWebApp`            | `adminWebApp`            |
| `global.authServer`             | `authServer`             |
| `global.broker`                 | `broker`                 |
| `global.containerManager`       | `containerManager`       |
| `global.ingress`                | `connectwareIngress`     |
| `global.ingressController`      | `ingressController`      |
| `global.nats`                   | `nats`                   |
| `global.postgresql`             | `postgresql`             |
| `global.protocolMapper`         | `protocolMapper`         |
| `global.resourceStatusTracking` | `resourceStatusTracking` |
| `global.serviceManager`         | `serviceManager`         |
| `global.systemControlServer`    | `systemControlServer`    |
| `global.topicExplorer`          | `topicExplorer`          |
| `global.workbench`              | `workbench`              |

**Before**

{% code lineNumbers="true" %}

```yaml
global:
  ingress:
    service:
      annotations:
        service.beta.kubernetes.io/load-balancer-scheme: 'internet-facing'
  broker:
    replicaCount: 3
  postgresql:
    storage:
      storageClassName: block-storage
  nats:
    replicas: 3
```

{% endcode %}

**After**

{% code lineNumbers="true" %}

```yaml
connectwareIngress:
  service:
    annotations:
      service.beta.kubernetes.io/load-balancer-scheme: 'internet-facing'
broker:
  replicas: 3
postgresql:
  persistence:
    storageClassName: block-storage
nats:
  replicas: 3
```

{% endcode %}

</details>

### A8. Resources Moved to Per-Component

#### Why the Change?

The `global.podResources.*` block has been removed. Resource limits and requests are now configured directly on each component. Default requests have also been reduced for most components.

{% hint style="warning" %}
If your current `values.yaml` file does not set `global.podResources`, your workloads will receive the new, lower default requests after the upgrade. Set the old values explicitly if your workload requires them.
{% endhint %}

#### What You Need to Do

<details>

<summary><strong>1. Moving Resources to Each Component</strong></summary>

Drop `global.podResources.*` and put `resources:` directly on each component. Watch the alias keys: `connectware`, `controlServer`, `database`, and `distributedProtocolMapper` do not match their target component names.

| Old Path                                        | New Path                                                                                                                                          |
| ----------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
| `global.podResources.<component>`               | `<component>.resources`                                                                                                                           |
| `global.podResources.connectware`               | `connectwareIngress.resources`                                                                                                                    |
| `global.podResources.controlServer`             | `systemControlServer.resources`                                                                                                                   |
| `global.podResources.database`                  | `postgresql.resources`                                                                                                                            |
| `global.podResources.distributedProtocolMapper` | `connectwareAgent.protocolMapperAgentDefaults.resources`. See also [B1. Protocol-Mapper Agents Structure](#b1.-protocol-mapper-agents-structure). |

**Before**

{% code lineNumbers="true" %}

```yaml
global:
  podResources:
    broker:
      limits:
        cpu: 2000m
        memory: 3000Mi
      requests:
        cpu: 2000m
        memory: 3000Mi
    connectware:
      limits:
        cpu: 1500m
        memory: 750Mi
      requests:
        cpu: 1000m
        memory: 500Mi
    database:
      limits:
        cpu: 2000m
        memory: 2000Mi
      requests:
        cpu: 2000m
        memory: 2000Mi
    distributedProtocolMapper:
      requests:
        cpu: 2000m
        memory: 2000Mi
```

{% endcode %}

**After**

{% code lineNumbers="true" %}

```yaml
broker:
  resources:
    limits:
      cpu: 2000m
      memory: 3000Mi
    requests:
      cpu: 2000m
      memory: 3000Mi
connectwareIngress:
  resources:
    limits:
      cpu: 1500m
      memory: 750Mi
    requests:
      cpu: 1000m
      memory: 500Mi
postgresql:
  resources:
    limits:
      cpu: 2000m
      memory: 2000Mi
    requests:
      cpu: 2000m
      memory: 2000Mi
connectwareAgent:
  protocolMapperAgentDefaults:
    resources:
      requests:
        cpu: 2000m
        memory: 2000Mi
```

{% endcode %}

</details>

<details>

<summary><strong>2. Default Request Changes</strong></summary>

The table below lists the default CPU and memory requests for each component in chart 2.4.0 and chart 3.0.0.

Most components have lower defaults in chart 3.0.0. However, lower defaults do not mean Connectware requires fewer resources. The chart reduces defaults to make it easier to get started on smaller clusters. Use actual resource consumption data to set values that match your workload before going to production.

Chart 3.0.0 also removes default limits. Running without limits is not recommended, since it allows workloads to starve others on the same cluster. See the [Kubernetes documentation on resource requests and limits](https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/) for guidance on setting appropriate values. If you are unsure where to start, see [Right-Sizing Kubernetes Resources for Connectware](/2-4-1/guides/right-sizing-kubernetes-resources.md).

| Component                | Old (cpu/mem)  | New (cpu/mem)  |
| ------------------------ | -------------- | -------------- |
| `adminWebApp`            | 100m / 50Mi    | 50m / 50Mi     |
| `authServer`             | 1500m / 1000Mi | 1000m / 500Mi  |
| `broker`                 | 2000m / 3000Mi | 600m / 1000Mi  |
| `connectwareIngress`     | 1000m / 500Mi  | 400m / 250Mi   |
| `containerManager`       | 250m / 200Mi   | 150m / 200Mi   |
| `ingressController`      | 100m / 100Mi   | 150m / 100Mi   |
| `nats`                   | 2000m / 2000Mi | 500m / 750Mi   |
| `postgresql`             | 2000m / 2000Mi | 500m / 750Mi   |
| `protocolMapper`         | 2000m / 2000Mi | 1000m / 1000Mi |
| `resourceStatusTracking` | 1000m / 1000Mi | 250m / 500Mi   |
| `serviceManager`         | 1000m / 1000Mi | 1000m / 500Mi  |
| `systemControlServer`    | 200m / 200Mi   | 300m / 200Mi   |
| `topicExplorer`          | 200m / 750Mi   | 200m / 500Mi   |
| `workbench`              | 200m / 400Mi   | 150m / 200Mi   |

</details>

### A9. CybusMQ Broker Value Changes

#### Why the Change?

Beyond the storage rename covered in [A4](#a4.-storage-to-persistence) and the top-level move covered in [A7](#a7.-components-moved-out-of-global), several CybusMQ broker keys were renamed or retyped.

#### What You Need to Do

<details>

<summary><strong>Updating CybusMQ Broker Values</strong></summary>

* Rename `replicaCount` to `replicas`.
* Rename `messageQueueSize` to `onlineMessageQueueSize`.
* Convert `allowRegisterDuringClusterFormation`, `allowPublishDuringClusterFormation`, `allowSubscribeDuringClusterFormation`, and `allowUnsubscribeDuringClusterFormation` from the strings `"on"` or `"off"` to the booleans `true` or `false`.
* Replace the `clusterSecret` placeholder `<defineAnySecret>` with a real value or an empty string `""` to auto-generate. This upgrade requires completely stopping your cluster, which means it is possible to change the secret, as well as the approach to configuring it.

**Before**

{% code lineNumbers="true" %}

```yaml
global:
  broker:
    replicaCount: 3
    clusterSecret: <defineAnySecret>
    messageQueueSize: 10000
    allowRegisterDuringClusterFormation: 'on'
    allowPublishDuringClusterFormation: 'on'
    allowSubscribeDuringClusterFormation: 'on'
    allowUnsubscribeDuringClusterFormation: 'off'
    storage:
      size: 40Gi
      storageClassName: 'ssd'
```

{% endcode %}

**After**

{% code lineNumbers="true" %}

```yaml
broker:
  replicas: 3
  clusterSecret: ''
  onlineMessageQueueSize: 10000
  allowRegisterDuringClusterFormation: true
  allowPublishDuringClusterFormation: true
  allowSubscribeDuringClusterFormation: true
  allowUnsubscribeDuringClusterFormation: false
  persistence:
    size: 40Gi
    storageClassName: 'ssd'
```

{% endcode %}

</details>

### A10. Auth-Server Default Replicas

#### Why the Change?

The default for `authServer.replicas` changed from `1` to `2` to improve availability.

#### What You Need to Do

<details>

<summary><strong>Setting the Old Replica Count</strong></summary>

If your `values.yaml` file does not set `authServer.replicas`, the new default applies after the upgrade. To keep the old behavior, set the replica count explicitly:

{% code lineNumbers="true" %}

```yaml
authServer:
  replicas: 1
```

{% endcode %}

</details>

### A11. Reserved MFA Environment Variables

#### Why the Change?

Chart 3.0.0 introduces dedicated Helm values for the MFA issuer and label: `global.authentication.mfa.issuer` and `global.authentication.mfa.label`. Because the chart now sets these on the auth-server itself, the matching environment variables `CYBUS_MFA_ISSUER` and `CYBUS_MFA_LABEL` are reserved and stripped from any `authServer.env` list. Setting them via `env` no longer has any effect.

#### What You Need to Do

<details>

<summary><strong>Migrating MFA Environment Variables to Helm Values</strong></summary>

If you previously set `CYBUS_MFA_ISSUER` or `CYBUS_MFA_LABEL` through `authServer.env`, remove them from the `env` list and set the equivalent Helm values instead.

| Environment Variable | Helm Value                         |
| -------------------- | ---------------------------------- |
| `CYBUS_MFA_ISSUER`   | `global.authentication.mfa.issuer` |
| `CYBUS_MFA_LABEL`    | `global.authentication.mfa.label`  |

**Before**

{% code lineNumbers="true" %}

```yaml
authServer:
  env:
    - name: CYBUS_MFA_ISSUER
      value: 'Acme Corp'
    - name: CYBUS_MFA_LABEL
      value: 'Connectware'
    - name: SOME_OTHER_ENV
      value: '5'
```

{% endcode %}

**After**

{% code lineNumbers="true" %}

```yaml
global:
  authentication:
    mfa:
      issuer: 'Acme Corp'
      label: 'Connectware'
authServer:
  env:
    - name: SOME_OTHER_ENV
      value: '5'
```

{% endcode %}

</details>

### A12. Workload Label Rename

#### Why the Change?

Workloads created by the `connectware` chart no longer carry the short `app=<component>` label. The chart now uses the standard Kubernetes recommended label `app.kubernetes.io/name=<component>` instead. This aligns the chart with [Kubernetes recommended labels](https://kubernetes.io/docs/concepts/overview/working-with-objects/common-labels/) and matches what the `connectware-agent` chart already uses.

#### What You Need to Do

<details>

<summary><strong>Updating External Workload Selectors</strong></summary>

No changes to your `values.yaml` file are required. The upgrade works without action.

If you have external tooling that selects Connectware workloads through the old label, update the selector. Common examples:

* `kubectl` commands using `-l app=<component>`.
* Scripts, CI pipelines, or operators that filter pods, services, or other resources by `app=<component>`.
* `NetworkPolicy`, `PodMonitor`, `ServiceMonitor`, or other resources whose `selector` or `podSelector` matches `app=<component>`.
* Monitoring or logging configurations that group workloads by the `app` label.

Replace the selector with `app.kubernetes.io/name=<component>`. For example:

**Before**

{% code lineNumbers="true" %}

```bash
kubectl get pods -n ${NAMESPACE} -l app=broker
```

{% endcode %}

**After**

{% code lineNumbers="true" %}

```bash
kubectl get pods -n ${NAMESPACE} -l app.kubernetes.io/name=broker
```

{% endcode %}

</details>

### A13. Ingress Service Ports for TCP IngressRoutes

#### Why the Change?

The `connectware` LoadBalancer Service is now fully configurable through `connectwareIngress.service.ports`. The new default port list only contains the core Connectware ports. The ports `40000` to `40009`, which were previously exposed for [`Cybus::IngressRoute`](/2-4-1/documentation/services/service-commissioning-files/resources/cybus-ingressroute.md) TCP resources, are no longer exposed unless you add them.

#### What You Need to Do

<details>

<summary><strong>Adding TCP Ports for IngressRoutes</strong></summary>

If you do not use `Cybus::IngressRoute` resources of type `tcp`, no action is required.

If you do, add an entry to `connectwareIngress.service.ports` for every `connectwarePort` your TCP IngressRoutes use. Ports between `40000` and `40100` are valid.

{% code lineNumbers="true" %}

```yaml
connectwareIngress:
  service:
    ports:
      - name: 'generic-tcp-40001'
        port: 40001
        targetPort: 40001
      - name: 'generic-tcp-40002'
        port: 40002
        targetPort: 40002
```

{% endcode %}

{% hint style="warning" %}
The list under `connectwareIngress.service.ports` fully replaces the default Service ports. When adding entries, keep the default Connectware ports from the chart's `values.yaml` and append your TCP ports, otherwise the Admin UI, MQTT, and other core entry points become unreachable.
{% endhint %}

</details>

### A14. NATS Metrics Path Change

#### Why the Change?

The intermediate `prometheus` block under NATS metrics is gone. The exporter sidecar configuration (`enabled`, `resources`) and the `ServiceMonitor` configuration now live directly under `nats.metrics`.

#### What You Need to Do

<details>

<summary><strong>Moving NATS Metrics Keys</strong></summary>

If you configured NATS metrics, move every key from `global.nats.metrics.prometheus.*` up one level to `nats.metrics.*`. The `global.nats` → `nats` move from [A7. Components Moved Out of global](#a7.-components-moved-out-of-global) applies here as well.

| Old                                               | New                             |
| ------------------------------------------------- | ------------------------------- |
| `global.nats.metrics.prometheus.enabled`          | `nats.metrics.enabled`          |
| `global.nats.metrics.prometheus.resources`        | `nats.metrics.resources`        |
| `global.nats.metrics.prometheus.serviceMonitor.*` | `nats.metrics.serviceMonitor.*` |

**Before**

{% code lineNumbers="true" %}

```yaml
global:
  nats:
    metrics:
      prometheus:
        enabled: true
        resources:
          requests:
            cpu: 100m
            memory: 300Mi
        serviceMonitor:
          enabled: true
          labels:
            release: prometheus
```

{% endcode %}

**After**

{% code lineNumbers="true" %}

```yaml
nats:
  metrics:
    enabled: true
    resources:
      requests:
        cpu: 100m
        memory: 300Mi
    serviceMonitor:
      enabled: true
      labels:
        release: prometheus
```

{% endcode %}

</details>

## Part B: Connectware-Agent Chart Migration

Chart 3.0.0 removes built-in agent orchestration from the `connectware` chart and replaces it with the `connectware-agent` chart, embedded as a subchart. The following steps cover both migrating agents from the old `connectware` chart and updating existing subchart installations.

{% hint style="warning" %}
After the upgrade, you must re-register any agents that were scheduled with the `connectware` chart. See [Post-Upgrade Actions](#post-upgrade-actions).
{% endhint %}

Apply the following changes to your `connectware-agent` or `connectware` chart values. Not all sections apply to both deployment modes. Check the table below before working through them. Sections with mode-specific examples use **Standalone** and **Subchart** tabs:

| Section                                                                       | Standalone   | Subchart     |
| ----------------------------------------------------------------------------- | ------------ | ------------ |
| [B1. Protocol-Mapper Agents Structure](#b1.-protocol-mapper-agents-structure) | No changes   | **Required** |
| [B2. Image Version](#b2.-image-version)                                       | **Required** | No changes   |
| [B3. Security Contexts](#b3.-security-contexts)                               | **Required** | **Required** |
| [B4. Storage to Persistence](#b4.-storage-to-persistence)                     | No changes   | **Required** |
| [B5. TLS CA Configuration Renames](#b5.-tls-ca-configuration-renames)         | **Required** | **Required** |
| [B6. Reserved Environment Variables](#b6.-reserved-environment-variables)     | **Required** | **Required** |
| [B7. Resource Defaults](#b7.-resource-defaults)                               | **Required** | **Required** |
| [B8. Cluster Resource Name Changes](#b8.-cluster-resource-name-changes)       | **Required** | **Required** |

* **Standalone**: `connectware-agent` installed as its own Helm release, keys are at the root of its `values.yaml`. See [Installing Connectware Agents Using the Connectware-Agent Helm Chart](/2-4-1/documentation/agents/agents-in-kubernetes/installing-connectware-agents-using-the-connectware-agent-helm-chart.md).
* **Subchart**: `connectware-agent` embedded in the `connectware` chart, keys are nested under `connectwareAgent.*`. See [Deploying Agents with Your Connectware Installation](/2-4-1/documentation/agents/agents-in-kubernetes/deploying-agents-with-your-connectware-installation.md).

### B1. Protocol-Mapper Agents Structure

#### Why the Change?

Chart 3.0.0 replaces the built-in agent templates under `global.protocolMapperAgents` with the `connectware-agent` subchart. Subchart users now configure agents through `connectwareAgent.*` instead of `global.*`, and gain access to the `protocolMapperAgentDefaults` mechanism that standalone `connectware-agent` Helm chart already uses.

Standalone `connectware-agent` users are not affected by this restructuring. The per-key renames in [B2](#b2.-image-version) through [B6](#b6.-reserved-environment-variables) still apply, but the overall `protocolMapperAgents` / `protocolMapperAgentDefaults` layout is unchanged.

#### What You Need to Do

This section applies to subchart users only. Move `global.protocolMapperAgents` to `connectwareAgent.protocolMapperAgents`. The `connectwareAgent.protocolMapperAgentDefaults` block is now available for values shared across agents.

{% hint style="warning" %}
Connectware treats migrated agents as new entities after the upgrade. After the Helm upgrade completes, you must de-register the old agents and register the new ones. See [Post-Upgrade Actions](#post-upgrade-actions).
{% endhint %}

#### Promoting Shared Values to protocolMapperAgentDefaults

Optional but recommended when you have multiple agents. Override precedence is: schema defaults, then `protocolMapperAgentDefaults`, then per-agent entry. Each agent entry then only needs its `name` plus its overrides. For full semantics, see [Configuration Principles for the connectware-agent Helm Chart](/2-4-1/cybus-helm-charts/connectware-agent-helm-chart.md#configuration-principles-for-the-connectware-agent-helm-chart).

A subset of keys also inherits from the parent `connectware` chart's `global.*` values when not set on the agent or its defaults. This applies to security contexts, image values other than `image.name`, `podPriorityClassName`, `nodeSelector`, and `tolerations`. The effective precedence in that case is: schema defaults, then inherited `global.*` values from the `connectware` chart, then `protocolMapperAgentDefaults`, then per-agent entry.

To promote shared values:

1. Identify values that are identical across every agent, such as `env`, `connectwareHost`, `tls.ca`, `mTLS.enabled`, `persistence.storageClassName`, and `resources`.
2. Move those values into `protocolMapperAgentDefaults`.
3. Leave only the per-agent overrides plus `name` in each `protocolMapperAgents` entry.

Some keys are always agent-specific and have no default counterpart: `name`, `mTLS.keyPair`, and `existingAgentPasswordSecret`. Keep them on the agent entry.

#### Simple Example (Two Agents, Shared env)

**Before**

{% code lineNumbers="true" %}

```yaml
global:
  protocolMapperAgents:
    - name: bender-robots
      storageSize: 50Mi
      env:
        - name: CYBUS_TRUST_ALL_CERTS
          value: 'true'
    - name: welder-robots
      env:
        - name: CYBUS_TRUST_ALL_CERTS
          value: 'true'
```

{% endcode %}

**After (shared env promoted)**

{% code lineNumbers="true" %}

```yaml
connectwareAgent:
  protocolMapperAgentDefaults:
    env:
      - name: CYBUS_TRUST_ALL_CERTS
        value: 'true'
  protocolMapperAgents:
    - name: bender-robots
      persistence:
        size: 50Mi
    - name: welder-robots
```

{% endcode %}

#### Advanced Example (Shared CA, Security Context, and Storage Class)

Agents share `env`, `tls.ca.cert`, `storageClassName`, and `containerSecurityContext`, but differ in `storageSize`.

**Before**

{% code lineNumbers="true" expandable="true" %}

```yaml
global:
  protocolMapperAgents:
    - name: welder-robots
      storageSize: 40Mi
      storageClassName: nfs-client
      env:
        - name: CYBUS_TRUST_ALL_CERTS
          value: 'true'
      tls:
        ca:
          cert: |
            -----BEGIN CERTIFICATE-----
            MIIFpT...
            -----END CERTIFICATE-----
      containerSecurityContext:
        allowPrivilegeEscalation: false
        capabilities:
          drop:
            - ALL
    - name: bender-robots
      storageSize: 50Mi
      storageClassName: nfs-client
      env:
        - name: CYBUS_TRUST_ALL_CERTS
          value: 'true'
      tls:
        ca:
          cert: |
            -----BEGIN CERTIFICATE-----
            MIIFpT...
            -----END CERTIFICATE-----
      containerSecurityContext:
        allowPrivilegeEscalation: false
        capabilities:
          drop:
            - ALL
```

{% endcode %}

**After**

{% code lineNumbers="true" expandable="true" %}

```yaml
connectwareAgent:
  protocolMapperAgentDefaults:
    persistence:
      storageClassName: nfs-client
    env:
      - name: CYBUS_TRUST_ALL_CERTS
        value: 'true'
    tls:
      ca:
        certChain: |
          -----BEGIN CERTIFICATE-----
          MIIFpT...
          -----END CERTIFICATE-----
  protocolMapperAgents:
    - name: welder-robots
      persistence:
        size: 40Mi
    - name: bender-robots
      persistence:
        size: 50Mi
```

{% endcode %}

In this example, `containerSecurityContext` matches the 3.0.0 default, so the block was dropped entirely. If your block had only partially overridden the default, you would merge it by hand as described in [B3. Security Contexts](#b3.-security-contexts).

### B2. Image Version

#### Why the Change?

The value controls the container image tag used, not necessarily a version. It is now aligned with the Kubernetes convention, matching the rename in [A2. Image Version](#a2.-image-version).

#### What You Need to Do

This section applies to **standalone** `connectware-agent` users only. Subchart users were previously unable to control image settings for agents. They can now use the values provided by the `connectware-agent` subchart, or let the chart fall back on the global `connectware` chart image tag in `global.image.tag` , which is already covered by [A2. Image Version](#a2.-image-version).

<details>

<summary><strong>Renaming the Image Key</strong></summary>

* Rename `image.version` to `image.tag`.

**Before**

{% code lineNumbers="true" %}

```yaml
protocolMapperAgents:
  - name: welder-robots
    image:
      version: 2.3.1
```

{% endcode %}

**After**

{% code lineNumbers="true" %}

```yaml
protocolMapperAgents:
  - name: welder-robots
    image:
      tag: 2.3.1
```

{% endcode %}

</details>

### B3. Security Contexts

#### Why the Change?

Per-agent security context keys were renamed to use `Override` suffixes, matching the convention introduced in [A3. Security Contexts](#a3.-security-contexts).

{% hint style="warning" %}

## Override values replace defaults, they do not merge

A partial override strips any default it does not redeclare. If you customized a per-agent security context, your migrated output must include both the new 3.0.0 defaults (listed in [A3](#a3.-security-contexts)) and your customizations, merged by hand.
{% endhint %}

#### What You Need to Do

Per agent, in each entry under `protocolMapperAgents`:

* `securityContext` → `podSecurityContextOverride`
* `containerSecurityContext` → `containerSecurityContextOverride`

You can also use the `protocolMapperAgentDefaults.podSecurityContextOverride` and `protocolMapperAgentDefaults.containerSecurityContextOverride` block to set security context for all agents.

If your source security context block exactly matches the 3.0.0 defaults from [A3](#a3.-security-contexts), drop the block instead of emitting an override.

{% tabs %}
{% tab title="Standalone" %}
**Before**

{% code lineNumbers="true" %}

```yaml
protocolMapperAgents:
  - name: welder-robots
    containerSecurityContext:
      allowPrivilegeEscalation: false
      capabilities:
        drop:
          - ALL
      runAsUser: 1000
```

{% endcode %}

**After**

{% code lineNumbers="true" %}

```yaml
protocolMapperAgents:
  - name: welder-robots
    containerSecurityContextOverride:
      allowPrivilegeEscalation: false
      capabilities:
        drop:
          - ALL
      runAsUser: 1000
```

{% endcode %}
{% endtab %}

{% tab title="Subchart" %}
**Before**

{% code lineNumbers="true" %}

```yaml
global:
  protocolMapperAgents:
    - name: welder-robots
      containerSecurityContext:
        allowPrivilegeEscalation: false
        capabilities:
          drop:
            - ALL
        runAsUser: 1000
```

{% endcode %}

**After**

{% code lineNumbers="true" %}

```yaml
connectwareAgent:
  protocolMapperAgents:
    - name: welder-robots
      containerSecurityContextOverride:
        allowPrivilegeEscalation: false
        capabilities:
          drop:
            - ALL
        runAsUser: 1000
```

{% endcode %}
{% endtab %}
{% endtabs %}

### B4. Storage to Persistence

#### Why the Change?

Per-agent storage keys of the `connectware` chart were folded into a `persistence` block by migrating to the `connectware-agent` chart as a subchart, matching the rename in [A4. Storage to Persistence](#a4.-storage-to-persistence). You can also use the `connectwareAgent.protocolMapperAgentDefaults.persistence` block to set persistence for all agents.

#### What You Need to Do

Per agent, in each entry under `protocolMapperAgents`:

| Old                | New                            |
| ------------------ | ------------------------------ |
| `storageSize`      | `persistence.size`             |
| `storageClassName` | `persistence.storageClassName` |

{% tabs %}
{% tab title="Standalone" %}
No changes are required when upgrading a standalone `connectware-agent` installation.
{% endtab %}

{% tab title="Subchart" %}
**Before**

{% code lineNumbers="true" %}

```yaml
global:
  protocolMapperAgents:
    - name: welder-robots
      storageSize: 50Mi
      storageClassName: nfs-client
```

{% endcode %}

**After**

{% code lineNumbers="true" %}

```yaml
connectwareAgent:
  protocolMapperAgents:
    - name: welder-robots
      persistence:
        size: 50Mi
        storageClassName: nfs-client
```

{% endcode %}
{% endtab %}
{% endtabs %}

### B5. TLS CA Configuration Renames

#### Why the Change?

The key holding the CA certificate body was renamed to reflect that it accepts a full certificate chain. The legacy `mTLS.caChain.*` path is also gone — previously it was kept for backwards compatibility and is now removed. Move all CA configuration under `tls.ca.*`.

#### What You Need to Do

Per agent, in each entry under `protocolMapperAgents`, and in `protocolMapperAgentDefaults` if you use it:

| Old                              | New                        |
| -------------------------------- | -------------------------- |
| `tls.ca.cert`                    | `tls.ca.certChain`         |
| `mTLS.caChain.cert`              | `tls.ca.certChain`         |
| `mTLS.caChain.existingConfigMap` | `tls.ca.existingConfigMap` |

{% tabs %}
{% tab title="Standalone" %}
**Before**

{% code lineNumbers="true" %}

```yaml
protocolMapperAgents:
  - name: welder-robots
    mTLS:
      caChain:
        cert: |
          -----BEGIN CERTIFICATE-----
          MIIFpT...
          -----END CERTIFICATE-----
```

{% endcode %}

**After**

{% code lineNumbers="true" %}

```yaml
protocolMapperAgents:
  - name: welder-robots
    tls:
      ca:
        certChain: |
          -----BEGIN CERTIFICATE-----
          MIIFpT...
          -----END CERTIFICATE-----
```

{% endcode %}
{% endtab %}

{% tab title="Subchart" %}
**Before**

{% code lineNumbers="true" %}

```yaml
global:
  protocolMapperAgents:
    - name: welder-robots
      mTLS:
        caChain:
          cert: |
            -----BEGIN CERTIFICATE-----
            MIIFpT...
            -----END CERTIFICATE-----
```

{% endcode %}

**After**

{% code lineNumbers="true" %}

```yaml
connectwareAgent:
  protocolMapperAgents:
    - name: welder-robots
      tls:
        ca:
          certChain: |
            -----BEGIN CERTIFICATE-----
            MIIFpT...
            -----END CERTIFICATE-----
```

{% endcode %}
{% endtab %}
{% endtabs %}

### B6. Reserved Environment Variables

#### Why the Change?

Chart 3.0.0 strips a fixed set of environment variables from any user-supplied `env` list before they reach the agent pod. These names are reserved for the chart to set internally, so that agent identity, connectivity, and security cannot be silently misconfigured. Previously, user overrides could be applied or ignored; now they are always filtered. Use the Helm values we provide if you previously set one of these environment variables.

#### What You Need to Do

Remove the following names from every `env` list, including each entry under `protocolMapperAgents` and `protocolMapperAgentDefaults` if you use it:

* `CYBUS_AGENT_MODE`
* `CYBUS_AGENT_NAME`
* `CYBUS_HOSTNAME_INGRESS`
* `CYBUS_PROTOCOL_MAPPER_PASSWORD`
* `CYBUS_USE_MUTUAL_TLS`
* Any name starting with `CYBUS_DATAPLANE_`
* Any name starting with `CYBUS_STREAMSERVER_`

Custom variables you set through `env` are unaffected. Only the names above and the two prefixes are filtered.

<details>

<summary><strong>Helm Values to Use Instead</strong></summary>

The following table shows how to control these environment variables with the `connectware-agent` Helm chart.

| Environment Variable             | Helm Value                                                                                                                                                                                       |
| -------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `CYBUS_AGENT_MODE`               | Always set to "distributed", do not set manually                                                                                                                                                 |
| `CYBUS_AGENT_NAME`               | `protocolMapperAgents[*].name`                                                                                                                                                                   |
| `CYBUS_HOSTNAME_INGRESS`         | `protocolMapperAgents[*].connectwareHost` or `protocolMapperAgentDefaults.connectwareHost`                                                                                                       |
| `CYBUS_PROTOCOL_MAPPER_PASSWORD` | Read from key `agentPassword` in the existing Kubernetes Secret configured in `protocolMapperAgents[*].existingAgentPasswordSecret` or `protocolMapperAgentDefaults.existingAgentPasswordSecret` |
| `CYBUS_USE_MUTUAL_TLS`           | `protocolMapperAgents[*].mTLS.enabled`                                                                                                                                                           |
| `CYBUS_DATAPLANE_HOST`           | `protocolMapperAgents[*].dataPlane.host`, `protocolMapperAgentDefaults.dataPlane.host`, `protocolMapperAgents[*].connectwareHost` or `protocolMapperAgentDefaults.connectwareHost`               |
| `CYBUS_DATAPLANE_PORT`           | Computed or overridden with `protocolMapperAgents[*].dataPlane.port` or `protocolMapperAgentDefaults.dataPlane.port`                                                                             |
| `CYBUS_DATAPLANE_SCHEME`         | Computed, do not set manually                                                                                                                                                                    |
| `CYBUS_DATAPLANE_USE_TLS`        | Computed or overridden with `protocolMapperAgents[*].dataPlane.tls` or `protocolMapperAgentDefaults.dataPlane.tls`                                                                               |
| `CYBUS_STREAMSERVER_HOST`        | `protocolMapperAgents[*].streamServer.host`, `protocolMapperAgentDefaults.streamServer.host`, `protocolMapperAgents[*].connectwareHost` or `protocolMapperAgentDefaults.connectwareHost`         |
| `CYBUS_STREAMSERVER_PORT`        | Computed or overridden with `protocolMapperAgents[*].streamServer.port` or `protocolMapperAgentDefaults.streamServer.port`                                                                       |
| `CYBUS_STREAMSERVER_SCHEME`      | Computed, do not set manually                                                                                                                                                                    |

</details>

{% tabs %}
{% tab title="Standalone" %}
**Before**

Reserved name `CYBUS_AGENT_MODE` listed alongside a custom variable:

{% code lineNumbers="true" %}

```yaml
protocolMapperAgents:
  - name: welder-robots
    env:
      - name: CYBUS_AGENT_MODE
        value: 'distributed'
      - name: CYBUS_TRUST_ALL_CERTS
        value: 'true'
```

{% endcode %}

**After**

Reserved name removed, custom variable kept:

{% code lineNumbers="true" %}

```yaml
protocolMapperAgents:
  - name: welder-robots
    env:
      - name: CYBUS_TRUST_ALL_CERTS
        value: 'true'
```

{% endcode %}
{% endtab %}

{% tab title="Subchart" %}
**Before**

Reserved name `CYBUS_AGENT_MODE` listed alongside a custom variable:

{% code lineNumbers="true" %}

```yaml
global:
  protocolMapperAgents:
    - name: welder-robots
      env:
        - name: CYBUS_AGENT_MODE
          value: 'distributed'
        - name: CYBUS_TRUST_ALL_CERTS
          value: 'true'
```

{% endcode %}

**After**

Reserved name removed, custom variable kept:

{% code lineNumbers="true" %}

```yaml
connectwareAgent:
  protocolMapperAgents:
    - name: welder-robots
      env:
        - name: CYBUS_TRUST_ALL_CERTS
          value: 'true'
```

{% endcode %}
{% endtab %}
{% endtabs %}

### B7. Resource Defaults

#### Why the Change?

Chart 3.0.0 halves the default CPU and memory requests and removes the default limits for protocol-mapper agents, matching the change made for `connectware` chart components in [A8. Resources Moved to Per-Component](#a8.-resources-moved-to-per-component). Additionally, for agents orchestrated using the `connectware` chart, the compute resource requests and limits need to be moved to the Helm values provided by the `connectware-agent` chart.

| Resource Field    | Old (chart 2.x) | New (chart 3.0.0) |
| ----------------- | --------------- | ----------------- |
| `requests.cpu`    | `2000m`         | `1000m`           |
| `requests.memory` | `2000Mi`        | `1000Mi`          |
| `limits.cpu`      | `2000m`         | not set           |
| `limits.memory`   | `2000Mi`        | not set           |

The same reasoning applies as in [A8. Resources Moved to Per-Component](#a8.-resources-moved-to-per-component): lower defaults do not reflect lower resource requirements, and running without limits in production is not recommended.

{% hint style="warning" %}
This affects both standalone and subchart deployments. If your `values.yaml` file does not set agent resources, your agents will receive the new, lower default requests and no default limits after the upgrade. Set the old values explicitly if your workloads require them.
{% endhint %}

#### What You Need to Do

If you set per-agent or `protocolMapperAgentDefaults` resources directly in **standalone** mode, your values carry over unchanged.

Subchart users only: if you previously set `global.podResources.distributedProtocolMapper` in the `connectware` chart, migrate it to `connectwareAgent.protocolMapperAgentDefaults.resources` as described in [A8. Resources Moved to Per-Component](#a8.-resources-moved-to-per-component).

If you relied on the chart-level defaults, decide whether to keep the previous values or adopt the new defaults. To keep the previous behavior, set the old chart 2.x defaults explicitly on each agent or on `protocolMapperAgentDefaults`.

{% tabs %}
{% tab title="Standalone" %}
**Before**

`values.yaml` contained a default of `2000m` / `2000Mi` for both requests and limits.

{% code lineNumbers="true" %}

```yaml
protocolMapperAgentDefaults:
  resources:
    requests:
      cpu: 2000m
      memory: 2000Mi
    limits:
      cpu: 2000m
      memory: 2000Mi
```

{% endcode %}

**After**

Set the previous values explicitly if you relied on these compute resource defaults:

{% code lineNumbers="true" %}

```yaml
protocolMapperAgentDefaults:
  resources:
    requests:
      cpu: 2000m
      memory: 2000Mi
    limits:
      cpu: 2000m
      memory: 2000Mi
```

{% endcode %}
{% endtab %}

{% tab title="Subchart" %}
**Before**

`values.yaml` of the `connectware` chart had compute resources in the `global.podResources.distributedProtocolMapper` block.

{% code lineNumbers="true" %}

```yaml
global:
  podResources:
    distributedProtocolMapper:
      requests:
        cpu: 2000m
        memory: 2000Mi
      limits:
        cpu: 2000m
        memory: 2000Mi
```

{% endcode %}

**After**

Move any values you set to `connectwareAgent.protocolMapperAgentDefaults.resources` and set the previous default values explicitly if you relied on these compute resources:

{% code lineNumbers="true" %}

```yaml
connectwareAgent:
  protocolMapperAgentDefaults:
    resources:
      requests:
        cpu: 2000m
        memory: 2000Mi
      limits:
        cpu: 2000m
        memory: 2000Mi
```

{% endcode %}
{% endtab %}
{% endtabs %}

### B8. Cluster Resource Name Changes

#### Why the Change?

Chart 3.0.0 replaces the helper that builds Kubernetes resource names for protocol-mapper agents. Most installations are unaffected, but a few naming patterns produce a different result on upgrade.

The patterns that produce a different name in chart 3.0.0:

* **The release name `connectware`.** The duplicated prefix `connectware-connectware-agent-<agent>` collapses to `connectware-agent-<agent>`. Affects every agent under that release. If you have used the name `connectware` for a `connectware-agent` chart installation, set the `fullNameOverride` Helm value to `connectware-connectware-agent`.
* **Long combined release-plus-agent names.** The new helper truncates the combined name at 52 characters with a fixed split between chart and agent name, instead of the old 63-character single truncation. Names that previously hit the old limit truncate differently.

{% hint style="warning" %}

## StatefulSet selectors are immutable in Kubernetes

If any of the patterns above apply to your installation, `helm upgrade` fails on the rename and the existing PersistentVolumeClaims are orphaned. Detect this before upgrading.
{% endhint %}

If none of these patterns apply to your release name or agent names, you do not need to take any action for this section. Continue to [Running the Upgrade](#running-the-upgrade).

#### Detecting Renames Before You Upgrade

Use the [helm-diff plugin](https://github.com/databus23/helm-diff) to compare the rendered output of the new chart version against the cluster state before applying the upgrade.

{% code lineNumbers="true" %}

```bash
helm plugin install https://github.com/databus23/helm-diff
helm diff upgrade -n ${NAMESPACE} ${INSTALLATION_NAME} oci://repo.cybus.io/charts/connectware-agent --version 3.0.0 -f <values.yaml>
```

{% endcode %}

Substitute the following placeholders:

* `${NAMESPACE}`: the namespace of the installation.
* `${INSTALLATION_NAME}`: the name of the Helm release.
* `<values.yaml>`: the path to the migrated `values.yaml` file.

If the diff shows a StatefulSet, Service, or PersistentVolumeClaim renaming for any agent, stop and contact support before continuing. Resolving the rename requires deleting the old resources by hand, recreating them under the new name, and migrating data from the orphaned PVCs.

## Complete Before-and-After Examples

Use these as a reference for the overall output shape.

### Connectware Chart

<details>

<summary><strong>Before (chart 2.1.0 values)</strong></summary>

{% code title="values.yaml (2.1.0)" lineNumbers="true" expandable="true" %}

```yaml
global:
  licensekey: xxxxxxxxxx
  image:
    registry: registry.cybus.io/cybus/
    pullSecrets:
      - name: my-pull-secret
    pullPolicy: Always
    version: 2.3.0

  userManagement:
    adminUser:
      initialPassword: Y2hhbmdlbWU=

  ingress:
    service:
      annotations:
        service.beta.kubernetes.io/load-balancer-scheme: 'internet-facing'

  ingressDnsNames:
    - connectware.example.com

  authServer:
    replicas: 1

  broker:
    clusterSecret: xxxxxxxxxxxxxxxxx
    replicaCount: 3

  postgresql:
    storage:
      storageClassName: block-storage

  nats:
    replicas: 3
```

{% endcode %}

</details>

<details>

<summary><strong>After (chart 3.0.0 values)</strong></summary>

{% code title="values.yaml (3.0.0)" lineNumbers="true" expandable="true" %}

```yaml
global:
  licenseKey: 'xxxxxxxxxx'
  image:
    registry: registry.cybus.io/cybus/
    pullSecrets:
      - name: my-pull-secret
    pullPolicy: Always
    tag: '2.3.0'

  authentication:
    adminUser:
      initialPassword: 'changeme'

  ingressDNSNames:
    - connectware.example.com

authServer:
  replicas: 1

connectwareIngress:
  service:
    annotations:
      service.beta.kubernetes.io/load-balancer-scheme: 'internet-facing'

broker:
  clusterSecret: 'xxxxxxxxxxxxxxxxx'
  replicas: 3

postgresql:
  persistence:
    storageClassName: block-storage

nats:
  replicas: 3
```

{% endcode %}

</details>

### Connectware-Agent Chart

{% tabs %}
{% tab title="Standalone" %}
**Before (chart 2.1.0 values)**

{% code title="values.yaml (2.1.0)" lineNumbers="true" expandable="true" %}

```yaml
protocolMapperAgents:
  - name: bender-robots
    storageSize: 50Mi
    env:
      - name: CYBUS_TRUST_ALL_CERTS
        value: 'true'
  - name: welder-robots
    env:
      - name: CYBUS_TRUST_ALL_CERTS
        value: 'true'
```

{% endcode %}

**After (chart 3.0.0 values)**

{% code title="values.yaml (3.0.0)" lineNumbers="true" expandable="true" %}

```yaml
protocolMapperAgentDefaults:
  env:
    - name: CYBUS_TRUST_ALL_CERTS
      value: 'true'
protocolMapperAgents:
  - name: bender-robots
    persistence:
      size: 50Mi
  - name: welder-robots
```

{% endcode %}
{% endtab %}

{% tab title="Subchart" %}
**Before (chart 2.1.0 values)**

{% code title="values.yaml (2.1.0)" lineNumbers="true" expandable="true" %}

```yaml
global:
  protocolMapperAgents:
    - name: bender-robots
      storageSize: 50Mi
      env:
        - name: CYBUS_TRUST_ALL_CERTS
          value: 'true'
    - name: welder-robots
      env:
        - name: CYBUS_TRUST_ALL_CERTS
          value: 'true'
```

{% endcode %}

**After (chart 3.0.0 values)**

{% code title="values.yaml (3.0.0)" lineNumbers="true" expandable="true" %}

```yaml
connectwareAgent:
  protocolMapperAgentDefaults:
    env:
      - name: CYBUS_TRUST_ALL_CERTS
        value: 'true'
  protocolMapperAgents:
    - name: bender-robots
      persistence:
        size: 50Mi
    - name: welder-robots
```

{% endcode %}
{% endtab %}
{% endtabs %}

## Running the Upgrade

After migrating your `values.yaml` file or files, run the Helm upgrade.

### Verifying Your Backups

Make sure you have backups of the following before running the upgrade:

* All Kubernetes PersistentVolumes that Connectware uses
* Your Connectware database. See [Backing Up the Connectware Database](/2-4-1/documentation/installation-and-upgrades/backing-up-the-connectware-database.md).
* Your `values.yaml` file or files
* All service commissioning files

### Running the Helm Upgrade

Follow the steps for the chart you are upgrading.

{% tabs %}
{% tab title="connectware chart" %}
Some changes in this release cannot be applied through a rolling restart, so you must fully stop Connectware before running the upgrade.

**1. Shutting Down Connectware**

Delete all workload controllers:

{% code lineNumbers="true" %}

```bash
kubectl delete -n ${NAMESPACE} sts,deploy -l app.kubernetes.io/part-of=connectware
```

{% endcode %}

**2. Running the Helm Upgrade**

{% code lineNumbers="true" %}

```bash
helm upgrade -n ${NAMESPACE} ${INSTALLATION_NAME} oci://repo.cybus.io/charts/connectware --version 3.0.0 -f <values.yaml>
```

{% endcode %}
{% endtab %}

{% tab title="connectware-agent chart" %}
This applies to standalone deployments only. If you run the agent chart as a subchart of the `connectware` chart, the `connectware` chart upgrade already covers it.

Chart 3.0.0 includes changes that cannot be applied through a rolling restart, so you must fully stop the agents before upgrading. PersistentVolumeClaims are not deleted with their StatefulSets, so agent data is preserved.

**1. Shutting Down the Agents**

Delete the agent StatefulSets:

{% code lineNumbers="true" %}

```bash
kubectl delete -n ${NAMESPACE} sts -l app.kubernetes.io/instance=${INSTALLATION_NAME}
```

{% endcode %}

**2. Running the Helm Upgrade**

{% code lineNumbers="true" %}

```bash
helm upgrade -n ${NAMESPACE} ${INSTALLATION_NAME} oci://repo.cybus.io/charts/connectware-agent --version 3.0.0 -f <values.yaml>
```

{% endcode %}
{% endtab %}
{% endtabs %}

Substitute the following placeholders:

* `${NAMESPACE}`: the namespace of the installation.
* `${INSTALLATION_NAME}`: the name of the Helm release.
* `<values.yaml>`: the path to the migrated `values.yaml` file.

### Monitoring the Upgrade

Monitor pod status while the upgrade runs.

{% code lineNumbers="true" %}

```bash
kubectl get pods -n ${NAMESPACE}
```

{% endcode %}

Each pod passes through the following stages: `Terminating`, `Pending`, `PodInitializing`, `ContainerCreating`, `Init:x/x`, and finally `Running`. The upgrade is complete when all pods report `Running` and show the same number on both sides of the slash in the `READY` column.

See [Verifying the Connectware Upgrade](/2-4-1/documentation/installation-and-upgrades/upgrading-connectware/upgrading-connectware-kubernetes.md#verifying-the-connectware-upgrade) for additional details on how to monitor the upgrade.

## Post-Upgrade Actions

Two tasks remain before your deployment is fully operational: re-registering migrated agents and reviewing resource usage.

<details>

<summary><strong>Re-Registering Protocol-Mapper Agents</strong></summary>

This applies if you moved agents from `global.protocolMapperAgents` to `connectwareAgent.protocolMapperAgents` in [B1](#b1.-protocol-mapper-agents-structure).

After the Helm upgrade, Connectware still holds the old agent identities — one user entry in [Users View](/2-4-1/documentation/user-management/users.md#users-view) and one entry in the [Agents View](/2-4-1/documentation/agents/agents-view.md) per agent. The new agent pods start up with fresh credentials and attempt to register, but the old entries block them. You must clean up the old entries first, then authorize the new registrations.

Repeat the following steps for each migrated agent:

1. In the Admin UI, [delete the user](/2-4-1/documentation/user-management/users.md#deleting-users) whose name matches the agent. This clears the old credentials so the new agent can register under the same name.
2. In the [Agents View](/2-4-1/documentation/agents/agents-view.md), select the old agent and click **Delete** to remove it from the list.
3. The agent pod registers automatically after the old entries are removed. In the Admin UI, open the [Client Registry](/2-4-1/documentation/client-registry.md) and authorize the pending registration for each agent. Check the agent name and pairing ID to confirm you are authorizing the correct agent.
4. Confirm each agent comes back online in **System** > **System Status** > **Agents**.

</details>

<details>

<summary><strong>Reviewing Resource Requests</strong></summary>

If you did not set explicit resource values in [A8](#a8.-resources-moved-to-per-component) or [B7](#b7.-resource-defaults), your workloads now run with the chart 3.0.0 defaults: reduced CPU and memory requests with no limits set. Monitor resource usage and set explicit values on affected components if you observe throttling or eviction.

</details>


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.cybus.io/2-4-1/documentation/installation-and-upgrades/upgrading-connectware/upgrading-connectware-kubernetes/upgrading-connectware-helm-charts-to-3-0-0.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
