Skip to content

feat: handle charm and model type mismatch at deploy#22773

Open
sinanawad wants to merge 6 commits into
juju:4.0from
sinanawad:JUJU-10101-charm-model-type-mismatch
Open

feat: handle charm and model type mismatch at deploy#22773
sinanawad wants to merge 6 commits into
juju:4.0from
sinanawad:JUJU-10101-charm-model-type-mismatch

Conversation

@sinanawad

@sinanawad sinanawad commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Deploying a Kubernetes (sidecar) charm to a machine model, or a machine charm
to a Kubernetes model, is not something Juju guards against. Unless the charm
declares assumes: k8s-api, both directions deploy cleanly and then break
silently: the unit starts but the workload never runs. When the deploy does
fail, it fails on an incidental check — typically block storage "..." is not supported for container charms — which never mentions the actual problem.

At deploy time the charm is resolved but not yet persisted, so state-backed
checks are unusable on both the client and the apiserver. Charm metadata is
the only available signal, and it has no positive "machine charm" marker; what
it does have is containers:

  • Meta.IsSidecar and Meta.ModelMismatch classify the charm and build the
    rejection or warning. IsSidecar matches the row-counting semantics of the
    model's SupportsContainers check, so an empty containers: {} block is
    not a sidecar charm, and subordinates — machine charms with no containers
    by nature — are never flagged.
  • The DeployFromRepository result gains an additive Warnings field:
    charmhub deploys resolve server side, and the result previously carried
    nothing short of an error back to the user. Warnings are also logged on the
    controller for API clients that do not render results. The major change
    is in eaa13ac.
  • The CLI prints the warning: directly for local charm deploys, and from the
    returned Warnings — ahead of any errors — for charmhub deploys.

Before this change a mismatched deploy produced silence or a misleading
error. After it, both paths print, for example:

WARNING "juju-norma" declares no containers but "mymodel" is a Kubernetes model; it has no workload to run there

Per review, the two directions are treated differently. A Kubernetes charm
on a machine model is unambiguous — the declared containers can never run —
so it is now rejected with a not-supported error (--force downgrades the
rejection to a warning, mirroring the existing assumes behaviour). The
machine-charm-on-Kubernetes direction is inferential (charm metadata has no
positive machine-charm marker), so it remains an advisory warning.

APIBase.DeployFromRepository previously set a result's Info only on
success, which would have dropped the warnings for rejected deploys; it is
now set unconditionally.

Bundle deploys are not instrumented — a mismatched charm inside a bundle
does not warn. The bundle seam is deliberate follow-up scope.

Checklist

  • Code style: imports ordered, good names, simple structure, etc
  • Comments saying why design decisions were made
  • Go unit tests, with comments saying what you're testing
  • Integration tests, with comments saying what you're testing (advisory output only; unit tests cover all three layers, manual QA below)
  • doc.go added or updated in changed packages (no new packages)

QA steps

Machine charm on a Kubernetes model (charmhub deploy):

$ juju add-model k8stest
$ juju deploy juju-norma -m k8stest
WARNING "juju-norma" declares no containers but "k8stest" is a Kubernetes model; it has no workload to run there
ERROR block storage "blk" is not supported for container charms
ERROR failed to deploy charm "juju-norma"

Kubernetes charm on a machine model (local charm deploy):

$ juju deploy ./juju-norma-k8s_*.charm -m lxdtest
ERROR "juju-norma-k8s" is a Kubernetes charm (it declares containers) but "lxdtest" is a machine model; its workload will not run
$ juju deploy ./juju-norma-k8s_*.charm -m lxdtest --force   # proceeds with a warning

Correct placements emit no warning:

$ juju deploy juju-norma -m lxdtest
$ juju deploy juju-norma-k8s -m k8stest

The controller log carries the same warning for non-CLI clients:

$ juju debug-log -m controller --include-module juju.apiserver.deployfromrepo

Facade change (additive Warnings result field), so model migration was
verified:

$ juju bootstrap lxd src36            # 3.6.24
$ juju add-model moveme1 && juju deploy juju-qa-test
$ juju bootstrap lxd dst40            # this branch, --build-agent
$ juju migrate src36:moveme1 dst40 && juju add-unit juju-qa-test
$ juju debug-log -m dst40:controller && juju debug-log -m dst40:moveme1

The model migrated, the added unit came up active, and the only ERROR-level
log lines are the standard migration-cutover watcher shutdowns and the
fresh machine's "container types not yet available" transient; nothing
references the new field or the application facade.

