1

Why does this Powershell command sequence using 2 field selectors and Powershell variable $Node not return any pods?

$Node = "mynode000001"
$pods = (kubectl get pods --field-selector status.phase!=Succeeded,spec.nodeName=$Node -A -o json | ConvertFrom-Json).items

But - this Powershell command sequence does return pods

$Node = "mynode000001"
$command = "kubectl get pods --field-selector status.phase!=Succeeded,spec.nodeName=$Node -A -o json"
$pods = (Invoke-Expression $command | ConvertFrom-Json).items

Is there a more elegant fix than pre-parsing the command then calling it an invoke-expression?

Breaking the problem down into smaller chunks, I suspect the comma separating the field selectors is breaking the parsing of the Powershell variable after the comma, but don't know a more elegant solution than pre-parsing the command.

This Powershell command sequence with a single field selector and Powershell variable $Node returns K8s pods:

$Node = "mynode000001"
$pods = (kubectl get pods --field-selector spec.nodeName=$Node -A -o json | ConvertFrom-Json).items

This Powershell command with 2 kubectl field selectors separated by a comma and hard coded node name returns pods:

$pods = (kubectl get pods --field-selector status.phase!=Succeeded,spec.nodeName=mynode000001 -A -o json | ConvertFrom-Json).items
mpowrie
  • 603
  • 8
  • 14
  • 1
    Try quoting the fieldselector - ```--field-selector "status.phase!=Succeeded,spec.nodeName=$Node"```. Not sure if ```kubectl``` will actually like that, but PowerShell will interpret it as a string instead of an array of values. If you compare the parsed commands you can see the difference in how it interprets it as a ```DoubleQuoted``` string instead of a ```System.Object[]``` - ```{ kubectl get pods --field-selector "status.phase!=Succeeded,spec.nodeName=$Node" -A -o json }.Ast.EndBlock.Statements[0].PipelineElements[0].CommandElements | fl``` – mclayton Mar 27 '23 at 13:06
  • It looks fine in echoargs, unless the nodeName needs literal quotes. – js2010 Mar 27 '23 at 13:23

1 Answers1

2

tl;dr

Wrap the --field-selector argument value in double quotes and it should work - i.e.

$pods = (kubectl get pods --field-selector "status.phase!=Succeeded,spec.nodeName=$Node" -A -o json | ConvertFrom-Json).items
#                                          ^                                           ^

Long Version

So from doing a bit of testing, it looks like your assessment is correct - the comma in --field-selector status.phase!=Succeeded,spec.nodeName=$Node is the issue, or at least it's partly the issue...

What's happening is PowerShell is parsing the argument value as an array, which is fine, but it's not then performing variable expansion, which is surprising (to me at least).

The actual command being invoked is literally:

$Node = "mynode000001";
kubectl get pods --field-selector status.phase!=Succeeded,spec.nodeName=$Node -A -o json

as if you'd typed exactly that into a command prompt yourself - e.g.

C:\> kubectl get pods --field-selector status.phase!=Succeeded,spec.nodeName=$Node -A -o json
#                                                                            ^^^^^ :-(

If you quote the argument value it behaves differently:

$Node = "mynode000001";
kubectl get pods --field-selector "status.phase!=Succeeded,spec.nodeName=$Node" -A -o json

is the same as:

C:\> kubectl get pods --field-selector "status.phase!=Succeeded,spec.nodeName=mynode000001" -A -o json
#                                                                             ^^^^^^^^^^^^ :-)

You can see the difference if you examine the AST generated by the parser:

{ kubectl get pods --field-selector status.phase!=Succeeded,spec.nodeName=$Node -A -o json }.Ast.EndBlock.Statements[0].PipelineElements[0].CommandElements

... snip ...

# System.Object[]
Elements   : {status.phase!=Succeeded, spec.nodeName=$Node}
StaticType : System.Object[]
Extent     : status.phase!=Succeeded,spec.nodeName=$Node
Parent     : kubectl get pods --field-selector status.phase!=Succeeded,spec.nodeName=$Node -A -o json

... snip ...

versus

{ kubectl get pods --field-selector "status.phase!=Succeeded,spec.nodeName=$Node" -A -o json }.Ast.EndBlock.Statements[0].PipelineElements[0].CommandElements[4] | fl *

... snip ...

# DoubleQuoted
Value              : status.phase!=Succeeded,spec.nodeName=$Node
StringConstantType : DoubleQuoted
NestedExpressions  : {$Node}
StaticType         : System.String
Extent             : "status.phase!=Succeeded,spec.nodeName=$Node"
Parent             : kubectl get pods --field-selector "status.phase!=Succeeded,spec.nodeName=$Node" -A -o json

... snip ...

The DoubleQuoted string has variable expansion applied, but the elements in the System.Object[] do not, it seems.

Digging further, it looks like the $Node expression is being identified in the unquoted argument value, but it's being parsed into a BareWord which doesn't get expanded...

 { kubectl get pods --field-selector status.phase!=Succeeded,spec.nodeName=$Node -A -o json }.Ast.EndBlock.Statements[0].PipelineElements[0].CommandElements[4].Elements[1] | fl *

# BareWord
Value              : spec.nodeName=$Node
StringConstantType : BareWord
NestedExpressions  : {$Node}
StaticType         : System.String
Extent             : spec.nodeName=$Node
Parent             : status.phase!=Succeeded,spec.nodeName=$Node

I don't know if that's by design or a bug, tbh, (probably the former at a guess) but quoting the argument value bypasses that whole question :-).

mclayton
  • 8,025
  • 2
  • 21
  • 26