Skip to content

feat(yconverge): label selector that propagates to dependencies#13

Merged
solsson merged 3 commits intomainfrom
yconverge-selector
May 2, 2026
Merged

feat(yconverge): label selector that propagates to dependencies#13
solsson merged 3 commits intomainfrom
yconverge-selector

Conversation

@solsson
Copy link
Copy Markdown
Contributor

@solsson solsson commented May 1, 2026

No description provided.

solsson and others added 3 commits May 1, 2026 21:30
Adds `-l <selector>` / `--selector` to `y-cluster yconverge`
(and the kubectl-yconverge plugin form), mirroring kubectl's
own `apply -k -l <selector>` filter. The selector ANDs into
every kubectl invocation in the apply phase, including the
converge-mode label routing -- so a `-l app=foo` run still
picks the right apply strategy per resource (create / replace
/ serverside-force / serverside / default) but only touches
resources matching the user's filter.

Propagates to dependency recursion. Without propagation a
selector would filter the target's apply but leave deps
unfiltered, which is incoherent when the selector represents
a coherent slice of the system the user wants to operate on
end-to-end.

Coverage:
- Unit (pkg/yconverge/kubectl_test.go): selector AND-ing
  into every group, empty-selector preserving the internal
  body verbatim, default group's negative-mode exclusions
  preserved alongside the user term, kubectl set syntax
  ("tier in (a, b)") passed through unmodified.
- Kwok e2e (e2e/yconverge_selector_test.go): a target with
  a dep, each carrying app=foo and app=bar configmaps;
  baseline applies all four; `-l app=foo` applies foo-* in
  both modules and skips bar-* in both.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two safety + coverage extensions to the label-selector feature:

1. Bail when the user selector matches zero resources in the
   kustomize tree. Without this safeguard a typo in -l (or a
   stale label) silently produces a no-op apply via the
   per-group "no objects passed to apply" tolerance -- the kind
   of surprise users tend to read as "everything's fine" rather
   than "the selector skipped the apply". preflightSelectorMatches
   uses `kubectl apply --dry-run=client -k <dir> -l <user> -o name`
   (no apiserver round-trip) and convergeSingle bails before
   touching the cluster when the count is zero.

2. Multi-mode e2e fixture: the test target now carries one foo +
   one bar ConfigMap for each converge-mode (default / create /
   replace / serverside-force / serverside) plus the dep's pair
   in default mode -- 12 ConfigMaps total. The new tests:

   - TestSelector_FiltersAcrossAllConvergeModes -- every mode's
     foo-* applies, every mode's bar-* is skipped, in BOTH
     target and dep. Catches bucket-routing or AND-composition
     regressions across the whole apply plan.
   - TestSelector_IdempotentReapply -- two consecutive applies
     with the same selector exercise per-mode tolerances
     (AlreadyExists on create, no-op delete on replace's first
     step, SSA merge on serverside modes) under filtering.
   - TestSelector_ReplaceModeSafetyAcrossSelectorChange -- the
     "delete must never touch what the user didn't intend"
     contract: a bar-replace ConfigMap applied unfiltered keeps
     its UID across a subsequent `-l app=foo` apply, proving the
     converge-mode AND user-selector AND filter is honored by
     the replace-mode delete step.
   - TestSelector_BailsWhenNoMatch -- the new preflight surfaces
     a clear "selector matched no resources, refusing to apply"
     rather than silently succeeding.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The PR's e2e suite covers the bail-on-zero behaviour through a
real cluster, but the count parser, the kubectl argv, and the
"no objects passed to apply" zero-match recognition had no
unit-level pin. Adds a fake-kubectl-on-PATH harness (same
shape as pkg/provision/docker/docker_test.go's) and four
focused tests:

  - Argv: --context= comes first, then `apply --dry-run=client`,
    then `-k <dir> -l <selector> -o name`. A regression that
    drops --dry-run=client (and silently round-trips to the
    apiserver) or reorders the flags fails before the cluster
    sees anything.
  - Zero-match: kubectl's real shape (exit 1, "no objects
    passed to apply" on stderr) returns (0, nil), not an
    error. Without this pin a refactor of the substring match
    would surface as an apply failure at runtime instead of
    the user-friendly "selector matched no resources" bail.
  - Empty stdout / exit 0: trimmed == "" must produce 0, not
    1 (which a naive strings.Count("\n")+1 would otherwise
    yield).
  - Other-error propagates: a kubectl failure that isn't the
    zero-match shape must surface; otherwise broken kustomize
    trees, missing contexts, or daemon outages would silently
    look like "selector matched no resources".

Also adds boundary cases (single match, multi-line, trailing
whitespace) so the count parser stays exact at the edges.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@solsson solsson merged commit e942e82 into main May 2, 2026
11 checks passed
solsson added a commit to Yolean/ystack that referenced this pull request May 2, 2026
v0.3.6 (Yolean/y-cluster#13) fixes the silent-drop where the
docker provider built every PortBinding with HostIp left as the
zero netip.Addr. moby v1.54+ marshals an invalid Addr as the
empty JSON string, and Docker Engine 28 (ubuntu-latest) drops
those bindings, leaving the container running with
NetworkSettings.Ports = {}. With the four-port acceptance config
(6443/80/443/8944) this manifested as kubectl getting
"connection refused" for the entire 60s host /readyz probe added
in v0.3.5.

Drop the diagnostic block (pre-provision dump, docker run -p
control, backgrounded port-state poller) and restore the linear
single-line `y-cluster provision` call. The y-kustomize
Deployment image moves to the matching v0.3.6 tag.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant