github.com/kaisenlinux/docker@v0.0.0-20230510090727-ea55db55fac7/swarmkit/api/genericresource/parse.go (about)

     1  package genericresource
     2  
     3  import (
     4  	"encoding/csv"
     5  	"fmt"
     6  	"strconv"
     7  	"strings"
     8  
     9  	"github.com/docker/swarmkit/api"
    10  )
    11  
    12  func newParseError(format string, args ...interface{}) error {
    13  	return fmt.Errorf("could not parse GenericResource: "+format, args...)
    14  }
    15  
    16  // discreteResourceVal returns an int64 if the string is a discreteResource
    17  // and an error if it isn't
    18  func discreteResourceVal(res string) (int64, error) {
    19  	return strconv.ParseInt(res, 10, 64)
    20  }
    21  
    22  // allNamedResources returns true if the array of resources are all namedResources
    23  // e.g: res = [red, orange, green]
    24  func allNamedResources(res []string) bool {
    25  	for _, v := range res {
    26  		if _, err := discreteResourceVal(v); err == nil {
    27  			return false
    28  		}
    29  	}
    30  
    31  	return true
    32  }
    33  
    34  // ParseCmd parses the Generic Resource command line argument
    35  // and returns a list of *api.GenericResource
    36  func ParseCmd(cmd string) ([]*api.GenericResource, error) {
    37  	if strings.Contains(cmd, "\n") {
    38  		return nil, newParseError("unexpected '\\n' character")
    39  	}
    40  
    41  	r := csv.NewReader(strings.NewReader(cmd))
    42  	records, err := r.ReadAll()
    43  
    44  	if err != nil {
    45  		return nil, newParseError("%v", err)
    46  	}
    47  
    48  	if len(records) != 1 {
    49  		return nil, newParseError("found multiple records while parsing cmd %v", records)
    50  	}
    51  
    52  	return Parse(records[0])
    53  }
    54  
    55  // Parse parses a table of GenericResource resources
    56  func Parse(cmds []string) ([]*api.GenericResource, error) {
    57  	tokens := make(map[string][]string)
    58  
    59  	for _, term := range cmds {
    60  		kva := strings.Split(term, "=")
    61  		if len(kva) != 2 {
    62  			return nil, newParseError("incorrect term %s, missing"+
    63  				" '=' or malformed expression", term)
    64  		}
    65  
    66  		key := strings.TrimSpace(kva[0])
    67  		val := strings.TrimSpace(kva[1])
    68  
    69  		tokens[key] = append(tokens[key], val)
    70  	}
    71  
    72  	var rs []*api.GenericResource
    73  	for k, v := range tokens {
    74  		if u, ok := isDiscreteResource(v); ok {
    75  			if u < 0 {
    76  				return nil, newParseError("cannot ask for"+
    77  					" negative resource %s", k)
    78  			}
    79  
    80  			rs = append(rs, NewDiscrete(k, u))
    81  			continue
    82  		}
    83  
    84  		if allNamedResources(v) {
    85  			rs = append(rs, NewSet(k, v...)...)
    86  			continue
    87  		}
    88  
    89  		return nil, newParseError("mixed discrete and named resources"+
    90  			" in expression '%s=%s'", k, v)
    91  	}
    92  
    93  	return rs, nil
    94  }
    95  
    96  // isDiscreteResource returns true if the array of resources is a
    97  // Discrete Resource.
    98  // e.g: res = [1]
    99  func isDiscreteResource(values []string) (int64, bool) {
   100  	if len(values) != 1 {
   101  		return int64(0), false
   102  	}
   103  
   104  	u, err := discreteResourceVal(values[0])
   105  	if err != nil {
   106  		return int64(0), false
   107  	}
   108  
   109  	return u, true
   110  
   111  }