...

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

Documentation: github.com/chaos-mesh/chaos-mesh/pkg/selector/generic/field

     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 field
    17  
    18  import (
    19  	v1 "k8s.io/api/core/v1"
    20  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    21  	"k8s.io/apimachinery/pkg/fields"
    22  	"sigs.k8s.io/controller-runtime/pkg/client"
    23  
    24  	"github.com/chaos-mesh/chaos-mesh/api/v1alpha1"
    25  	"github.com/chaos-mesh/chaos-mesh/pkg/selector/generic"
    26  )
    27  
    28  const Name = "field"
    29  
    30  type fieldSelector struct {
    31  	fields.Selector
    32  }
    33  
    34  var _ generic.Selector = &fieldSelector{}
    35  
    36  func (s *fieldSelector) ListOption() client.ListOption {
    37  	if !s.Empty() {
    38  		return client.MatchingFieldsSelector{Selector: s}
    39  	}
    40  	return nil
    41  }
    42  
    43  func (s *fieldSelector) ListFunc(r client.Reader) generic.ListFunc {
    44  	// Since FieldSelectors need to implement index creation, Reader.List is used to get the pod list.
    45  	// Otherwise, just call Client.List directly, which can be obtained through cache.
    46  	if !s.Empty() && r != nil {
    47  		return r.List
    48  	}
    49  	return nil
    50  }
    51  
    52  func (s *fieldSelector) Match(obj client.Object) bool {
    53  	var objFields fields.Set
    54  	switch obj := obj.(type) {
    55  	case *v1.Pod:
    56  		objFields = toPodSelectableFields(obj)
    57  	case *v1alpha1.PhysicalMachine:
    58  		objFields = toPhysicalMachineSelectableFields(obj)
    59  	default:
    60  		// not support
    61  		return false
    62  	}
    63  	return s.Matches(objFields)
    64  }
    65  
    66  func New(spec v1alpha1.GenericSelectorSpec, _ generic.Option) (generic.Selector, error) {
    67  	return &fieldSelector{
    68  		Selector: fields.SelectorFromSet(spec.FieldSelectors),
    69  	}, nil
    70  }
    71  
    72  // toPodSelectableFields returns a field set that represents the object
    73  // https://github.com/kubernetes/kubernetes/blob/v1.22.2/pkg/registry/core/pod/strategy.go#L306
    74  func toPodSelectableFields(pod *v1.Pod) fields.Set {
    75  	// The purpose of allocation with a given number of elements is to reduce
    76  	// amount of allocations needed to create the fields.Set. If you add any
    77  	// field here or the number of object-meta related fields changes, this should
    78  	// be adjusted.
    79  	podSpecificFieldsSet := make(fields.Set, 9)
    80  	podSpecificFieldsSet["spec.nodeName"] = pod.Spec.NodeName
    81  	podSpecificFieldsSet["spec.restartPolicy"] = string(pod.Spec.RestartPolicy)
    82  	podSpecificFieldsSet["spec.schedulerName"] = pod.Spec.SchedulerName
    83  	podSpecificFieldsSet["spec.serviceAccountName"] = pod.Spec.ServiceAccountName
    84  	podSpecificFieldsSet["status.phase"] = string(pod.Status.Phase)
    85  	podIP := ""
    86  	if len(pod.Status.PodIPs) > 0 {
    87  		podIP = string(pod.Status.PodIPs[0].IP)
    88  	}
    89  	podSpecificFieldsSet["status.podIP"] = podIP
    90  	podSpecificFieldsSet["status.nominatedNodeName"] = pod.Status.NominatedNodeName
    91  	return addObjectMetaFieldsSet(podSpecificFieldsSet, &pod.ObjectMeta, true)
    92  }
    93  
    94  // toPhysicalMachineSelectableFields returns a field set that represents the object
    95  func toPhysicalMachineSelectableFields(physicalMachine *v1alpha1.PhysicalMachine) fields.Set {
    96  	pmSpecificFieldsSet := make(fields.Set, 3)
    97  	pmSpecificFieldsSet["spec.address"] = physicalMachine.Spec.Address
    98  	return addObjectMetaFieldsSet(pmSpecificFieldsSet, &physicalMachine.ObjectMeta, true)
    99  }
   100  
   101  // addObjectMetaFieldsSet add fields that represent the ObjectMeta to source.
   102  func addObjectMetaFieldsSet(source fields.Set, objectMeta *metav1.ObjectMeta, hasNamespaceField bool) fields.Set {
   103  	source["metadata.name"] = objectMeta.Name
   104  	if hasNamespaceField {
   105  		source["metadata.namespace"] = objectMeta.Namespace
   106  	}
   107  	return source
   108  }
   109