mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-19 09:52:49 +00:00
234 lines
7.9 KiB
Go
234 lines
7.9 KiB
Go
/*
|
|
Copyright 2018 The Kubernetes Authors.
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
you may not use this file except in compliance with the License.
|
|
You may obtain a copy of the License at
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing permissions and
|
|
limitations under the License.
|
|
*/
|
|
|
|
package utils
|
|
|
|
import (
|
|
"fmt"
|
|
"path"
|
|
"strings"
|
|
|
|
appsv1 "k8s.io/api/apps/v1"
|
|
v1 "k8s.io/api/core/v1"
|
|
storagev1 "k8s.io/api/storage/v1"
|
|
e2eframework "k8s.io/kubernetes/test/e2e/framework"
|
|
e2epod "k8s.io/kubernetes/test/e2e/framework/pod"
|
|
)
|
|
|
|
// PatchCSIDeployment modifies the CSI driver deployment:
|
|
// - replaces the provisioner name
|
|
// - forces pods onto a specific host
|
|
//
|
|
// All of that is optional, see PatchCSIOptions. Just beware
|
|
// that not renaming the CSI driver deployment can be problematic:
|
|
// - when multiple tests deploy the driver, they need
|
|
// to run sequentially
|
|
// - might conflict with manual deployments
|
|
//
|
|
// This function is written so that it works for CSI driver deployments
|
|
// that follow these conventions:
|
|
// - driver and provisioner names are identical
|
|
// - the driver binary accepts a --drivername parameter
|
|
// - the paths inside the container are either fixed
|
|
// and don't need to be patch (for example, --csi-address=/csi/csi.sock is
|
|
// okay) or are specified directly in a parameter (for example,
|
|
// --kubelet-registration-path=/var/lib/kubelet/plugins/csi-hostpath/csi.sock)
|
|
//
|
|
// Driver deployments that are different will have to do the patching
|
|
// without this function, or skip patching entirely.
|
|
func PatchCSIDeployment(f *e2eframework.Framework, o PatchCSIOptions, object interface{}) error {
|
|
rename := o.OldDriverName != "" && o.NewDriverName != "" &&
|
|
o.OldDriverName != o.NewDriverName
|
|
|
|
substKubeletRootDir := func(s string) string {
|
|
return strings.ReplaceAll(s, "/var/lib/kubelet/", e2eframework.TestContext.KubeletRootDir+"/")
|
|
}
|
|
|
|
patchVolumes := func(volumes []v1.Volume) {
|
|
if !rename {
|
|
return
|
|
}
|
|
for i := range volumes {
|
|
volume := &volumes[i]
|
|
if volume.HostPath != nil {
|
|
// Update paths like /var/lib/kubelet/plugins/<provisioner>.
|
|
p := &volume.HostPath.Path
|
|
dir, file := path.Split(*p)
|
|
if file == o.OldDriverName {
|
|
*p = path.Join(dir, o.NewDriverName)
|
|
}
|
|
// Inject non-standard kubelet path.
|
|
*p = substKubeletRootDir(*p)
|
|
}
|
|
}
|
|
}
|
|
|
|
patchContainers := func(containers []v1.Container) {
|
|
for i := range containers {
|
|
container := &containers[i]
|
|
if rename {
|
|
for e := range container.Args {
|
|
// Inject test-specific provider name into paths like this one:
|
|
// --kubelet-registration-path=/var/lib/kubelet/plugins/csi-hostpath/csi.sock
|
|
container.Args[e] = strings.Replace(container.Args[e], "/"+o.OldDriverName+"/", "/"+o.NewDriverName+"/", 1)
|
|
}
|
|
}
|
|
|
|
// Modify --kubelet-registration-path.
|
|
for e := range container.Args {
|
|
container.Args[e] = substKubeletRootDir(container.Args[e])
|
|
}
|
|
for e := range container.VolumeMounts {
|
|
container.VolumeMounts[e].MountPath = substKubeletRootDir(container.VolumeMounts[e].MountPath)
|
|
}
|
|
|
|
if len(o.Features) > 0 && len(o.Features[container.Name]) > 0 {
|
|
featuregateString := strings.Join(o.Features[container.Name], ",")
|
|
container.Args = append(container.Args, fmt.Sprintf("--feature-gates=%s", featuregateString))
|
|
}
|
|
|
|
// Overwrite driver name resp. provider name
|
|
// by appending a parameter with the right
|
|
// value.
|
|
switch container.Name {
|
|
case o.DriverContainerName:
|
|
container.Args = append(container.Args, o.DriverContainerArguments...)
|
|
}
|
|
}
|
|
}
|
|
|
|
patchPodSpec := func(spec *v1.PodSpec) {
|
|
patchContainers(spec.Containers)
|
|
patchVolumes(spec.Volumes)
|
|
if o.NodeName != "" {
|
|
e2epod.SetNodeSelection(spec, e2epod.NodeSelection{Name: o.NodeName})
|
|
}
|
|
}
|
|
|
|
switch object := object.(type) {
|
|
case *appsv1.ReplicaSet:
|
|
patchPodSpec(&object.Spec.Template.Spec)
|
|
case *appsv1.DaemonSet:
|
|
patchPodSpec(&object.Spec.Template.Spec)
|
|
case *appsv1.StatefulSet:
|
|
patchPodSpec(&object.Spec.Template.Spec)
|
|
case *appsv1.Deployment:
|
|
patchPodSpec(&object.Spec.Template.Spec)
|
|
case *storagev1.StorageClass:
|
|
if o.NewDriverName != "" {
|
|
// Driver name is expected to be the same
|
|
// as the provisioner name here.
|
|
object.Provisioner = o.NewDriverName
|
|
}
|
|
case *storagev1.CSIDriver:
|
|
if o.NewDriverName != "" {
|
|
object.Name = o.NewDriverName
|
|
}
|
|
if o.PodInfo != nil {
|
|
object.Spec.PodInfoOnMount = o.PodInfo
|
|
}
|
|
if o.StorageCapacity != nil {
|
|
object.Spec.StorageCapacity = o.StorageCapacity
|
|
}
|
|
if o.CanAttach != nil {
|
|
object.Spec.AttachRequired = o.CanAttach
|
|
}
|
|
if o.VolumeLifecycleModes != nil {
|
|
object.Spec.VolumeLifecycleModes = *o.VolumeLifecycleModes
|
|
}
|
|
if o.TokenRequests != nil {
|
|
object.Spec.TokenRequests = o.TokenRequests
|
|
}
|
|
if o.RequiresRepublish != nil {
|
|
object.Spec.RequiresRepublish = o.RequiresRepublish
|
|
}
|
|
if o.FSGroupPolicy != nil {
|
|
object.Spec.FSGroupPolicy = o.FSGroupPolicy
|
|
}
|
|
if o.SELinuxMount != nil {
|
|
object.Spec.SELinuxMount = o.SELinuxMount
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// PatchCSIOptions controls how PatchCSIDeployment patches the objects.
|
|
type PatchCSIOptions struct {
|
|
// The original driver name.
|
|
OldDriverName string
|
|
// The driver name that replaces the original name.
|
|
// Can be empty (not used at all) or equal to OldDriverName
|
|
// (then it will be added were appropriate without renaming
|
|
// in existing fields).
|
|
NewDriverName string
|
|
// The name of the container which has the CSI driver binary.
|
|
// If non-empty, DriverContainerArguments are added to argument
|
|
// list in container with that name.
|
|
DriverContainerName string
|
|
// List of arguments to add to container with
|
|
// DriverContainerName.
|
|
DriverContainerArguments []string
|
|
// The name of the container which has the provisioner binary.
|
|
// If non-empty, --provisioner with new name will be appended
|
|
// to the argument list.
|
|
ProvisionerContainerName string
|
|
// The name of the container which has the snapshotter binary.
|
|
// If non-empty, --snapshotter with new name will be appended
|
|
// to the argument list.
|
|
SnapshotterContainerName string
|
|
// If non-empty, all pods are forced to run on this node.
|
|
NodeName string
|
|
// If not nil, the value to use for the CSIDriver.Spec.PodInfo
|
|
// field *if* the driver deploys a CSIDriver object. Ignored
|
|
// otherwise.
|
|
PodInfo *bool
|
|
// If not nil, the value to use for the CSIDriver.Spec.CanAttach
|
|
// field *if* the driver deploys a CSIDriver object. Ignored
|
|
// otherwise.
|
|
CanAttach *bool
|
|
// If not nil, the value to use for the CSIDriver.Spec.StorageCapacity
|
|
// field *if* the driver deploys a CSIDriver object. Ignored
|
|
// otherwise.
|
|
StorageCapacity *bool
|
|
// If not nil, the value to use for the CSIDriver.Spec.VolumeLifecycleModes
|
|
// field *if* the driver deploys a CSIDriver object. Ignored
|
|
// otherwise.
|
|
VolumeLifecycleModes *[]storagev1.VolumeLifecycleMode
|
|
// If not nil, the value to use for the CSIDriver.Spec.TokenRequests
|
|
// field *if* the driver deploys a CSIDriver object. Ignored
|
|
// otherwise.
|
|
TokenRequests []storagev1.TokenRequest
|
|
// If not nil, the value to use for the CSIDriver.Spec.RequiresRepublish
|
|
// field *if* the driver deploys a CSIDriver object. Ignored
|
|
// otherwise.
|
|
RequiresRepublish *bool
|
|
// If not nil, the value to use for the CSIDriver.Spec.FSGroupPolicy
|
|
// field *if* the driver deploys a CSIDriver object. Ignored
|
|
// otherwise.
|
|
FSGroupPolicy *storagev1.FSGroupPolicy
|
|
// If not nil, the value to use for the CSIDriver.Spec.SELinuxMount
|
|
// field *if* the driver deploys a CSIDriver object. Ignored
|
|
// otherwise.
|
|
SELinuxMount *bool
|
|
// If not nil, the values will be used for setting feature arguments to
|
|
// specific sidecar.
|
|
// Feature is a map - where key is sidecar name such as:
|
|
// -- key: resizer
|
|
// -- value: []string{feature-gates}
|
|
Features map[string][]string
|
|
}
|