...

Source file src/k8s.io/kubernetes/pkg/registry/storage/volumeattachment/strategy_test.go

Documentation: k8s.io/kubernetes/pkg/registry/storage/volumeattachment

     1  /*
     2  Copyright 2017 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package volumeattachment
    18  
    19  import (
    20  	"context"
    21  	"testing"
    22  
    23  	"github.com/google/go-cmp/cmp"
    24  	apiequality "k8s.io/apimachinery/pkg/api/equality"
    25  	"k8s.io/apimachinery/pkg/api/resource"
    26  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    27  	genericapirequest "k8s.io/apiserver/pkg/endpoints/request"
    28  	api "k8s.io/kubernetes/pkg/apis/core"
    29  	"k8s.io/kubernetes/pkg/apis/storage"
    30  )
    31  
    32  func getValidVolumeAttachment(name string) *storage.VolumeAttachment {
    33  	return &storage.VolumeAttachment{
    34  		ObjectMeta: metav1.ObjectMeta{
    35  			Name: name,
    36  		},
    37  		Spec: storage.VolumeAttachmentSpec{
    38  			Attacher: "valid-attacher",
    39  			Source: storage.VolumeAttachmentSource{
    40  				PersistentVolumeName: &name,
    41  			},
    42  			NodeName: "valid-node",
    43  		},
    44  	}
    45  }
    46  
    47  func getValidVolumeAttachmentWithInlineSpec(name string) *storage.VolumeAttachment {
    48  	volumeAttachment := getValidVolumeAttachment(name)
    49  	volumeAttachment.Spec.Source.PersistentVolumeName = nil
    50  	volumeAttachment.Spec.Source.InlineVolumeSpec = &api.PersistentVolumeSpec{
    51  		Capacity: api.ResourceList{
    52  			api.ResourceName(api.ResourceStorage): resource.MustParse("10"),
    53  		},
    54  		AccessModes: []api.PersistentVolumeAccessMode{api.ReadWriteOnce},
    55  		PersistentVolumeSource: api.PersistentVolumeSource{
    56  			CSI: &api.CSIPersistentVolumeSource{
    57  				Driver:       "com.test.foo",
    58  				VolumeHandle: name,
    59  			},
    60  		},
    61  		MountOptions: []string{"soft"},
    62  	}
    63  	return volumeAttachment
    64  }
    65  
    66  func TestVolumeAttachmentStrategy(t *testing.T) {
    67  	ctx := genericapirequest.WithRequestInfo(genericapirequest.NewContext(), &genericapirequest.RequestInfo{
    68  		APIGroup:   "storage.k8s.io",
    69  		APIVersion: "v1",
    70  		Resource:   "volumeattachments",
    71  	})
    72  	if Strategy.NamespaceScoped() {
    73  		t.Errorf("VolumeAttachment must not be namespace scoped")
    74  	}
    75  	if Strategy.AllowCreateOnUpdate() {
    76  		t.Errorf("VolumeAttachment should not allow create on update")
    77  	}
    78  
    79  	volumeAttachment := getValidVolumeAttachment("valid-attachment")
    80  
    81  	Strategy.PrepareForCreate(ctx, volumeAttachment)
    82  
    83  	errs := Strategy.Validate(ctx, volumeAttachment)
    84  	if len(errs) != 0 {
    85  		t.Errorf("unexpected error validating %v", errs)
    86  	}
    87  
    88  	// Create with status should drop status
    89  	statusVolumeAttachment := volumeAttachment.DeepCopy()
    90  	statusVolumeAttachment.Status = storage.VolumeAttachmentStatus{Attached: true}
    91  	Strategy.PrepareForCreate(ctx, statusVolumeAttachment)
    92  	if !apiequality.Semantic.DeepEqual(statusVolumeAttachment, volumeAttachment) {
    93  		t.Errorf("unexpected objects difference after creating with status: %v", cmp.Diff(statusVolumeAttachment, volumeAttachment))
    94  	}
    95  
    96  	// Update of spec is disallowed
    97  	newVolumeAttachment := volumeAttachment.DeepCopy()
    98  	newVolumeAttachment.Spec.NodeName = "valid-node-2"
    99  
   100  	Strategy.PrepareForUpdate(ctx, newVolumeAttachment, volumeAttachment)
   101  
   102  	errs = Strategy.ValidateUpdate(ctx, newVolumeAttachment, volumeAttachment)
   103  	if len(errs) == 0 {
   104  		t.Errorf("Expected a validation error")
   105  	}
   106  
   107  	// modifying status should be dropped
   108  	statusVolumeAttachment = volumeAttachment.DeepCopy()
   109  	statusVolumeAttachment.Status = storage.VolumeAttachmentStatus{Attached: true}
   110  
   111  	Strategy.PrepareForUpdate(ctx, statusVolumeAttachment, volumeAttachment)
   112  
   113  	if !apiequality.Semantic.DeepEqual(statusVolumeAttachment, volumeAttachment) {
   114  		t.Errorf("unexpected objects difference after modifying status: %v", cmp.Diff(statusVolumeAttachment, volumeAttachment))
   115  	}
   116  }
   117  
   118  func TestVolumeAttachmentStrategySourceInlineSpec(t *testing.T) {
   119  	ctx := genericapirequest.WithRequestInfo(genericapirequest.NewContext(), &genericapirequest.RequestInfo{
   120  		APIGroup:   "storage.k8s.io",
   121  		APIVersion: "v1",
   122  		Resource:   "volumeattachments",
   123  	})
   124  
   125  	volumeAttachment := getValidVolumeAttachmentWithInlineSpec("valid-attachment")
   126  	volumeAttachmentSaved := volumeAttachment.DeepCopy()
   127  	Strategy.PrepareForCreate(ctx, volumeAttachment)
   128  	if volumeAttachment.Spec.Source.InlineVolumeSpec == nil {
   129  		t.Errorf("InlineVolumeSpec unexpectedly set to nil during PrepareForCreate")
   130  	}
   131  	if !apiequality.Semantic.DeepEqual(volumeAttachmentSaved, volumeAttachment) {
   132  		t.Errorf("unexpected difference in object after creation: %v", cmp.Diff(volumeAttachment, volumeAttachmentSaved))
   133  	}
   134  	Strategy.PrepareForUpdate(ctx, volumeAttachmentSaved, volumeAttachment)
   135  	if volumeAttachmentSaved.Spec.Source.InlineVolumeSpec == nil {
   136  		t.Errorf("InlineVolumeSpec unexpectedly set to nil during PrepareForUpdate")
   137  	}
   138  	Strategy.PrepareForUpdate(ctx, volumeAttachmentSaved, volumeAttachment)
   139  	if volumeAttachmentSaved.Spec.Source.InlineVolumeSpec == nil {
   140  		t.Errorf("InlineVolumeSpec unexpectedly set to nil during PrepareForUpdate")
   141  	}
   142  }
   143  
   144  func TestVolumeAttachmentStatusStrategy(t *testing.T) {
   145  	ctx := genericapirequest.WithRequestInfo(genericapirequest.NewContext(), &genericapirequest.RequestInfo{
   146  		APIGroup:   "storage.k8s.io",
   147  		APIVersion: "v1",
   148  		Resource:   "volumeattachments",
   149  	})
   150  
   151  	volumeAttachment := getValidVolumeAttachment("valid-attachment")
   152  
   153  	// modifying status should be allowed
   154  	statusVolumeAttachment := volumeAttachment.DeepCopy()
   155  	statusVolumeAttachment.Status = storage.VolumeAttachmentStatus{Attached: true}
   156  
   157  	expectedVolumeAttachment := statusVolumeAttachment.DeepCopy()
   158  	StatusStrategy.PrepareForUpdate(ctx, statusVolumeAttachment, volumeAttachment)
   159  	if !apiequality.Semantic.DeepEqual(statusVolumeAttachment, expectedVolumeAttachment) {
   160  		t.Errorf("unexpected objects difference after modifying status: %v", cmp.Diff(statusVolumeAttachment, expectedVolumeAttachment))
   161  	}
   162  
   163  	// spec and metadata modifications should be dropped
   164  	newVolumeAttachment := volumeAttachment.DeepCopy()
   165  	newVolumeAttachment.Spec.NodeName = "valid-node-2"
   166  	newVolumeAttachment.Labels = map[string]string{"foo": "bar"}
   167  	newVolumeAttachment.Annotations = map[string]string{"foo": "baz"}
   168  	newVolumeAttachment.OwnerReferences = []metav1.OwnerReference{
   169  		{
   170  			APIVersion: "v1",
   171  			Kind:       "Pod",
   172  			Name:       "Foo",
   173  		},
   174  	}
   175  
   176  	StatusStrategy.PrepareForUpdate(ctx, newVolumeAttachment, volumeAttachment)
   177  	if !apiequality.Semantic.DeepEqual(newVolumeAttachment, volumeAttachment) {
   178  		t.Errorf("unexpected objects difference after modifying spec: %v", cmp.Diff(newVolumeAttachment, volumeAttachment))
   179  	}
   180  }
   181  
   182  func TestUpdatePreventsStatusWrite(t *testing.T) {
   183  	va := getValidVolumeAttachment("valid-attachment")
   184  	newAttachment := va.DeepCopy()
   185  	newAttachment.Status.Attached = true
   186  	Strategy.PrepareForUpdate(context.TODO(), newAttachment, va)
   187  	if newAttachment.Status.Attached {
   188  		t.Errorf("expected status to be %v got %v", false, newAttachment.Status.Attached)
   189  	}
   190  }
   191  
   192  func TestCreatePreventsStatusWrite(t *testing.T) {
   193  	va := getValidVolumeAttachment("valid-attachment")
   194  	va.Status.Attached = true
   195  	Strategy.PrepareForCreate(context.TODO(), va)
   196  	if va.Status.Attached {
   197  		t.Errorf("expected status to be false got %v", va.Status.Attached)
   198  	}
   199  }
   200  
   201  func TestVolumeAttachmentValidation(t *testing.T) {
   202  	invalidPVName := "invalid-!@#$%^&*()"
   203  	validPVName := "valid-volume-name"
   204  	tests := []struct {
   205  		name             string
   206  		volumeAttachment *storage.VolumeAttachment
   207  		expectError      bool
   208  	}{
   209  		{
   210  			"valid attachment",
   211  			getValidVolumeAttachment("foo"),
   212  			false,
   213  		},
   214  		{
   215  			"invalid PV name",
   216  			&storage.VolumeAttachment{
   217  				ObjectMeta: metav1.ObjectMeta{
   218  					Name: "foo",
   219  				},
   220  				Spec: storage.VolumeAttachmentSpec{
   221  					Attacher: "valid-attacher",
   222  					Source: storage.VolumeAttachmentSource{
   223  						PersistentVolumeName: &invalidPVName,
   224  					},
   225  					NodeName: "valid-node",
   226  				},
   227  			},
   228  			true,
   229  		},
   230  		{
   231  			"invalid attacher name",
   232  			&storage.VolumeAttachment{
   233  				ObjectMeta: metav1.ObjectMeta{
   234  					Name: "foo",
   235  				},
   236  				Spec: storage.VolumeAttachmentSpec{
   237  					Attacher: "invalid!@#$%^&*()",
   238  					Source: storage.VolumeAttachmentSource{
   239  						PersistentVolumeName: &validPVName,
   240  					},
   241  					NodeName: "valid-node",
   242  				},
   243  			},
   244  			true,
   245  		},
   246  		{
   247  			"invalid volume attachment",
   248  			&storage.VolumeAttachment{
   249  				ObjectMeta: metav1.ObjectMeta{
   250  					Name: "foo",
   251  				},
   252  				Spec: storage.VolumeAttachmentSpec{
   253  					Attacher: "invalid!@#$%^&*()",
   254  					Source: storage.VolumeAttachmentSource{
   255  						PersistentVolumeName: nil,
   256  					},
   257  					NodeName: "valid-node",
   258  				},
   259  			},
   260  			true,
   261  		},
   262  	}
   263  
   264  	for _, test := range tests {
   265  		t.Run(test.name, func(t *testing.T) {
   266  			err := Strategy.Validate(context.TODO(), test.volumeAttachment)
   267  			if len(err) > 0 && !test.expectError {
   268  				t.Errorf("Validation of object failed: %+v", err)
   269  			}
   270  			if len(err) == 0 && test.expectError {
   271  				t.Errorf("Validation of object unexpectedly succeeded")
   272  			}
   273  		})
   274  	}
   275  }
   276  

View as plain text