Update kubectl describe to print out PV node affinity

This commit is contained in:
Michelle Au 2018-02-21 10:10:42 -08:00
parent a6a225623b
commit 61417bd9ff
2 changed files with 143 additions and 0 deletions

View File

@ -1134,6 +1134,48 @@ func (d *PersistentVolumeDescriber) Describe(namespace, name string, describerSe
return describePersistentVolume(pv, events)
}
func printVolumeNodeAffinity(w PrefixWriter, affinity *api.VolumeNodeAffinity) {
w.Write(LEVEL_0, "Node Affinity:\t")
if affinity == nil || affinity.Required == nil {
w.WriteLine("<none>")
return
}
w.WriteLine("")
if affinity.Required != nil {
w.Write(LEVEL_1, "Required Terms:\t")
if len(affinity.Required.NodeSelectorTerms) == 0 {
w.WriteLine("<none>")
} else {
w.WriteLine("")
for i, term := range affinity.Required.NodeSelectorTerms {
printNodeSelectorTermsMultilineWithIndent(w, LEVEL_2, fmt.Sprintf("Term %v", i), "\t", term.MatchExpressions)
}
}
}
}
// printLabelsMultiline prints multiple labels with a user-defined alignment.
func printNodeSelectorTermsMultilineWithIndent(w PrefixWriter, indentLevel int, title, innerIndent string, reqs []api.NodeSelectorRequirement) {
w.Write(indentLevel, "%s:%s", title, innerIndent)
if len(reqs) == 0 {
w.WriteLine("<none>")
return
}
for i, req := range reqs {
if i != 0 {
w.Write(indentLevel, "%s", innerIndent)
}
exprStr := fmt.Sprintf("%s %s", req.Key, strings.ToLower(string(req.Operator)))
if len(req.Values) > 0 {
exprStr = fmt.Sprintf("%s [%s]", exprStr, strings.Join(req.Values, ", "))
}
w.Write(LEVEL_0, "%s\n", exprStr)
}
}
func describePersistentVolume(pv *api.PersistentVolume, events *api.EventList) (string, error) {
return tabbedString(func(out io.Writer) error {
w := NewPrefixWriter(out)
@ -1159,6 +1201,7 @@ func describePersistentVolume(pv *api.PersistentVolume, events *api.EventList) (
}
storage := pv.Spec.Capacity[api.ResourceStorage]
w.Write(LEVEL_0, "Capacity:\t%s\n", storage.String())
printVolumeNodeAffinity(w, pv.Spec.NodeAffinity)
w.Write(LEVEL_0, "Message:\t%s\n", pv.Status.Message)
w.Write(LEVEL_0, "Source:\n")

View File

@ -991,6 +991,106 @@ func TestPersistentVolumeDescriber(t *testing.T) {
},
expectedElements: []string{"VolumeMode", "Block"},
},
{
plugin: "local",
pv: &api.PersistentVolume{
ObjectMeta: metav1.ObjectMeta{Name: "bar"},
Spec: api.PersistentVolumeSpec{
PersistentVolumeSource: api.PersistentVolumeSource{
Local: &api.LocalVolumeSource{},
},
},
},
expectedElements: []string{"Node Affinity: <none>"},
unexpectedElements: []string{"Required Terms", "Term "},
},
{
plugin: "local",
pv: &api.PersistentVolume{
ObjectMeta: metav1.ObjectMeta{Name: "bar"},
Spec: api.PersistentVolumeSpec{
PersistentVolumeSource: api.PersistentVolumeSource{
Local: &api.LocalVolumeSource{},
},
NodeAffinity: &api.VolumeNodeAffinity{},
},
},
expectedElements: []string{"Node Affinity: <none>"},
unexpectedElements: []string{"Required Terms", "Term "},
},
{
plugin: "local",
pv: &api.PersistentVolume{
ObjectMeta: metav1.ObjectMeta{Name: "bar"},
Spec: api.PersistentVolumeSpec{
PersistentVolumeSource: api.PersistentVolumeSource{
Local: &api.LocalVolumeSource{},
},
NodeAffinity: &api.VolumeNodeAffinity{
Required: &api.NodeSelector{},
},
},
},
expectedElements: []string{"Node Affinity", "Required Terms: <none>"},
unexpectedElements: []string{"Term "},
},
{
plugin: "local",
pv: &api.PersistentVolume{
ObjectMeta: metav1.ObjectMeta{Name: "bar"},
Spec: api.PersistentVolumeSpec{
PersistentVolumeSource: api.PersistentVolumeSource{
Local: &api.LocalVolumeSource{},
},
NodeAffinity: &api.VolumeNodeAffinity{
Required: &api.NodeSelector{
NodeSelectorTerms: []api.NodeSelectorTerm{
{
MatchExpressions: []api.NodeSelectorRequirement{},
},
{
MatchExpressions: []api.NodeSelectorRequirement{},
},
},
},
},
},
},
expectedElements: []string{"Node Affinity", "Required Terms", "Term 0", "Term 1"},
},
{
plugin: "local",
pv: &api.PersistentVolume{
ObjectMeta: metav1.ObjectMeta{Name: "bar"},
Spec: api.PersistentVolumeSpec{
PersistentVolumeSource: api.PersistentVolumeSource{
Local: &api.LocalVolumeSource{},
},
NodeAffinity: &api.VolumeNodeAffinity{
Required: &api.NodeSelector{
NodeSelectorTerms: []api.NodeSelectorTerm{
{
MatchExpressions: []api.NodeSelectorRequirement{
{
Key: "foo",
Operator: "In",
Values: []string{"val1", "val2"},
},
{
Key: "foo",
Operator: "Exists",
},
},
},
},
},
},
},
},
expectedElements: []string{"Node Affinity", "Required Terms", "Term 0",
"foo in [val1, val2]",
"foo exists"},
},
}
for _, test := range testCases {