github.com/xeptore/docker-cli@v20.10.14+incompatible/cli/command/service/generic_resource_opts.go (about) 1 package service 2 3 import ( 4 "fmt" 5 "strings" 6 7 "github.com/pkg/errors" 8 9 "github.com/docker/docker/api/types/swarm" 10 swarmapi "github.com/docker/swarmkit/api" 11 "github.com/docker/swarmkit/api/genericresource" 12 ) 13 14 // GenericResource is a concept that a user can use to advertise user-defined 15 // resources on a node and thus better place services based on these resources. 16 // E.g: NVIDIA GPUs, Intel FPGAs, ... 17 // See https://github.com/docker/swarmkit/blob/master/design/generic_resources.md 18 19 // ValidateSingleGenericResource validates that a single entry in the 20 // generic resource list is valid. 21 // i.e 'GPU=UID1' is valid however 'GPU:UID1' or 'UID1' isn't 22 func ValidateSingleGenericResource(val string) (string, error) { 23 if strings.Count(val, "=") < 1 { 24 return "", fmt.Errorf("invalid generic-resource format `%s` expected `name=value`", val) 25 } 26 27 return val, nil 28 } 29 30 // ParseGenericResources parses an array of Generic resourceResources 31 // Requesting Named Generic Resources for a service is not supported this 32 // is filtered here. 33 func ParseGenericResources(value []string) ([]swarm.GenericResource, error) { 34 if len(value) == 0 { 35 return nil, nil 36 } 37 38 resources, err := genericresource.Parse(value) 39 if err != nil { 40 return nil, errors.Wrapf(err, "invalid generic resource specification") 41 } 42 43 swarmResources := genericResourcesFromGRPC(resources) 44 for _, res := range swarmResources { 45 if res.NamedResourceSpec != nil { 46 return nil, fmt.Errorf("invalid generic-resource request `%s=%s`, Named Generic Resources is not supported for service create or update", res.NamedResourceSpec.Kind, res.NamedResourceSpec.Value) 47 } 48 } 49 50 return swarmResources, nil 51 } 52 53 // genericResourcesFromGRPC converts a GRPC GenericResource to a GenericResource 54 func genericResourcesFromGRPC(genericRes []*swarmapi.GenericResource) []swarm.GenericResource { 55 var generic []swarm.GenericResource 56 for _, res := range genericRes { 57 var current swarm.GenericResource 58 59 switch r := res.Resource.(type) { 60 case *swarmapi.GenericResource_DiscreteResourceSpec: 61 current.DiscreteResourceSpec = &swarm.DiscreteGenericResource{ 62 Kind: r.DiscreteResourceSpec.Kind, 63 Value: r.DiscreteResourceSpec.Value, 64 } 65 case *swarmapi.GenericResource_NamedResourceSpec: 66 current.NamedResourceSpec = &swarm.NamedGenericResource{ 67 Kind: r.NamedResourceSpec.Kind, 68 Value: r.NamedResourceSpec.Value, 69 } 70 } 71 72 generic = append(generic, current) 73 } 74 75 return generic 76 } 77 78 func buildGenericResourceMap(genericRes []swarm.GenericResource) (map[string]swarm.GenericResource, error) { 79 m := make(map[string]swarm.GenericResource) 80 81 for _, res := range genericRes { 82 if res.DiscreteResourceSpec == nil { 83 return nil, fmt.Errorf("invalid generic-resource `%+v` for service task", res) 84 } 85 86 _, ok := m[res.DiscreteResourceSpec.Kind] 87 if ok { 88 return nil, fmt.Errorf("duplicate generic-resource `%+v` for service task", res.DiscreteResourceSpec.Kind) 89 } 90 91 m[res.DiscreteResourceSpec.Kind] = res 92 } 93 94 return m, nil 95 } 96 97 func buildGenericResourceList(genericRes map[string]swarm.GenericResource) []swarm.GenericResource { 98 var l []swarm.GenericResource 99 100 for _, res := range genericRes { 101 l = append(l, res) 102 } 103 104 return l 105 }