The 4.0 to 4.0 leg cannot currently be exercised: it is broken on the 4.0
branch itself, independent of this change.
The source side of the
password-to-macaroon exchange landed on 4.0 in #22675 and requires
MigrationTarget v8 on the target (internal/migration/auth.go:42), but the
target-side v8 facade landed on main only (#22655, #22674) and has not been
backported, so any password-authenticated 4.0 to 4.0 migration fails at
precheck with "target controller is too old...". This PR touches no
migration, auth or facade-registration files; the leg will be re-run once
v8 reaches 4.0.

Documentation changes

None — advisory warning only; the Warnings result field is additive and no
CLI flags or command shapes change.

Links

Jira card: JUJU-10101

sinanawad added 3 commits July 2, 2026 13:01
Juju does not stop a Kubernetes charm being deployed to a machine model,
or a machine charm to a Kubernetes model. Unless the charm declares
"assumes: k8s-api", both directions deploy silently and then break, or
fail later on an incidental check (e.g. block storage) whose message
never mentions the real problem.

Add the classification to charm metadata, the only signal available at
deploy time on both the client and the apiserver (the charm is resolved
but not yet persisted, so state-backed checks cannot be used):

- Meta.IsSidecar reports whether the charm declares workload containers.
  It intentionally matches the row-counting semantics of the model's
  SupportsContainers check, so an empty "containers: {}" block does not
  classify as a sidecar charm.
- Meta.ModelMismatchWarning returns a user-facing warning for the two
  mismatch directions. Subordinate charms declare no containers but are
  machine charms by nature, so they are never flagged on a Kubernetes
  model. The check is advisory only and never blocks a deploy.

MetaFormat now uses IsSidecar in place of its inline containers check.

refers to JUJU-10101
Charmhub deploys are resolved server side via DeployFromRepository, so a
charm/model type mismatch can only be detected on the apiserver, and the
result carried no channel to tell the deploying user anything short of
an error.

Add a Warnings field to DeployFromRepositoryInfo. The validator computes
mismatch warnings from the resolved charm metadata, logs them on the
controller for clients that do not render results, and threads them into
the returned info on both the success and the validation-error paths, so
the user sees the context alongside a rejection.

Before this commit, the facade only set a result's Info on the success
path, silently dropping the payload for rejected deploys; it is now set
unconditionally.

refers to JUJU-10101
Surface the charm/model type mismatch warnings on the deploying user's
terminal, in both deploy paths:

- Local charm deploys hold the charm metadata client side, so the
  deployer checks it directly before calling the API.
- Charmhub deploys print the warnings returned by DeployFromRepository,
  ahead of any errors, so the context is visible even when the deploy is
  rejected (e.g. by the block storage precheck, whose message otherwise
  never mentions the charm type).

The warning is advisory only; deploys proceed exactly as before.

refers to JUJU-10101

@manadart manadart left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just some minor ordering/semantic changes.

Comment thread apiserver/facades/client/application/deployrepository.go Outdated
Comment thread cmd/juju/application/deployer/charm.go Outdated
Comment thread domain/deployment/charm/meta.go Outdated
Comment thread domain/deployment/charm/meta.go Outdated
Comment thread domain/deployment/charm/meta.go Outdated
sinanawad added 2 commits July 2, 2026 17:28
Return the already-built result info from every post-validation error
path in DeployFromRepository, so accumulated warnings are no longer
hidden from the user when the deploy is rejected after validation.

Also from review: emit the client-side mismatch warning before the charm
format check; drop the IAAS/CAAS jargon from the user-facing messages in
favour of "Kubernetes model" and "machine model"; return a plain string
from Meta.ModelMismatchWarning and test for empty at the callers; name
the parameter isK8s in line with the caas-to-k8s direction.

refers to JUJU-10101
From review: a charm that declares workload containers can never run
them on a machine model, so this direction is now rejected with a
not-supported error instead of a warning; --force downgrades the
rejection to a warning, mirroring the assumes handling. The inverse
direction cannot be classified with certainty (charm metadata has no
positive machine charm marker), so it remains an advisory warning.

Meta.ModelMismatchWarning becomes Meta.ModelMismatch, returning the
warning and/or the rejection; both deploy seams honour --force.

refers to JUJU-10101
@sinanawad sinanawad changed the title feat: warn on charm and model type mismatch at deploy feat: handle charm and model type mismatch at deploy Jul 2, 2026
@sinanawad sinanawad marked this pull request as ready for review July 2, 2026 15:12
Revision int `json:"revision"`
// Warnings holds advisory, non-blocking messages about the deployment
// (e.g. a charm/model-type mismatch) for the client to surface to the user.
Warnings []string `json:"warnings,omitempty"`

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We won't need to bump the facade as this is optional, though older facade versions (19 for example) will emit the warnings, though it should be harmless.

The Warnings field added to DeployFromRepositoryInfo changed the client
facade wire shape; regenerate the schema to satisfy the static-analysis
schema check.

refers to JUJU-10101
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants