[deckhouse-cli] New plugins contract support - impl [2/2]#347
Open
Glitchy-Sheep wants to merge 12 commits into
Open
[deckhouse-cli] New plugins contract support - impl [2/2]#347Glitchy-Sheep wants to merge 12 commits into
Glitchy-Sheep wants to merge 12 commits into
Conversation
…to internal This is for consistency with other commands and their layouts Signed-off-by: Roman Berezkin <roman.berezkin@flant.com>
Some of them are likely copied from mirror command, but in plugins there is no use of them. Signed-off-by: Roman Berezkin <roman.berezkin@flant.com>
…mand and plugins in general Signed-off-by: Roman Berezkin <roman.berezkin@flant.com>
…th builder functions) Signed-off-by: Roman Berezkin <roman.berezkin@flant.com>
- `runInstalledPlugin` returns errors, so the run path is testable and the command body just logs and exits on failure. - `ensureInstallRoot` centralizes the homedir fallback used by both `NewCommand` and `NewPluginCommand`. - `cachedDescription` wraps the contract cache lookup and returns "" when the file is missing or unreadable. - All path joins flow through the `layout` package (`PluginsRoot`, `CurrentLinkPath`, `ContractFile`). Signed-off-by: Roman Berezkin <roman.berezkin@flant.com>
- Add v2 schema types: deckhouse, plugins.{mandatory,conditional},
modules.{mandatory,conditional,anyOf}
- Smart UnmarshalJSON on group types: v1 flat arrays land in .Mandatory of v2
- Marshal always emits v2 (cache and `plugins contract` migrate over time)
- Factor ContractToDomain/DomainToContract into 6 helpers
- Validators: minimal compile-only updates (range over .Mandatory)
- 14 unit tests for smart unmarshal + round-trip
No behaviour change for v1 contracts. New fields populated but
not yet enforced.
Signed-off-by: Roman Berezkin <roman.berezkin@flant.com>
… conflict-check bug - Fix bug in validatePluginConflict: compare against plugin.Version (the NEW plugin) instead of installedPlugin.Version (which made the reverse conflict check a tautology) - Iterate both .Mandatory and .Conditional sections of an installed plugin's requirements during conflict check - Split validatePluginRequirement into Mandatory (soft, --resolve-able) and Conditional (hard error if installed + version fails) variants - Orchestrator validateRequirements calls both, in order - 3 unit tests on pure validatePluginConflict covering bug regression, happy path, and .Conditional section detection - nit: Remove obvious comments Signed-off-by: Roman Berezkin <roman.berezkin@flant.com>
- Add validateKubernetesRequirement and validateDeckhouseRequirement: Warn-log when the constraint is declared, return nil (no enforcement) - Replace empty validateModuleRequirement stub with per-section logging for .Mandatory / .Conditional / .AnyOf groups - Wire all three into validateRequirements after plugin validators - d8 now understands the v2 contract end-to-end and informs operators about declared-but-not-enforced cluster-side requirements Real cluster connectivity (kubeconfig + clientset + module discovery) deferred to a follow-up. Signed-off-by: Roman Berezkin <roman.berezkin@flant.com>
…ince we haven't released any support) - Remove UnmarshalJSON from PluginRequirementsGroupDTO and ModuleRequirementsGroupDTO; standard reflection unmarshal applies - Drop encoding/json and fmt imports from dto.go (no longer needed) - Slim dto_test.go to 2 cases: v2 positive end-to-end + v1 rejection - Update fixture in TestGetPluginContract_Success to v2 form Nothing released yet, so accepting both shapes is unnecessary tech debt. Any old v1 flat-array contract now surfaces a clear unmarshal error pinpointing the offending field. Signed-off-by: Roman Berezkin <roman.berezkin@flant.com>
Signed-off-by: Roman Berezkin <roman.berezkin@flant.com>
…structured log Signed-off-by: Roman Berezkin <roman.berezkin@flant.com>
Base automatically changed from
feat/new-plugins-contract-stage1-refactor
to
main
May 13, 2026 14:02
…-plugins-contract-stage2-implementation Signed-off-by: Pavel Okhlopkov <pavel.okhlopkov@flant.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This PR implements support for the new plugin contract format:
mandatoryconditionalanyOfThe refactor stage (PR
[1/2]) is the base of this branch and must be merged first.⭐ What the new contract format enables
deckhousefield for declaring "this plugin needs Deckhouse >= 1.65".mandatoryfor "always required"conditionalfor "only enforced if the dependency is actually installed". Useful when a plugin wants to say "if module X is enabled, I need at least v2.40 of it" without forcing X to be present.anyOfyou need at least one of N modules (e.g. some ingress controller, doesn't matter which).🐛 Alongside the format change, this PR also fixes one latent bug that existed in v1 and would have carried over:
installedPlugin.Versionagainst itself, which was tautologically true, so real conflicts were silently accepted. Now compares against the new plugin's version.📄 Contract shape: before vs after
🚶♂️➡️ Implementation walkthrough
Structured Requirements DTO.
Kubernetes,Deckhouse,ModuleRequirementsGroupDTO,PluginRequirementsGroupDTOreplace the flat arrays.ContractToDomain/DomainToContractfactored into 6 small per-field helpers.Validator split + conflict-check fix.
mandatoryis soft (resolvable with--resolve);conditionalis a hard error only when the dependency is actually installed..Mandatoryand.Conditionalof every installed plugin.Cluster-side requirements as log-only notices.
validateKubernetesRequirement/validateDeckhouseRequirement/validateModuleRequirementparse the constraints and print a two-line stderr record:Real cluster connectivity (kubeconfig + clientset + module discovery) is out of scope - lands in a follow-up PR.
Friendlier error messages.
unmarshalContracthelper rewritesencoding/jsonerrors as user-actionable messages, shared by the registry-annotation and local-file paths:Before:
After:
Verification
go build ./...clean at every commit.validatePluginConflictregression suite (bug regression, happy path, conditional detection), and the invalid-contract error paths.Follow-up
Real cluster-side enforcement (kubeconfig + clientset + module discovery against a live API server) is intentionally out of scope. The contract surface, validation skeleton, and operator-facing notices land in this PR; runtime enforcement lands later.