Block Volume: cmdline printer update

pull/6/head
Mitsuhiro Tanino 2017-11-04 22:31:29 -04:00 committed by mtanino
parent 849d7f8595
commit 334a0f0620
2 changed files with 267 additions and 56 deletions

View File

@ -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, "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]
w.Write(LEVEL_0, "Capacity:\t%s\n", storage.String())
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, "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 {
DescribeEvents(events, w)
}
@ -1365,6 +1371,7 @@ func describeContainerProbe(container api.Container, w PrefixWriter) {
}
func describeContainerVolumes(container api.Container, w PrefixWriter) {
// Show volumeMounts
none := ""
if len(container.VolumeMounts) == 0 {
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, ","))
}
// 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) {
@ -3803,6 +3818,20 @@ func (list SortableVolumeMounts) Less(i, j int) bool {
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
func versionedExtensionsClientV1beta1(internalClient clientset.Interface) clientextensionsv1beta1.ExtensionsV1beta1Interface {
if internalClient == nil {

View File

@ -634,6 +634,50 @@ func TestDescribeContainers(t *testing.T) {
},
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 {
@ -815,99 +859,237 @@ func TestGetPodsTotalRequests(t *testing.T) {
}
func TestPersistentVolumeDescriber(t *testing.T) {
tests := map[string]*api.PersistentVolume{
"hostpath": {
ObjectMeta: metav1.ObjectMeta{Name: "bar"},
Spec: api.PersistentVolumeSpec{
PersistentVolumeSource: api.PersistentVolumeSource{
HostPath: &api.HostPathVolumeSource{Type: new(api.HostPathType)},
block := api.PersistentVolumeBlock
file := api.PersistentVolumeFilesystem
testCases := []struct {
plugin string
pv *api.PersistentVolume
expectedElements []string
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"},
Spec: api.PersistentVolumeSpec{
PersistentVolumeSource: api.PersistentVolumeSource{
GCEPersistentDisk: &api.GCEPersistentDiskVolumeSource{},
{
plugin: "gce",
pv: &api.PersistentVolume{
ObjectMeta: metav1.ObjectMeta{Name: "bar"},
Spec: api.PersistentVolumeSpec{
PersistentVolumeSource: api.PersistentVolumeSource{
GCEPersistentDisk: &api.GCEPersistentDiskVolumeSource{},
},
VolumeMode: &file,
},
},
expectedElements: []string{"VolumeMode", "Filesystem"},
},
"ebs": {
ObjectMeta: metav1.ObjectMeta{Name: "bar"},
Spec: api.PersistentVolumeSpec{
PersistentVolumeSource: api.PersistentVolumeSource{
AWSElasticBlockStore: &api.AWSElasticBlockStoreVolumeSource{},
{
plugin: "ebs",
pv: &api.PersistentVolume{
ObjectMeta: metav1.ObjectMeta{Name: "bar"},
Spec: api.PersistentVolumeSpec{
PersistentVolumeSource: api.PersistentVolumeSource{
AWSElasticBlockStore: &api.AWSElasticBlockStoreVolumeSource{},
},
},
},
unexpectedElements: []string{"VolumeMode", "Filesystem"},
},
"nfs": {
ObjectMeta: metav1.ObjectMeta{Name: "bar"},
Spec: api.PersistentVolumeSpec{
PersistentVolumeSource: api.PersistentVolumeSource{
NFS: &api.NFSVolumeSource{},
{
plugin: "nfs",
pv: &api.PersistentVolume{
ObjectMeta: metav1.ObjectMeta{Name: "bar"},
Spec: api.PersistentVolumeSpec{
PersistentVolumeSource: api.PersistentVolumeSource{
NFS: &api.NFSVolumeSource{},
},
},
},
unexpectedElements: []string{"VolumeMode", "Filesystem"},
},
"iscsi": {
ObjectMeta: metav1.ObjectMeta{Name: "bar"},
Spec: api.PersistentVolumeSpec{
PersistentVolumeSource: api.PersistentVolumeSource{
ISCSI: &api.ISCSIPersistentVolumeSource{},
{
plugin: "iscsi",
pv: &api.PersistentVolume{
ObjectMeta: metav1.ObjectMeta{Name: "bar"},
Spec: api.PersistentVolumeSpec{
PersistentVolumeSource: api.PersistentVolumeSource{
ISCSI: &api.ISCSIPersistentVolumeSource{},
},
VolumeMode: &block,
},
},
expectedElements: []string{"VolumeMode", "Block"},
},
"gluster": {
ObjectMeta: metav1.ObjectMeta{Name: "bar"},
Spec: api.PersistentVolumeSpec{
PersistentVolumeSource: api.PersistentVolumeSource{
Glusterfs: &api.GlusterfsVolumeSource{},
{
plugin: "gluster",
pv: &api.PersistentVolume{
ObjectMeta: metav1.ObjectMeta{Name: "bar"},
Spec: api.PersistentVolumeSpec{
PersistentVolumeSource: api.PersistentVolumeSource{
Glusterfs: &api.GlusterfsVolumeSource{},
},
},
},
unexpectedElements: []string{"VolumeMode", "Filesystem"},
},
"rbd": {
ObjectMeta: metav1.ObjectMeta{Name: "bar"},
Spec: api.PersistentVolumeSpec{
PersistentVolumeSource: api.PersistentVolumeSource{
RBD: &api.RBDPersistentVolumeSource{},
{
plugin: "rbd",
pv: &api.PersistentVolume{
ObjectMeta: metav1.ObjectMeta{Name: "bar"},
Spec: api.PersistentVolumeSpec{
PersistentVolumeSource: api.PersistentVolumeSource{
RBD: &api.RBDPersistentVolumeSource{},
},
},
},
unexpectedElements: []string{"VolumeMode", "Filesystem"},
},
"quobyte": {
ObjectMeta: metav1.ObjectMeta{Name: "bar"},
Spec: api.PersistentVolumeSpec{
PersistentVolumeSource: api.PersistentVolumeSource{
Quobyte: &api.QuobyteVolumeSource{},
{
plugin: "quobyte",
pv: &api.PersistentVolume{
ObjectMeta: metav1.ObjectMeta{Name: "bar"},
Spec: api.PersistentVolumeSpec{
PersistentVolumeSource: api.PersistentVolumeSource{
Quobyte: &api.QuobyteVolumeSource{},
},
},
},
unexpectedElements: []string{"VolumeMode", "Filesystem"},
},
"cinder": {
ObjectMeta: metav1.ObjectMeta{Name: "bar"},
Spec: api.PersistentVolumeSpec{
PersistentVolumeSource: api.PersistentVolumeSource{
Cinder: &api.CinderVolumeSource{},
{
plugin: "cinder",
pv: &api.PersistentVolume{
ObjectMeta: metav1.ObjectMeta{Name: "bar"},
Spec: api.PersistentVolumeSpec{
PersistentVolumeSource: api.PersistentVolumeSource{
Cinder: &api.CinderVolumeSource{},
},
},
},
unexpectedElements: []string{"VolumeMode", "Filesystem"},
},
"fc": {
ObjectMeta: metav1.ObjectMeta{Name: "bar"},
Spec: api.PersistentVolumeSpec{
PersistentVolumeSource: api.PersistentVolumeSource{
FC: &api.FCVolumeSource{},
{
plugin: "fc",
pv: &api.PersistentVolume{
ObjectMeta: metav1.ObjectMeta{Name: "bar"},
Spec: api.PersistentVolumeSpec{
PersistentVolumeSource: api.PersistentVolumeSource{
FC: &api.FCVolumeSource{},
},
VolumeMode: &block,
},
},
expectedElements: []string{"VolumeMode", "Block"},
},
}
for name, pv := range tests {
fake := fake.NewSimpleClientset(pv)
for _, test := range testCases {
fake := fake.NewSimpleClientset(test.pv)
c := PersistentVolumeDescriber{fake}
str, err := c.Describe("foo", "bar", printers.DescriberSettings{ShowEvents: true})
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 == "" {
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)
}
}
}
}