...

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

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

     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 generic
    17  
    18  import (
    19  	"crypto/rand"
    20  	"math"
    21  	"math/big"
    22  	"strconv"
    23  
    24  	"github.com/pkg/errors"
    25  
    26  	"github.com/chaos-mesh/chaos-mesh/api/v1alpha1"
    27  )
    28  
    29  // FilterObjectsByMode filters objects by mode
    30  func FilterObjectsByMode(mode v1alpha1.SelectorMode, value string, count int) ([]uint, error) {
    31  	if count == 0 {
    32  		return nil, errors.New("cannot generate objects from empty list")
    33  	}
    34  
    35  	switch mode {
    36  	case v1alpha1.OneMode:
    37  		index := getRandomNumber(count)
    38  		return []uint{uint(index)}, nil
    39  	case v1alpha1.AllMode:
    40  		return RandomFixedIndexes(0, uint(count), uint(count)+1), nil
    41  	case v1alpha1.FixedMode:
    42  		num, err := strconv.Atoi(value)
    43  		if err != nil {
    44  			return nil, err
    45  		}
    46  
    47  		if count < num {
    48  			num = count
    49  		}
    50  
    51  		if num <= 0 {
    52  			return nil, errors.New("cannot select any object as value below or equal 0")
    53  		}
    54  
    55  		return RandomFixedIndexes(0, uint(count), uint(num)), nil
    56  	case v1alpha1.FixedPercentMode:
    57  		percentage, err := strconv.Atoi(value)
    58  		if err != nil {
    59  			return nil, err
    60  		}
    61  
    62  		if percentage == 0 {
    63  			return nil, errors.New("cannot select any object as value below or equal 0")
    64  		}
    65  
    66  		if percentage < 0 || percentage > 100 {
    67  			return nil, errors.Errorf("fixed percentage value of %d is invalid, Must be (0,100]", percentage)
    68  		}
    69  
    70  		// at least one object should be selected
    71  		num := int(math.Ceil(float64(count) * float64(percentage) / 100))
    72  
    73  		return RandomFixedIndexes(0, uint(count), uint(num)), nil
    74  	case v1alpha1.RandomMaxPercentMode:
    75  		maxPercentage, err := strconv.Atoi(value)
    76  		if err != nil {
    77  			return nil, err
    78  		}
    79  
    80  		if maxPercentage == 0 {
    81  			return nil, errors.New("cannot select any object as value below or equal 0")
    82  		}
    83  
    84  		if maxPercentage < 0 || maxPercentage > 100 {
    85  			return nil, errors.Errorf("fixed percentage value of %d is invalid, Must be [0-100]", maxPercentage)
    86  		}
    87  
    88  		percentage := getRandomNumber(maxPercentage + 1) // + 1 because Intn works with half open interval [0,n) and we want [0,n]
    89  		num := int(math.Ceil(float64(count) * float64(percentage) / 100))
    90  
    91  		return RandomFixedIndexes(0, uint(count), uint(num)), nil
    92  	default:
    93  		return nil, errors.Errorf("mode %s not supported", mode)
    94  	}
    95  }
    96  
    97  // RandomFixedIndexes returns the `count` random indexes between `start` and `end`.
    98  // [start, end)
    99  func RandomFixedIndexes(start, end, count uint) []uint {
   100  	var indexes []uint
   101  	m := make(map[uint]uint, count)
   102  
   103  	if end < start {
   104  		return indexes
   105  	}
   106  
   107  	if count > end-start {
   108  		for i := start; i < end; i++ {
   109  			indexes = append(indexes, i)
   110  		}
   111  
   112  		return indexes
   113  	}
   114  
   115  	for i := 0; i < int(count); {
   116  		index := uint(getRandomNumber(int(end-start))) + start
   117  
   118  		_, exist := m[index]
   119  		if exist {
   120  			continue
   121  		}
   122  
   123  		m[index] = index
   124  		indexes = append(indexes, index)
   125  		i++
   126  	}
   127  
   128  	return indexes
   129  }
   130  
   131  func getRandomNumber(max int) uint64 {
   132  	num, _ := rand.Int(rand.Reader, big.NewInt(int64(max)))
   133  	return num.Uint64()
   134  }
   135