Unverified Commit 5f3c3647 authored by Kubernetes Submit Queue's avatar Kubernetes Submit Queue Committed by GitHub

Merge pull request #60157 from msau42/topology-beta

Automatic merge from submit-queue. If you want to cherry-pick this change to another branch, please follow the instructions <a href="https://github.com/kubernetes/community/blob/master/contributors/devel/cherry-picks.md">here</a>. Update kubectl describe to print out PV node affinity **What this PR does / why we need it**: Print out PV NodeAffinity in kubectl describe. Sample output: ``` Name: example-local-pv Labels: foo1=bar1 foo2=bar2 Annotations: <none> Finalizers: [] StorageClass: local-storage Status: Available Claim: Reclaim Policy: Delete Access Modes: RWO Capacity: 5Gi Node Affinity: Required Terms: Term 0: kubernetes.io/hostname in [my-node] foo1 in [bar1, bar2] Term 1: foo2 exists Message: Source: Type: LocalVolume (a persistent volume backed by local storage on a node) Path: /mnt/disks/ssd1 Events: <none> ``` No NodeAffinity is set: ``` Name: nfs Labels: <none> Annotations: <none> Finalizers: [] StorageClass: Status: Available Claim: Reclaim Policy: Retain Access Modes: RWX Capacity: 1Mi Node Affinity: <none> Message: Source: Type: NFS (an NFS mount that lasts the lifetime of a pod) Server: 10.244.1.4 Path: /exports ReadOnly: false Events: <none> ``` **Which issue(s) this PR fixes** *(optional, in `fixes #<issue number>(, fixes #<issue_number>, ...)` format, will close the issue(s) when PR gets merged)*: Fixes #60119 **Special notes for your reviewer**: **Release note**: ```release-note NONE ```
parents 744b5d33 61417bd9
......@@ -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")
......
......@@ -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 {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment