mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-02 08:17:26 +00:00
Block Volume: cmdline printer update
This commit is contained in:
parent
849d7f8595
commit
334a0f0620
@ -1136,6 +1136,9 @@ func describePersistentVolume(pv *api.PersistentVolume, events *api.EventList) (
|
|||||||
}
|
}
|
||||||
w.Write(LEVEL_0, "Reclaim Policy:\t%v\n", pv.Spec.PersistentVolumeReclaimPolicy)
|
w.Write(LEVEL_0, "Reclaim Policy:\t%v\n", pv.Spec.PersistentVolumeReclaimPolicy)
|
||||||
w.Write(LEVEL_0, "Access Modes:\t%s\n", helper.GetAccessModesAsString(pv.Spec.AccessModes))
|
w.Write(LEVEL_0, "Access Modes:\t%s\n", helper.GetAccessModesAsString(pv.Spec.AccessModes))
|
||||||
|
if pv.Spec.VolumeMode != nil {
|
||||||
|
w.Write(LEVEL_0, "VolumeMode:\t%v\n", *pv.Spec.VolumeMode)
|
||||||
|
}
|
||||||
storage := pv.Spec.Capacity[api.ResourceStorage]
|
storage := pv.Spec.Capacity[api.ResourceStorage]
|
||||||
w.Write(LEVEL_0, "Capacity:\t%s\n", storage.String())
|
w.Write(LEVEL_0, "Capacity:\t%s\n", storage.String())
|
||||||
w.Write(LEVEL_0, "Message:\t%s\n", pv.Status.Message)
|
w.Write(LEVEL_0, "Message:\t%s\n", pv.Status.Message)
|
||||||
@ -1235,6 +1238,9 @@ func describePersistentVolumeClaim(pvc *api.PersistentVolumeClaim, events *api.E
|
|||||||
}
|
}
|
||||||
w.Write(LEVEL_0, "Capacity:\t%s\n", capacity)
|
w.Write(LEVEL_0, "Capacity:\t%s\n", capacity)
|
||||||
w.Write(LEVEL_0, "Access Modes:\t%s\n", accessModes)
|
w.Write(LEVEL_0, "Access Modes:\t%s\n", accessModes)
|
||||||
|
if pvc.Spec.VolumeMode != nil {
|
||||||
|
w.Write(LEVEL_0, "VolumeMode:\t%v\n", *pvc.Spec.VolumeMode)
|
||||||
|
}
|
||||||
if events != nil {
|
if events != nil {
|
||||||
DescribeEvents(events, w)
|
DescribeEvents(events, w)
|
||||||
}
|
}
|
||||||
@ -1365,6 +1371,7 @@ func describeContainerProbe(container api.Container, w PrefixWriter) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func describeContainerVolumes(container api.Container, w PrefixWriter) {
|
func describeContainerVolumes(container api.Container, w PrefixWriter) {
|
||||||
|
// Show volumeMounts
|
||||||
none := ""
|
none := ""
|
||||||
if len(container.VolumeMounts) == 0 {
|
if len(container.VolumeMounts) == 0 {
|
||||||
none = "\t<none>"
|
none = "\t<none>"
|
||||||
@ -1383,6 +1390,14 @@ func describeContainerVolumes(container api.Container, w PrefixWriter) {
|
|||||||
}
|
}
|
||||||
w.Write(LEVEL_3, "%s from %s (%s)\n", mount.MountPath, mount.Name, strings.Join(flags, ","))
|
w.Write(LEVEL_3, "%s from %s (%s)\n", mount.MountPath, mount.Name, strings.Join(flags, ","))
|
||||||
}
|
}
|
||||||
|
// Show volumeDevices if exists
|
||||||
|
if len(container.VolumeDevices) > 0 {
|
||||||
|
w.Write(LEVEL_2, "Devices:%s\n", none)
|
||||||
|
sort.Sort(SortableVolumeDevices(container.VolumeDevices))
|
||||||
|
for _, device := range container.VolumeDevices {
|
||||||
|
w.Write(LEVEL_3, "%s from %s\n", device.DevicePath, device.Name)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func describeContainerEnvVars(container api.Container, resolverFn EnvVarResolverFunc, w PrefixWriter) {
|
func describeContainerEnvVars(container api.Container, resolverFn EnvVarResolverFunc, w PrefixWriter) {
|
||||||
@ -3803,6 +3818,20 @@ func (list SortableVolumeMounts) Less(i, j int) bool {
|
|||||||
return list[i].MountPath < list[j].MountPath
|
return list[i].MountPath < list[j].MountPath
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type SortableVolumeDevices []api.VolumeDevice
|
||||||
|
|
||||||
|
func (list SortableVolumeDevices) Len() int {
|
||||||
|
return len(list)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (list SortableVolumeDevices) Swap(i, j int) {
|
||||||
|
list[i], list[j] = list[j], list[i]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (list SortableVolumeDevices) Less(i, j int) bool {
|
||||||
|
return list[i].DevicePath < list[j].DevicePath
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: get rid of this and plumb the caller correctly
|
// TODO: get rid of this and plumb the caller correctly
|
||||||
func versionedExtensionsClientV1beta1(internalClient clientset.Interface) clientextensionsv1beta1.ExtensionsV1beta1Interface {
|
func versionedExtensionsClientV1beta1(internalClient clientset.Interface) clientextensionsv1beta1.ExtensionsV1beta1Interface {
|
||||||
if internalClient == nil {
|
if internalClient == nil {
|
||||||
|
@ -634,6 +634,50 @@ func TestDescribeContainers(t *testing.T) {
|
|||||||
},
|
},
|
||||||
expectedElements: []string{"cpu", "1k", "memory", "4G", "storage", "20G"},
|
expectedElements: []string{"cpu", "1k", "memory", "4G", "storage", "20G"},
|
||||||
},
|
},
|
||||||
|
// volumeMounts read/write
|
||||||
|
{
|
||||||
|
container: api.Container{
|
||||||
|
Name: "test",
|
||||||
|
Image: "image",
|
||||||
|
VolumeMounts: []api.VolumeMount{
|
||||||
|
{
|
||||||
|
Name: "mounted-volume",
|
||||||
|
MountPath: "/opt/",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedElements: []string{"mounted-volume", "/opt/", "(rw)"},
|
||||||
|
},
|
||||||
|
// volumeMounts readonly
|
||||||
|
{
|
||||||
|
container: api.Container{
|
||||||
|
Name: "test",
|
||||||
|
Image: "image",
|
||||||
|
VolumeMounts: []api.VolumeMount{
|
||||||
|
{
|
||||||
|
Name: "mounted-volume",
|
||||||
|
MountPath: "/opt/",
|
||||||
|
ReadOnly: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedElements: []string{"Mounts", "mounted-volume", "/opt/", "(ro)"},
|
||||||
|
},
|
||||||
|
|
||||||
|
// volumeDevices
|
||||||
|
{
|
||||||
|
container: api.Container{
|
||||||
|
Name: "test",
|
||||||
|
Image: "image",
|
||||||
|
VolumeDevices: []api.VolumeDevice{
|
||||||
|
{
|
||||||
|
Name: "volume-device",
|
||||||
|
DevicePath: "/dev/xvda",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedElements: []string{"Devices", "volume-device", "/dev/xvda"},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, testCase := range testCases {
|
for i, testCase := range testCases {
|
||||||
@ -815,99 +859,237 @@ func TestGetPodsTotalRequests(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestPersistentVolumeDescriber(t *testing.T) {
|
func TestPersistentVolumeDescriber(t *testing.T) {
|
||||||
tests := map[string]*api.PersistentVolume{
|
block := api.PersistentVolumeBlock
|
||||||
|
file := api.PersistentVolumeFilesystem
|
||||||
"hostpath": {
|
testCases := []struct {
|
||||||
ObjectMeta: metav1.ObjectMeta{Name: "bar"},
|
plugin string
|
||||||
Spec: api.PersistentVolumeSpec{
|
pv *api.PersistentVolume
|
||||||
PersistentVolumeSource: api.PersistentVolumeSource{
|
expectedElements []string
|
||||||
HostPath: &api.HostPathVolumeSource{Type: new(api.HostPathType)},
|
unexpectedElements []string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
plugin: "hostpath",
|
||||||
|
pv: &api.PersistentVolume{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{Name: "bar"},
|
||||||
|
Spec: api.PersistentVolumeSpec{
|
||||||
|
PersistentVolumeSource: api.PersistentVolumeSource{
|
||||||
|
HostPath: &api.HostPathVolumeSource{Type: new(api.HostPathType)},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
unexpectedElements: []string{"VolumeMode", "Filesystem"},
|
||||||
},
|
},
|
||||||
"gce": {
|
{
|
||||||
ObjectMeta: metav1.ObjectMeta{Name: "bar"},
|
plugin: "gce",
|
||||||
Spec: api.PersistentVolumeSpec{
|
pv: &api.PersistentVolume{
|
||||||
PersistentVolumeSource: api.PersistentVolumeSource{
|
ObjectMeta: metav1.ObjectMeta{Name: "bar"},
|
||||||
GCEPersistentDisk: &api.GCEPersistentDiskVolumeSource{},
|
Spec: api.PersistentVolumeSpec{
|
||||||
|
PersistentVolumeSource: api.PersistentVolumeSource{
|
||||||
|
GCEPersistentDisk: &api.GCEPersistentDiskVolumeSource{},
|
||||||
|
},
|
||||||
|
VolumeMode: &file,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
expectedElements: []string{"VolumeMode", "Filesystem"},
|
||||||
},
|
},
|
||||||
"ebs": {
|
{
|
||||||
ObjectMeta: metav1.ObjectMeta{Name: "bar"},
|
plugin: "ebs",
|
||||||
Spec: api.PersistentVolumeSpec{
|
pv: &api.PersistentVolume{
|
||||||
PersistentVolumeSource: api.PersistentVolumeSource{
|
ObjectMeta: metav1.ObjectMeta{Name: "bar"},
|
||||||
AWSElasticBlockStore: &api.AWSElasticBlockStoreVolumeSource{},
|
Spec: api.PersistentVolumeSpec{
|
||||||
|
PersistentVolumeSource: api.PersistentVolumeSource{
|
||||||
|
AWSElasticBlockStore: &api.AWSElasticBlockStoreVolumeSource{},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
unexpectedElements: []string{"VolumeMode", "Filesystem"},
|
||||||
},
|
},
|
||||||
"nfs": {
|
{
|
||||||
ObjectMeta: metav1.ObjectMeta{Name: "bar"},
|
plugin: "nfs",
|
||||||
Spec: api.PersistentVolumeSpec{
|
pv: &api.PersistentVolume{
|
||||||
PersistentVolumeSource: api.PersistentVolumeSource{
|
ObjectMeta: metav1.ObjectMeta{Name: "bar"},
|
||||||
NFS: &api.NFSVolumeSource{},
|
Spec: api.PersistentVolumeSpec{
|
||||||
|
PersistentVolumeSource: api.PersistentVolumeSource{
|
||||||
|
NFS: &api.NFSVolumeSource{},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
unexpectedElements: []string{"VolumeMode", "Filesystem"},
|
||||||
},
|
},
|
||||||
"iscsi": {
|
{
|
||||||
ObjectMeta: metav1.ObjectMeta{Name: "bar"},
|
plugin: "iscsi",
|
||||||
Spec: api.PersistentVolumeSpec{
|
pv: &api.PersistentVolume{
|
||||||
PersistentVolumeSource: api.PersistentVolumeSource{
|
ObjectMeta: metav1.ObjectMeta{Name: "bar"},
|
||||||
ISCSI: &api.ISCSIPersistentVolumeSource{},
|
Spec: api.PersistentVolumeSpec{
|
||||||
|
PersistentVolumeSource: api.PersistentVolumeSource{
|
||||||
|
ISCSI: &api.ISCSIPersistentVolumeSource{},
|
||||||
|
},
|
||||||
|
VolumeMode: &block,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
expectedElements: []string{"VolumeMode", "Block"},
|
||||||
},
|
},
|
||||||
"gluster": {
|
{
|
||||||
ObjectMeta: metav1.ObjectMeta{Name: "bar"},
|
plugin: "gluster",
|
||||||
Spec: api.PersistentVolumeSpec{
|
pv: &api.PersistentVolume{
|
||||||
PersistentVolumeSource: api.PersistentVolumeSource{
|
ObjectMeta: metav1.ObjectMeta{Name: "bar"},
|
||||||
Glusterfs: &api.GlusterfsVolumeSource{},
|
Spec: api.PersistentVolumeSpec{
|
||||||
|
PersistentVolumeSource: api.PersistentVolumeSource{
|
||||||
|
Glusterfs: &api.GlusterfsVolumeSource{},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
unexpectedElements: []string{"VolumeMode", "Filesystem"},
|
||||||
},
|
},
|
||||||
"rbd": {
|
{
|
||||||
ObjectMeta: metav1.ObjectMeta{Name: "bar"},
|
plugin: "rbd",
|
||||||
Spec: api.PersistentVolumeSpec{
|
pv: &api.PersistentVolume{
|
||||||
PersistentVolumeSource: api.PersistentVolumeSource{
|
ObjectMeta: metav1.ObjectMeta{Name: "bar"},
|
||||||
RBD: &api.RBDPersistentVolumeSource{},
|
Spec: api.PersistentVolumeSpec{
|
||||||
|
PersistentVolumeSource: api.PersistentVolumeSource{
|
||||||
|
RBD: &api.RBDPersistentVolumeSource{},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
unexpectedElements: []string{"VolumeMode", "Filesystem"},
|
||||||
},
|
},
|
||||||
"quobyte": {
|
{
|
||||||
ObjectMeta: metav1.ObjectMeta{Name: "bar"},
|
plugin: "quobyte",
|
||||||
Spec: api.PersistentVolumeSpec{
|
pv: &api.PersistentVolume{
|
||||||
PersistentVolumeSource: api.PersistentVolumeSource{
|
ObjectMeta: metav1.ObjectMeta{Name: "bar"},
|
||||||
Quobyte: &api.QuobyteVolumeSource{},
|
Spec: api.PersistentVolumeSpec{
|
||||||
|
PersistentVolumeSource: api.PersistentVolumeSource{
|
||||||
|
Quobyte: &api.QuobyteVolumeSource{},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
unexpectedElements: []string{"VolumeMode", "Filesystem"},
|
||||||
},
|
},
|
||||||
"cinder": {
|
{
|
||||||
ObjectMeta: metav1.ObjectMeta{Name: "bar"},
|
plugin: "cinder",
|
||||||
Spec: api.PersistentVolumeSpec{
|
pv: &api.PersistentVolume{
|
||||||
PersistentVolumeSource: api.PersistentVolumeSource{
|
ObjectMeta: metav1.ObjectMeta{Name: "bar"},
|
||||||
Cinder: &api.CinderVolumeSource{},
|
Spec: api.PersistentVolumeSpec{
|
||||||
|
PersistentVolumeSource: api.PersistentVolumeSource{
|
||||||
|
Cinder: &api.CinderVolumeSource{},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
unexpectedElements: []string{"VolumeMode", "Filesystem"},
|
||||||
},
|
},
|
||||||
"fc": {
|
{
|
||||||
ObjectMeta: metav1.ObjectMeta{Name: "bar"},
|
plugin: "fc",
|
||||||
Spec: api.PersistentVolumeSpec{
|
pv: &api.PersistentVolume{
|
||||||
PersistentVolumeSource: api.PersistentVolumeSource{
|
ObjectMeta: metav1.ObjectMeta{Name: "bar"},
|
||||||
FC: &api.FCVolumeSource{},
|
Spec: api.PersistentVolumeSpec{
|
||||||
|
PersistentVolumeSource: api.PersistentVolumeSource{
|
||||||
|
FC: &api.FCVolumeSource{},
|
||||||
|
},
|
||||||
|
VolumeMode: &block,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
expectedElements: []string{"VolumeMode", "Block"},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for name, pv := range tests {
|
for _, test := range testCases {
|
||||||
fake := fake.NewSimpleClientset(pv)
|
fake := fake.NewSimpleClientset(test.pv)
|
||||||
c := PersistentVolumeDescriber{fake}
|
c := PersistentVolumeDescriber{fake}
|
||||||
str, err := c.Describe("foo", "bar", printers.DescriberSettings{ShowEvents: true})
|
str, err := c.Describe("foo", "bar", printers.DescriberSettings{ShowEvents: true})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Unexpected error for test %s: %v", name, err)
|
t.Errorf("Unexpected error for test %s: %v", test.plugin, err)
|
||||||
}
|
}
|
||||||
if str == "" {
|
if str == "" {
|
||||||
t.Errorf("Unexpected empty string for test %s. Expected PV Describer output", name)
|
t.Errorf("Unexpected empty string for test %s. Expected PV Describer output", test.plugin)
|
||||||
|
}
|
||||||
|
for _, expected := range test.expectedElements {
|
||||||
|
if !strings.Contains(str, expected) {
|
||||||
|
t.Errorf("expected to find %q in output: %q", expected, str)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, unexpected := range test.unexpectedElements {
|
||||||
|
if strings.Contains(str, unexpected) {
|
||||||
|
t.Errorf("unexpected to find %q in output: %q", unexpected, str)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPersistentVolumeClaimDescriber(t *testing.T) {
|
||||||
|
block := api.PersistentVolumeBlock
|
||||||
|
file := api.PersistentVolumeFilesystem
|
||||||
|
goldClassName := "gold"
|
||||||
|
testCases := []struct {
|
||||||
|
name string
|
||||||
|
pvc *api.PersistentVolumeClaim
|
||||||
|
expectedElements []string
|
||||||
|
unexpectedElements []string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "default",
|
||||||
|
pvc: &api.PersistentVolumeClaim{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{Namespace: "foo", Name: "bar"},
|
||||||
|
Spec: api.PersistentVolumeClaimSpec{
|
||||||
|
VolumeName: "volume1",
|
||||||
|
StorageClassName: &goldClassName,
|
||||||
|
},
|
||||||
|
Status: api.PersistentVolumeClaimStatus{
|
||||||
|
Phase: api.ClaimBound,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
unexpectedElements: []string{"VolumeMode", "Filesystem"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "filesystem",
|
||||||
|
pvc: &api.PersistentVolumeClaim{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{Namespace: "foo", Name: "bar"},
|
||||||
|
Spec: api.PersistentVolumeClaimSpec{
|
||||||
|
VolumeName: "volume2",
|
||||||
|
StorageClassName: &goldClassName,
|
||||||
|
VolumeMode: &file,
|
||||||
|
},
|
||||||
|
Status: api.PersistentVolumeClaimStatus{
|
||||||
|
Phase: api.ClaimBound,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedElements: []string{"VolumeMode", "Filesystem"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "block",
|
||||||
|
pvc: &api.PersistentVolumeClaim{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{Namespace: "foo", Name: "bar"},
|
||||||
|
Spec: api.PersistentVolumeClaimSpec{
|
||||||
|
VolumeName: "volume3",
|
||||||
|
StorageClassName: &goldClassName,
|
||||||
|
VolumeMode: &block,
|
||||||
|
},
|
||||||
|
Status: api.PersistentVolumeClaimStatus{
|
||||||
|
Phase: api.ClaimBound,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedElements: []string{"VolumeMode", "Block"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range testCases {
|
||||||
|
fake := fake.NewSimpleClientset(test.pvc)
|
||||||
|
c := PersistentVolumeClaimDescriber{fake}
|
||||||
|
str, err := c.Describe("foo", "bar", printers.DescriberSettings{ShowEvents: true})
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Unexpected error for test %s: %v", test.name, err)
|
||||||
|
}
|
||||||
|
if str == "" {
|
||||||
|
t.Errorf("Unexpected empty string for test %s. Expected PVC Describer output", test.name)
|
||||||
|
}
|
||||||
|
for _, expected := range test.expectedElements {
|
||||||
|
if !strings.Contains(str, expected) {
|
||||||
|
t.Errorf("expected to find %q in output: %q", expected, str)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, unexpected := range test.unexpectedElements {
|
||||||
|
if strings.Contains(str, unexpected) {
|
||||||
|
t.Errorf("unexpected to find %q in output: %q", unexpected, str)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user