docs/content/en/project/contributing/contributing-controllers-config.md
Meshery Operator, MeshSync and Meshery Broker are configured through a layered
document, MesheryControllersConfig, defined in
meshery/schemas as the controllers_config
construct (v1alpha1). This page is the authoritative map of that surface for
contributors: every setting, its storage, its reader, and its observable effect.
Keep it current. A setting added without a row here is a setting nobody can find, and a row without an end-to-end test is a setting nobody can trust.
Configuration resolves through a fixed precedence chain. Every field is independently layered - leaving a field unset at one layer defers to the next.
| Precedence | Layer | Stored in | Set from |
|---|---|---|---|
| 1 (highest) | Per-connection override | connection.metadata.controllers_config | Connections table -> row actions -> Configure Operator, MeshSync & Broker |
| 2 | Server-wide default | system_settings row controllers_config_defaults | Settings -> Operator, MeshSync & Broker tab |
| 3 (lowest) | Built-in default | Compiled in: connections.BuiltInControllersConfig() | Not settable |
connections.ResolveControllersConfig returns two documents:
The UI mirrors the built-in defaults in BUILT_IN_CONTROLLERS_CONFIG
(ui/components/configuration/ControllersConfigForm.tsx). The two must agree;
they are asserted against each other by unit test.
Scalars merge per leaf. Collections - meshsync.watchList,
meshsync.outputNamespaces, meshsync.outputResources,
broker.service.annotations, broker.service.loadBalancerSourceRanges - merge
whole: a layer that sets one replaces the lower layer's value entirely.
Element-wise merging of a whitelist or a namespace filter would produce a scope
neither layer asked for.
Every row is a distinct behavior. "Propagates to" names the cluster object the server writes; "Observable as" names what the user can actually see change.
| Setting | Wire path | Propagates to | Observable as |
|---|---|---|---|
| Deployment mode | operator.deploymentMode | Deploy/undeploy of the operator; MeshSync data pipeline teardown and reattach | Connection detail "MeshSync Deployment Mode"; operator/MeshSync/broker status chips in the header |
| Operator version | operator.version | meshery-operator Helm release chart version | Operator version in the header status chip; meshery-operator pod image |
deploymentMode is one of operator (Meshery Operator installs MeshSync and
Broker into the cluster) or embedded (MeshSync runs in-process inside Meshery
Server; nothing is installed into the cluster). The built-in default is
embedded.
operator.version is readconnections.OperatorChartVersionFromControllersConfig is the single reader.
It feeds MesheryControllersHelper.operatorDeploymentConfig, which overlays the
resolved value onto the controllers.OperatorDeploymentConfig assembled once at
boot by models.NewOperatorDeploymentConfig. That struct is what the meshkit
operator controller handler is constructed with, and its MesheryReleaseVersion
is the chart version passed to the meshery-operator Helm release.
Two consequences shape the code around it:
SetControllersConfig must run before AddCtxControllerHandlers. Every call
site orders them that way.MesheryControllersHelper.ReconcileOperatorChartVersion
re-attaches the handlers and re-runs the Helm release (installed with
UpgradeIfInstalled, so this is an in-place upgrade). It is a no-op in
embedded mode, when the operator is disabled server-wide or explicitly
undeployed for the context, and when the resolved version already matches the
attached handler's - so a chart-version change never resurrects an operator
the user turned off.Leaving the field unset at every layer resolves to "", and the boot-time chart
version applies unchanged: a connection on Inherit behaves exactly as it did
before the field was wired up.
operatorDeploymentConfig returns the version that was asked for. Nothing yet
guarantees such a chart exists, and two everyday cases guarantee it does not:
Chart publishing is decoupled from Meshery Server releases and trails them, so a current server routinely names a chart version the repository has not published. Helm then fails with a chart-not-found error and the operator never deploys.
Charts below models.MinimumOperatorChartVersion are published but are not
known to run: every one that was rendered from its published archive ships a
kube-rbac-proxy sidecar that affected clusters report as ImagePullBackOff,
and no webhook certificate. Because the derived
version tracks the server's own release, an old server would install one of
those on every cluster it is ever pointed at, forever.
The floor means only "below this, the chart cannot deploy at all" - it is not a
preference for newer charts. Setting it above a chart that provably works would
substitute a working release and tell the user, falsely, that theirs cannot
deploy. Its doc comment in server/models/operator_chart_version.go records
exactly which archives were rendered to establish the boundary; raise the
constant only with the same evidence.
MesheryControllersHelper.pinnedOperatorDeploymentConfig is therefore the only
deployment config allowed to reach Helm. It lists what the repository publishes
(helpers/utils.PublishedChartVersions) and hands that to
models.ResolveOperatorChartVersion, which distinguishes two sources:
OperatorChartVersionDerived) - the boot-time server release.
Nobody chose it, so it may be corrected: unpinned or unpublished falls back to
the newest published chart, and anything below the floor is raised to the
oldest published chart at or above the floor. Every correction returns a
one-sentence reason that is logged and emitted as a warning event, so no
substitution is silent.OperatorChartVersionRequested) - an explicit
operator.version. Never substituted. A moving tag or an unpublished version
fails through setOperatorError, which the connection-diagnostics API and the
events feed surface to the user. The floor does not apply, so deliberately
pinning an old chart still works.Both corrections above - the newest-published fallback and the floor raise -
draw only from stable releases. The repository publishes prerelease charts
(v0.6.0-rc.6, v0.5.0-rc-5g are real entries), and by semver a release
candidate outranks every stable chart below it, so an rc published ahead of its
release would otherwise become what every server whose own chart is not yet
published installs onto production clusters. A prerelease is still fully
reachable by name: an explicit operator.version naming one is honored exactly,
as is a derived version that already matches a published prerelease - a
prerelease server asking for its own prerelease chart chose nothing. A
repository that publishes only prereleases fails resolution
(ErrNoOperatorChartPublished) rather than having one selected for it.
Membership in the published set is decided by semver comparison, not by string
equality, because Helm treats 1.0.64 and v1.0.64 as the same version.
Resolution always returns the repository's own spelling of the matched release -
that is the string handed to Helm and the string
attachedOperatorChartVersion is compared against - and a spelling difference
is not a substitution, so it produces no reason.
PublishedChartVersions reads index.yaml through a per-repository cache in
server/helpers/utils/helm_chart_repo.go. That read happens inside the
cluster-connect request handler and the Meshery index is several megabytes, so
expiry is stale-while-revalidate, not a miss: an expired catalogue is served
immediately while a single-flighted refresh runs behind the caller, and only a
cold cache with nothing to serve blocks. Published charts are append-mostly, so
the worst a stale list costs is not yet knowing about the newest chart - which
the resolver already handles - whereas blocking would put a full
chartIndexTimeout in front of every connect whenever the TTL lapsed against a
slow repository. Failures are never cached as successes, so a repository outage
is retried on the next call rather than pinned in for a TTL.
An unreadable repository index fails rather than guessing: without the index
there is no way to know which versions exist. What that failure costs is
deliberately narrow. A chart version is what it takes to install the
operator, not to observe one - meshkit's mesheryOperator reads its
OperatorDeploymentConfig in Deploy and Undeploy only, never in GetStatus
or GetVersion - so all three handlers still attach and the operator card keeps
reporting a healthy operator's status and image tag, which is exactly the value
the troubleshooting guide
tells users to read. The failure is recorded on operatorChartError
(GetOperatorChartError) as well as setOperatorError, and every install path
refuses on it rather than handing Helm a version the repository does not
publish, which would surface as an opaque chart-not-found error instead.
Every install path means exactly that, and it is enforced by a single
function rather than by convention. operatorInstallTarget is the one guard, and
there are exactly three callers of Deploy on an operator handler in the whole
server - the FSM's DeployUndeployedOperators, the user-initiated
SetOperatorDeployment, and ReconcileOperatorChartVersion - all three of which
go through it. None can drift into installing an unpublishable version while the
others refuse it. ReconcileOperatorChartVersion was the last one to reach
Deploy by reading the handler out of the map directly; it was guarded only
incidentally, because AddCtxControllerHandlers happens to write
lastOperatorError and operatorChartError together, and five other writers of
lastOperatorError could have broken that coupling. If you add a fourth caller,
route it through the guard or this paragraph becomes false.
The GraphQL changeOperatorStatus mutation is the second entry point and calls
SetOperatorDeployment through the connection's helper (resolved via the state
machine, the same route resync and controller-status take). It previously read
a MesheryControllerHandlersKey context value that nothing ever populated -
that key is now retired; do not reintroduce it.
A latched operatorChartError is not permanent. It is written only where
handlers are attached, so a connect that landed during a chart-repository outage
would otherwise refuse every later install for the life of that connection, long
after the repository came back - while ErrHelmChartIndex tells the user to
confirm the repository is reachable and retry. SetOperatorDeployment
therefore re-runs AddCtxControllerHandlers when a chart error is latched, which
makes that instruction true: clicking deploy again genuinely re-resolves.
Clearing the latch on its own would not be enough - the handler the failure path
attached still carries the raw unresolved chart version, so the latch and the
handler have to be corrected together, which is exactly what re-attaching does.
The latch clears only as a consequence of a resolution that succeeded; one that
fails again replaces it with the fresh error and the guard refuses on that
instead of falling through to a Deploy. The FSM paths need no equivalent
because they always run straight after a fresh AddCtxControllerHandlers, and
ReconcileOperatorChartVersion re-resolves before it installs.
"Only as a consequence of a resolution that succeeded" is where the clear
physically sits, and it has to stay there. AddCtxControllerHandlers clears
lastOperatorError at the top but clears operatorChartError on the success
path, beside the handler built from the resolved config. Both of its early
returns - an unreadable kubeconfig and a failed Kubernetes client - leave the
previously attached operator handler in place so the operator card keeps
reporting status, and that handler still carries whatever chart version it was
built with. Clearing the refusal at the top therefore produced the one state the
install guard cannot see: a stale handler holding an unresolved version with
GetOperatorChartError() reading nil, which the very next
DeployUndeployedOperators in an FSM chain would hand to Helm. Do not move that
clear back up.
UndeployDeployedOperators is deliberately not gated on the chart error:
removal is the direction to attempt rather than refuse, since refusing would
leave the operator running on a cluster the user asked to have it taken off.
Attempted is all it is, though - meshkit's ApplyHelmChart downloads and loads
the chart archive before dispatching UNINSTALL exactly as it does for
INSTALL, from the same repository whose index could not be read, so in the very
case that motivates not refusing, Undeploy fails at chart download, the
operator stays on the cluster, and the user gets a Helm error. A removal path
that does not need the archive would have to come from meshkit.
A missing MesheryOperator handler - which means only that the kubeconfig or
the Kubernetes client failed - is reported through ErrOperatorHandlerNotAttached
rather than passed over in silence, so a lifecycle request that did nothing does
not read to the user as one that succeeded. Two things bound that report:
K8sContext) rather than read from MesheryControllersHelper.contextID, which
nothing assigns. That field's emptiness is a separate latent bug - it makes
UpdateOperatorsStatusMap's ot.IsUndeployed(mch.contextID) probe the
empty-string key forever - and is documented at its declaration rather than
fixed here, because assigning it would silently change operator-undeploy
behavior.UndeployDeployedOperators reports a missing handler only when the operator
status was ever genuinely observed (not the controllers.Unknown the
constructor seeds), so deleting a connection that never had an operator does
not alert about failing to remove one. User-initiated deploy and undeploy are
not gated this way - those always report.Relatedly, the missing-handler error never overwrites a more specific one:
setOperatorErrorIfUnset records it only when nothing is already recorded. "No
handler is attached" is the consequence of the unreadable kubeconfig or failed
Kubernetes client that AddCtxControllerHandlers already recorded by name, and
letting the consequence replace the cause degraded the diagnostic on teardown.
The controller-status snapshot is built from models.MesheryControllers, not
from the attached-handler map, so a connection with a ready FSM context always
reports exactly one row per controller. A controller with no handler behind it
reports UNKOWN and no version - Meshery made no observation of the cluster, so
any other value would assert something it did not check. Without that the card
disappears from the UI, because the client replaces its controller state with
each snapshot wholesale: an unreadable kubeconfig or a failed Kubernetes client,
where no handlers attach at all, would drop all three cards. The reason a row is
unknown belongs to the connection diagnostics - operator_deploy_failed reads
GetOperatorError - not to the status payload.
NewOperatorDeploymentConfig consequently leaves the chart version empty for an
unstamped build instead of asking the GitHub releases API for the newest server
tag. The newest GitHub release is not the newest published chart, so that call
spent a rate-limited request to produce a version that frequently does not exist
in the chart repository; an empty version resolves to the newest published chart,
which is what was wanted.
ReconcileOperatorChartVersion compares pinned against pinned.
attachedOperatorChartVersion always records a published version, so comparing
the raw request against it would differ forever whenever the request is being
substituted - re-running the Helm upgrade on every reconcile.
| Setting | Wire path | Propagates to | Observable as |
|---|---|---|---|
| Version | meshsync.version | MeshSync CR spec.version | MeshSync version in the header status chip; MeshSync pod image |
| Replicas | meshsync.replicas | MeshSync CR spec.size | MeshSync pod count |
| Watch list | meshsync.watchList | MeshSync CR spec.watch-list.data.{whitelist,blacklist} + rolling restart | Which resources appear under Dashboard -> Resources |
| Output namespaces | meshsync.outputNamespaces | MeshSync Deployment arg --outputNamespaces | Which namespaces' resources are published |
| Output resources | meshsync.outputResources | MeshSync Deployment arg --outputResources | Which kinds are published |
| Secret redaction | meshsync.redactSecrets | MeshSync Deployment env MESHSYNC_REDACT_SECRETS | Secret values redacted in Dashboard -> Resources |
| Broker content dedup | meshsync.brokerContentDedup | MeshSync Deployment env MESHSYNC_BROKER_CONTENT_DEDUP | Fewer duplicate MeshSync events in the notification center |
| Debug logging | meshsync.debugLogging | MeshSync Deployment env DEBUG | MeshSync pod logs |
watchList accepts at most one of whitelist or blacklist; both set is
rejected. MeshSync reads its watch-list at startup only, so a watch-list change
also stamps meshery.io/restarted-at on the MeshSync Deployment pod template,
which rolls the pods.
Be precise about what that guarantee covers. Every setting in this section that propagates to the Deployment - the three env vars and the two output-filter args
meshery.io/restarted-at
is refreshed only when the watch-list changes, and the previously-applied
value is otherwise carried forward unchanged, so an apply that changes nothing
in the pod template does not roll pods gratuitously. A watch-list change is the
only thing that forces a restart when the template is otherwise identical.Version, replicas and watch-list are operator-mode only: they live on the MeshSync custom resource, which embedded-mode clusters never install.
| Setting | Wire path | Propagates to | Observable as |
|---|---|---|---|
| Version | broker.version | Broker CR spec.version | Broker version in the header status chip |
| Replicas | broker.replicas | Broker CR spec.size | NATS statefulset replica count |
| Service type | broker.service.type | Broker CR spec.service.type | meshery-broker Service type; broker endpoint |
| Service annotations | broker.service.annotations | Broker CR spec.service.annotations | Annotations on the broker client Service |
| Load balancer class | broker.service.loadBalancerClass | Broker CR spec.service.loadBalancerClass | Which LB controller provisions the Service |
| Load balancer source ranges | broker.service.loadBalancerSourceRanges | Broker CR spec.service.loadBalancerSourceRanges | Which CIDRs may reach the broker |
| External endpoint override | broker.service.externalEndpointOverride | Broker CR spec.service.externalEndpointOverride | The advertised broker endpoint (connection diagnostics) |
loadBalancerClass and loadBalancerSourceRanges are valid only when
service.type is LoadBalancer; the server rejects them otherwise, and the
form clears them when the effective type changes away from LoadBalancer.
Service changes reconcile in place and must not restart broker pods.
Meshery Operator manages MeshSync and Meshery Broker, so the deployment mode is
not one setting among many - it decides which of the others can reach anything.
In embedded mode Meshery Server runs MeshSync in-process and installs nothing
into the cluster: no operator release, no MeshSync Deployment, no Broker, no
meshery.io custom resources.
| Setting | operator | embedded |
|---|---|---|
operator.deploymentMode | applies | applies |
operator.version | applies | inert - no operator release is installed |
meshsync.outputNamespaces, meshsync.outputResources | applies | applies - passed to the in-process libmeshsync run |
meshsync.version, meshsync.replicas, meshsync.watchList | applies | inert - MeshSync CR absent |
meshsync.redactSecrets, meshsync.brokerContentDedup, meshsync.debugLogging | applies | inert - these are env on the MeshSync Deployment; embedded MeshSync takes them from the Meshery Server process environment |
every broker.* | applies | inert - no Broker on the cluster |
The server states this at apply time through
ControllersConfigApplyResult.Skipped. The UI states it before the save:
ui/components/configuration/deploymentMode.ts is the single client-side
statement of the same structure (takesEffectIn), and the editors are governed
by it - the per-connection editor renders a setting the effective mode cannot
apply as inert, marks it Not applied, and says why in the form body rather
than in a tooltip. Values already stored for such a setting are kept and shown
as dormant with a control to clear them; they become live again if the
connection moves to operator mode.
The server-wide defaults editor annotates instead of disabling: its mode is only
what inheriting connections get, and a connection that overrides the mode to
operator uses every value stored there.
That decision needs the mode the connection actually runs, which is why
GET /api/integrations/connections/{connectionId}/controllers/config resolves
effective.operator.deploymentMode through
connections.ResolveConnectionControllersConfig rather than by merging the two
editable layers: a connection whose mode comes from the materialized cache or
from MESHSYNC_DEFAULT_DEPLOYMENT_MODE would otherwise be described as running
the built-in embedded mode, and every applicability decision made from that
value would be wrong. merged is deliberately left untouched - it is what
propagates to the cluster and must keep carrying only explicitly-set fields.
Every cluster write uses server-side apply under the meshery-server field
manager (server/models/controllers_config_apply.go). The applied document
always describes the complete set of fields Meshery Server owns, so:
The operator applies the same objects under its own field manager and never sets these env names, args, or the restart annotation, so ownership stays disjoint.
Absent custom resources or Deployment (operator not deployed yet, embedded-mode
cluster) are skipped and reported in ControllersConfigApplyResult.Skipped,
not treated as errors: the configuration re-applies when the connection
reconnects.
These are not part of controllers_config but govern the same three components.
Contributors changing controller behavior must account for them.
| Setting | Where | Storage | Notes |
|---|---|---|---|
MESHSYNC_DEFAULT_DEPLOYMENT_MODE | Server env / viper | Process config | Fallback when no layer and no materialization sets a deployment mode. Logged at boot. |
| MeshSync deployment mode (wizard) | Connection Wizard -> MeshSync Mode step | controllers_config.operator.deploymentMode | Reconfigure-time picker. Writes the override through connections.SetDeploymentModeOverride via POST /api/integrations/connections/{id}/actions (setMeshsyncMode). |
| MeshSync deployment mode (per-context, at import) | Connection Wizard -> kubeconfig context review | Same field, per context | Written only when the user actually picks one; otherwise the connection inherits. |
| Operator status | GraphQL changeOperatorStatus | Cluster state | Deploys/undeploys the operator directly, bypassing the layered document. |
connection.metadata.meshsync_deployment_mode used to carry two different
facts under one key - the user's explicit per-connection choice and a
materialized cache of the resolved mode - and that ambiguity was the root cause
of two separate defects. The two are now separated
(server/models/connections/deployment_mode_resolution.go):
controllers_config.operator.deploymentMode is the only store of the
explicit choice. Every entry point - the wizard's MeshSync Mode step, the
kubeconfig import picker, the controllers editor - writes it through
connections.SetDeploymentModeOverride, so no two controls can disagree
about what a connection is set to.meshsync_deployment_mode is only the materialization of the resolved
mode, written through connections.MaterializeMeshsyncDeploymentMode and
read by the consumers that predate the layered document (the connection state
machine, the header status chips, the kubeconfig flows).connections.ResolveDeploymentMode is the single decision point, and it reports
the layer it resolved from:
| Precedence | Layer | Reported as |
|---|---|---|
| 1 (highest) | Layered document (per-connection override over server-wide default) | layeredConfig |
| 2 | Materialized meshsync_deployment_mode | legacyConnectionMetadata |
| 3 | MESHSYNC_DEFAULT_DEPLOYMENT_MODE | serverEnvDefault |
| 4 (lowest) | Compiled-in default (embedded) | builtIn |
Ranking the materialization below the layered document is what lets a server-wide default reach an existing connection: every Kubernetes connection has that key written at registration, so while it sat on top no fan-out could ever change a mode. It survives as a compatibility floor for connections registered before the layered document existed - their recorded mode is kept when, and only when, no layer sets one.
A server-wide default change is not just a document to re-apply.
reconcileInheritedDeploymentMode persists the refreshed materialization and
drives the same undeploy/redeploy path the wizard uses, so an inheriting
connection actually switches modes on the cluster.
| Method | Path | Handler |
|---|---|---|
GET | /api/system/controllers/config | GetControllersDefaultConfig |
PUT | /api/system/controllers/config | UpdateControllersDefaultConfig |
GET | /api/integrations/connections/{connectionId}/controllers/config | GetConnectionControllersConfig |
PUT | /api/integrations/connections/{connectionId}/controllers/config | UpdateConnectionControllersConfig |
Both PUTs validate before persisting (connections.ValidateControllersConfig)
and return the stored document. The connection PUT additionally applies the
resolved configuration to that connection's cluster; the system PUT fans the
re-apply out to every tracked Kubernetes connection.
Writes are asynchronous with respect to the cluster: the override persists even if the apply fails, and the failure surfaces as an event rather than an HTTP error, because the configuration re-applies on the next connect.
Tracked here so they are not rediscovered. Each is a defect, not a design.
ApplyControllersConfigToCluster returns
which custom resources it patched, whether MeshSync was restarted, and a
Skipped[] list with human-readable reasons. That result only reaches event
metadata; both editors report "saved" either way, so a save that changed
nothing on the cluster looks identical to one that changed everything.Unit coverage that exists today:
server/models/connections/controllers_config_test.go - precedence, atomic
collection merge, metadata round-trip, validation, and the single reader of
operator.version.
server/models/connections/deployment_mode_resolution_test.go - deployment
mode precedence (a server-wide default reaching an inheriting connection),
the wizard/editor convergence on one store, and the effective document
reporting the mode a connection actually runs.
server/models/operator_chart_version_test.go - operator.version selecting
the operator Helm chart version, the layering it resolves through, and the
cases where a chart-version reconcile must not touch the cluster.
server/models/operator_chart_pinning_test.go - pinning the resolved version
to one the repository publishes: the floor, the unpublished-release fallback,
moving tags never reaching Helm, explicit requests failing loudly, prereleases
excluded from every automatic selection but honored when named, the
pinned-against-pinned reconcile comparison, and the split between withholding
installation and withholding observation (all three handlers still attach when
no chart version resolves; all three install paths - the FSM reconcile, the
chart-version reconcile, and the user-initiated SetOperatorDeployment -
refuse through the shared guard; a latched chart error is re-resolved on a
user-initiated retry, survives a re-attach that never reached resolution, and
clears only when resolution actually succeeds; undeploy does not refuse, a
missing handler is reported by name with its context id rather than passed
over, teardown of a never-connected connection stays quiet, and the
kubeconfig/client diagnostic survives that teardown).
These are unit tests and none of them may reach a meshkit Deploy or
Undeploy. reachableK8sContext yields real meshkit handlers, and meshkit
downloads the chart archive before it touches the cluster - so a test that
reaches an install performs live Helm I/O, and really installs the operator
wherever 127.0.0.1:6443 answers (Docker Desktop Kubernetes, k3s). Assert
through operatorInstallTarget, or swap a stubController in first. The two
context helpers are a matched pair and say so at their declarations:
reachableK8sContext enables real handlers, unresolvableK8sContext reliably
prevents them - and because the latter depends on meshkit rejecting the
kubeconfig rather than falling back to the ambient one, every test built on it
calls requireUnresolvableK8sContext so a meshkit change surfaces as a
failure rather than as a real install.
reattachControllerHandlers is injected on the helper for the same reason
chartVersions is. AddCtxControllerHandlers clears the chart refusal exactly
where it resolves, so it can never return having both succeeded and left one
standing - which makes the guard's refusal branch unreachable, and would leave
an install site that stopped consulting the guard entirely unobserved. The
seam lets TestReconcileInstallGoesThroughTheSharedGuard produce that state
with a stub handler attached, so dropping the guard call fails the test by
construction instead of silently.
server/helpers/utils/helm_chart_repo_test.go - the index.yaml read: chart
version extraction, structured failures, TTL reuse, stale-while-revalidate on
expiry (including through a failing refresh), that only a cold cache blocks,
that failures are not cached, that the lock is not held across the fetch, that
concurrent misses single-flight, that a panicking fetch leaves the cache
usable, and that the cached catalogue is never handed out by reference.
server/handlers/controllers_status_handler_test.go - that the status
snapshot carries one row per controller, sorted, even when no handlers are
attached at all.
ui/components/configuration/__tests__/deploymentMode.test.ts - which
settings each deployment mode can apply, and how the mode governing each
editor is resolved and attributed to a layer.
ui/components/configuration/__tests__/ControllersConfigForm.test.tsx - the
rendered editor: tri-state inherit/override, the conditional LoadBalancer-only
fields, and the deployment-mode gating (inert-and-explained on a connection,
annotated-but-live on the server-wide defaults).
server/models/controllers_config_apply_test.go - cluster propagation with
fake clients: per-setting custom-resource and Deployment patch contents,
withdrawal when a field is cleared at every layer,
restart-only-on-watch-list-change, and the Skipped[] reporting.
server/handlers/controllers_config_handlers_test.go - the four endpoints:
validation rejection, the layered response shape, clearing an override, and
that an unreadable override is skipped rather than reconciled.
End-to-end coverage lives in ui/tests/e2e/controllers-config.spec.ts, keyed to
the Operator, MeshSync & Broker Settings Test Plan Test Group via the Allure
testGroup label - the same mechanism the Connection Lifecycle report uses (see
[Contributing to Meshery's CLI tests]({{< relref "cli/tests.md" >}})). It covers
every wire path in the tables above plus the precedence chain, the inherit
round-trip, validation rejection, and the mode gating.
What remains uncovered:
Before adding a setting, add its row above, its propagation assertion, and its end-to-end case. A setting whose effect a user cannot observe is a defect; so is one that fails silently.