...

Source file src/github.com/chaos-mesh/chaos-mesh/pkg/selector/nodevolumepath/selector.go

Documentation: github.com/chaos-mesh/chaos-mesh/pkg/selector/nodevolumepath

     1  // Copyright 2021 Chaos Mesh Authors.
     2  //
     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  //
     7  // http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  //
    15  
    16  package nodevolumepath
    17  
    18  import (
    19  	"context"
    20  
    21  	"github.com/pkg/errors"
    22  	"go.uber.org/fx"
    23  	v1 "k8s.io/api/core/v1"
    24  	"k8s.io/apimachinery/pkg/types"
    25  	"sigs.k8s.io/controller-runtime/pkg/client"
    26  
    27  	"github.com/chaos-mesh/chaos-mesh/api/v1alpha1"
    28  	"github.com/chaos-mesh/chaos-mesh/controllers/config"
    29  	"github.com/chaos-mesh/chaos-mesh/pkg/selector/container"
    30  	"github.com/chaos-mesh/chaos-mesh/pkg/selector/generic"
    31  )
    32  
    33  var errNotSupported = errors.New("not supported")
    34  
    35  type SelectImpl struct {
    36  	c client.Client
    37  	r client.Reader
    38  
    39  	containerSelector *container.SelectImpl
    40  	generic.Option
    41  }
    42  
    43  type NodeVolumePath struct {
    44  	*container.Container
    45  
    46  	// volumePath is a volumePath to the block device or directory on a node
    47  	volumePath string
    48  }
    49  
    50  func (n *NodeVolumePath) Id() string {
    51  	// The path may contain "/", but it doesn't matter
    52  	return n.Container.Id() + "/" + n.volumePath
    53  }
    54  
    55  func (impl *SelectImpl) Select(ctx context.Context, selector *v1alpha1.ContainerNodeVolumePathSelector) ([]*NodeVolumePath, error) {
    56  	containers, err := impl.containerSelector.Select(ctx, &selector.ContainerSelector)
    57  	if err != nil {
    58  		return nil, err
    59  	}
    60  
    61  	var result []*NodeVolumePath
    62  	for _, container := range containers {
    63  		for _, volume := range container.Spec.Volumes {
    64  			if volume.Name == selector.VolumeName {
    65  				// Find the path of the volume
    66  				// If the volume is a `HostPath`, the path is the `Path` field
    67  				// If the volume is a `PersistentVolumeClaim`, we can get the path from the related `PersistentVolume`
    68  				if volume.HostPath != nil {
    69  					result = append(result, &NodeVolumePath{
    70  						Container:  container,
    71  						volumePath: volume.HostPath.Path,
    72  					})
    73  				} else if volume.PersistentVolumeClaim != nil {
    74  					var pvc v1.PersistentVolumeClaim
    75  					impl.c.Get(ctx, types.NamespacedName{
    76  						Namespace: container.Namespace,
    77  						Name:      volume.PersistentVolumeClaim.ClaimName,
    78  					}, &pvc)
    79  					if pvc.Status.Phase == v1.ClaimBound {
    80  						var pv v1.PersistentVolume
    81  						impl.c.Get(ctx, types.NamespacedName{
    82  							Name: pvc.Spec.VolumeName,
    83  						}, &pv)
    84  
    85  						// Only `HostPath` and `LocalVolume` are supported
    86  						// TODO: Possibly support more PersistentVolume source.
    87  						if pv.Spec.HostPath != nil {
    88  							result = append(result, &NodeVolumePath{
    89  								Container:  container,
    90  								volumePath: pv.Spec.HostPath.Path,
    91  							})
    92  						} else if pv.Spec.Local != nil {
    93  							result = append(result, &NodeVolumePath{
    94  								Container:  container,
    95  								volumePath: pv.Spec.Local.Path,
    96  							})
    97  						} else {
    98  							return nil, errors.Wrap(errNotSupported, "unsupported PersistentVolume source")
    99  						}
   100  					} else {
   101  						return nil, errors.Wrapf(errNotSupported, "PVC is not bounded yet: pvc phase: %s", pvc.Status.Phase)
   102  					}
   103  				} else {
   104  					return nil, errors.Wrapf(errNotSupported, "volume source is not supported")
   105  				}
   106  			}
   107  		}
   108  	}
   109  
   110  	return result, nil
   111  }
   112  
   113  type Params struct {
   114  	fx.In
   115  
   116  	ContainerSelector *container.SelectImpl
   117  	Client            client.Client
   118  	Reader            client.Reader `name:"no-cache"`
   119  }
   120  
   121  func New(params Params) *SelectImpl {
   122  	return &SelectImpl{
   123  		params.Client,
   124  		params.Reader,
   125  		params.ContainerSelector,
   126  		generic.Option{
   127  			ClusterScoped:         config.ControllerCfg.ClusterScoped,
   128  			TargetNamespace:       config.ControllerCfg.TargetNamespace,
   129  			EnableFilterNamespace: config.ControllerCfg.EnableFilterNamespace,
   130  		},
   131  	}
   132  }
   133