deployment.go 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. /*
  2. Copyright 2018 The Kubernetes Authors.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package utils
  14. import (
  15. "path"
  16. "strings"
  17. appsv1 "k8s.io/api/apps/v1"
  18. v1 "k8s.io/api/core/v1"
  19. storagev1 "k8s.io/api/storage/v1"
  20. storagev1beta1 "k8s.io/api/storage/v1beta1"
  21. "k8s.io/kubernetes/test/e2e/framework"
  22. )
  23. // PatchCSIDeployment modifies the CSI driver deployment:
  24. // - replaces the provisioner name
  25. // - forces pods onto a specific host
  26. //
  27. // All of that is optional, see PatchCSIOptions. Just beware
  28. // that not renaming the CSI driver deployment can be problematic:
  29. // - when multiple tests deploy the driver, they need
  30. // to run sequentially
  31. // - might conflict with manual deployments
  32. //
  33. // This function is written so that it works for CSI driver deployments
  34. // that follow these conventions:
  35. // - driver and provisioner names are identical
  36. // - the driver binary accepts a --drivername parameter
  37. // - the provisioner binary accepts a --provisioner parameter
  38. // - the paths inside the container are either fixed
  39. // and don't need to be patch (for example, --csi-address=/csi/csi.sock is
  40. // okay) or are specified directly in a parameter (for example,
  41. // --kubelet-registration-path=/var/lib/kubelet/plugins/csi-hostpath/csi.sock)
  42. //
  43. // Driver deployments that are different will have to do the patching
  44. // without this function, or skip patching entirely.
  45. func PatchCSIDeployment(f *framework.Framework, o PatchCSIOptions, object interface{}) error {
  46. rename := o.OldDriverName != "" && o.NewDriverName != "" &&
  47. o.OldDriverName != o.NewDriverName
  48. patchVolumes := func(volumes []v1.Volume) {
  49. if !rename {
  50. return
  51. }
  52. for i := range volumes {
  53. volume := &volumes[i]
  54. if volume.HostPath != nil {
  55. // Update paths like /var/lib/kubelet/plugins/<provisioner>.
  56. p := &volume.HostPath.Path
  57. dir, file := path.Split(*p)
  58. if file == o.OldDriverName {
  59. *p = path.Join(dir, o.NewDriverName)
  60. }
  61. }
  62. }
  63. }
  64. patchContainers := func(containers []v1.Container) {
  65. for i := range containers {
  66. container := &containers[i]
  67. if rename {
  68. for e := range container.Args {
  69. // Inject test-specific provider name into paths like this one:
  70. // --kubelet-registration-path=/var/lib/kubelet/plugins/csi-hostpath/csi.sock
  71. container.Args[e] = strings.Replace(container.Args[e], "/"+o.OldDriverName+"/", "/"+o.NewDriverName+"/", 1)
  72. }
  73. }
  74. // Overwrite driver name resp. provider name
  75. // by appending a parameter with the right
  76. // value.
  77. switch container.Name {
  78. case o.DriverContainerName:
  79. container.Args = append(container.Args, o.DriverContainerArguments...)
  80. case o.ProvisionerContainerName:
  81. // Driver name is expected to be the same
  82. // as the provisioner here.
  83. container.Args = append(container.Args, "--provisioner="+o.NewDriverName)
  84. }
  85. }
  86. }
  87. patchPodSpec := func(spec *v1.PodSpec) {
  88. patchContainers(spec.Containers)
  89. patchVolumes(spec.Volumes)
  90. if o.NodeName != "" {
  91. spec.NodeName = o.NodeName
  92. }
  93. }
  94. switch object := object.(type) {
  95. case *appsv1.ReplicaSet:
  96. patchPodSpec(&object.Spec.Template.Spec)
  97. case *appsv1.DaemonSet:
  98. patchPodSpec(&object.Spec.Template.Spec)
  99. case *appsv1.StatefulSet:
  100. patchPodSpec(&object.Spec.Template.Spec)
  101. case *appsv1.Deployment:
  102. patchPodSpec(&object.Spec.Template.Spec)
  103. case *storagev1.StorageClass:
  104. if o.NewDriverName != "" {
  105. // Driver name is expected to be the same
  106. // as the provisioner name here.
  107. object.Provisioner = o.NewDriverName
  108. }
  109. case *storagev1beta1.CSIDriver:
  110. if o.NewDriverName != "" {
  111. object.Name = o.NewDriverName
  112. }
  113. if o.PodInfo != nil {
  114. object.Spec.PodInfoOnMount = o.PodInfo
  115. }
  116. if o.CanAttach != nil {
  117. object.Spec.AttachRequired = o.CanAttach
  118. }
  119. if o.VolumeLifecycleModes != nil {
  120. object.Spec.VolumeLifecycleModes = *o.VolumeLifecycleModes
  121. }
  122. }
  123. return nil
  124. }
  125. // PatchCSIOptions controls how PatchCSIDeployment patches the objects.
  126. type PatchCSIOptions struct {
  127. // The original driver name.
  128. OldDriverName string
  129. // The driver name that replaces the original name.
  130. // Can be empty (not used at all) or equal to OldDriverName
  131. // (then it will be added were appropriate without renaming
  132. // in existing fields).
  133. NewDriverName string
  134. // The name of the container which has the CSI driver binary.
  135. // If non-empty, DriverContainerArguments are added to argument
  136. // list in container with that name.
  137. DriverContainerName string
  138. // List of arguments to add to container with
  139. // DriverContainerName.
  140. DriverContainerArguments []string
  141. // The name of the container which has the provisioner binary.
  142. // If non-empty, --provisioner with new name will be appended
  143. // to the argument list.
  144. ProvisionerContainerName string
  145. // The name of the container which has the snapshotter binary.
  146. // If non-empty, --snapshotter with new name will be appended
  147. // to the argument list.
  148. SnapshotterContainerName string
  149. // If non-empty, all pods are forced to run on this node.
  150. NodeName string
  151. // If not nil, the value to use for the CSIDriver.Spec.PodInfo
  152. // field *if* the driver deploys a CSIDriver object. Ignored
  153. // otherwise.
  154. PodInfo *bool
  155. // If not nil, the value to use for the CSIDriver.Spec.CanAttach
  156. // field *if* the driver deploys a CSIDriver object. Ignored
  157. // otherwise.
  158. CanAttach *bool
  159. // If not nil, the value to use for the CSIDriver.Spec.VolumeLifecycleModes
  160. // field *if* the driver deploys a CSIDriver object. Ignored
  161. // otherwise.
  162. VolumeLifecycleModes *[]storagev1beta1.VolumeLifecycleMode
  163. }