1
0
mirror of synced 2026-06-26 21:50:48 +00:00

cmd: support type!=status in get --status-selector

`flux get --status-selector` only supported equality (`type=status`),
so finding objects that are not in a given state required multiple
invocations, e.g. listing everything that is not ready needed both
`Ready=False` and `Ready=Unknown`.

Add support for a negated selector `type!=status`. Since all resource
adapters delegate matching to the shared `statusMatches` helper and
filtering is centralised in `getRowsToPrint`, negation is implemented
purely in the parse/filter layer by inverting the match result. This
covers every resource type and the `--watch` path without touching the
per-resource adapters.

A missing condition is treated as not-matching by `statusMatches` (Flux
considers it "waiting to be reconciled"), so `Ready!=True` also surfaces
objects that have no Ready condition yet, i.e. the complete not-ready set:

    flux get all -A --status-selector Ready!=True

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: 3uzbcqje <3uzbcqje@addy.to>
This commit is contained in:
3uzbcqje
2026-06-24 10:53:37 -07:00
parent e833099e1d
commit 5afd1d8728
6 changed files with 144 additions and 6 deletions
+21 -6
View File
@@ -78,7 +78,7 @@ func init() {
getCmd.PersistentFlags().BoolVarP(&getArgs.noHeader, "no-header", "", false, "skip the header when printing the results")
getCmd.PersistentFlags().BoolVarP(&getArgs.watch, "watch", "w", false, "After listing/getting the requested object, watch for changes.")
getCmd.PersistentFlags().StringVar(&getArgs.statusSelector, "status-selector", "",
"specify the status condition name and the desired state to filter the get result, e.g. ready=false")
"specify the status condition name and the desired state to filter the get result, e.g. ready=false or ready!=true")
getCmd.PersistentFlags().StringVarP(&getArgs.labelSelector, "label-selector", "l", "",
"filter objects by label selector")
rootCmd.AddCommand(getCmd)
@@ -230,10 +230,18 @@ func namespaceNameOrAny(allNamespaces bool, namespaceName string) string {
func getRowsToPrint(getAll bool, list summarisable) ([][]string, error) {
noFilter := true
var conditionType, conditionStatus string
var negate bool
if getArgs.statusSelector != "" {
parts := strings.SplitN(getArgs.statusSelector, "=", 2)
// Support both type=status (match) and type!=status (negated match).
// "!=" must be checked first since it also contains "=".
separator := "="
if strings.Contains(getArgs.statusSelector, "!=") {
separator = "!="
negate = true
}
parts := strings.SplitN(getArgs.statusSelector, separator, 2)
if len(parts) != 2 {
return nil, fmt.Errorf("expected status selector in type=status format, but found: %s", getArgs.statusSelector)
return nil, fmt.Errorf("expected status selector in type=status or type!=status format, but found: %s", getArgs.statusSelector)
}
conditionType = parts[0]
conditionStatus = parts[1]
@@ -241,10 +249,17 @@ func getRowsToPrint(getAll bool, list summarisable) ([][]string, error) {
}
var rows [][]string
for i := 0; i < list.len(); i++ {
if noFilter || list.statusSelectorMatches(i, conditionType, conditionStatus) {
row := list.summariseItem(i, getArgs.allNamespaces, getAll)
rows = append(rows, row)
if !noFilter {
matches := list.statusSelectorMatches(i, conditionType, conditionStatus)
if negate {
matches = !matches
}
if !matches {
continue
}
}
row := list.summariseItem(i, getArgs.allNamespaces, getAll)
rows = append(rows, row)
}
return rows, nil
}