Merge pull request #6627 from thaJeztah/local_parsegeneric_resource
cli/command/service: parse generic resources without protobufs
This commit is contained in:
@ -4,9 +4,8 @@ import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/cli/cli/command/service/internal/genericresource"
|
||||
"github.com/moby/moby/api/types/swarm"
|
||||
swarmapi "github.com/moby/swarmkit/v2/api"
|
||||
"github.com/moby/swarmkit/v2/api/genericresource"
|
||||
)
|
||||
|
||||
// GenericResource is a concept that a user can use to advertise user-defined
|
||||
@ -33,12 +32,11 @@ func ParseGenericResources(value []string) ([]swarm.GenericResource, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
resources, err := genericresource.Parse(value)
|
||||
swarmResources, err := genericresource.Parse(value)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid generic resource specification: %w", err)
|
||||
}
|
||||
|
||||
swarmResources := genericResourcesFromGRPC(resources)
|
||||
for _, res := range swarmResources {
|
||||
if res.NamedResourceSpec != nil {
|
||||
return nil, fmt.Errorf("invalid generic-resource request `%s=%s`, Named Generic Resources is not supported for service create or update",
|
||||
@ -50,31 +48,6 @@ func ParseGenericResources(value []string) ([]swarm.GenericResource, error) {
|
||||
return swarmResources, nil
|
||||
}
|
||||
|
||||
// genericResourcesFromGRPC converts a GRPC GenericResource to a GenericResource
|
||||
func genericResourcesFromGRPC(genericRes []*swarmapi.GenericResource) []swarm.GenericResource {
|
||||
generic := make([]swarm.GenericResource, 0, len(genericRes))
|
||||
for _, res := range genericRes {
|
||||
var current swarm.GenericResource
|
||||
|
||||
switch r := res.Resource.(type) {
|
||||
case *swarmapi.GenericResource_DiscreteResourceSpec:
|
||||
current.DiscreteResourceSpec = &swarm.DiscreteGenericResource{
|
||||
Kind: r.DiscreteResourceSpec.Kind,
|
||||
Value: r.DiscreteResourceSpec.Value,
|
||||
}
|
||||
case *swarmapi.GenericResource_NamedResourceSpec:
|
||||
current.NamedResourceSpec = &swarm.NamedGenericResource{
|
||||
Kind: r.NamedResourceSpec.Kind,
|
||||
Value: r.NamedResourceSpec.Value,
|
||||
}
|
||||
}
|
||||
|
||||
generic = append(generic, current)
|
||||
}
|
||||
|
||||
return generic
|
||||
}
|
||||
|
||||
func buildGenericResourceMap(genericRes []swarm.GenericResource) (map[string]swarm.GenericResource, error) {
|
||||
m := make(map[string]swarm.GenericResource)
|
||||
|
||||
|
||||
48
cli/command/service/internal/genericresource/helpers.go
Normal file
48
cli/command/service/internal/genericresource/helpers.go
Normal file
@ -0,0 +1,48 @@
|
||||
package genericresource
|
||||
|
||||
import (
|
||||
api "github.com/moby/moby/api/types/swarm"
|
||||
)
|
||||
|
||||
// NewSet creates a set object
|
||||
func NewSet(key string, vals ...string) []api.GenericResource {
|
||||
rs := make([]api.GenericResource, 0, len(vals))
|
||||
for _, v := range vals {
|
||||
rs = append(rs, NewString(key, v))
|
||||
}
|
||||
return rs
|
||||
}
|
||||
|
||||
// NewString creates a String resource
|
||||
func NewString(kind, value string) api.GenericResource {
|
||||
return api.GenericResource{
|
||||
NamedResourceSpec: &api.NamedGenericResource{
|
||||
Kind: kind,
|
||||
Value: value,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// NewDiscrete creates a Discrete resource
|
||||
func NewDiscrete(key string, val int64) api.GenericResource {
|
||||
return api.GenericResource{
|
||||
DiscreteResourceSpec: &api.DiscreteGenericResource{
|
||||
Kind: key,
|
||||
Value: val,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// GetResource returns resources from the "resources" parameter matching the kind key
|
||||
func GetResource(kind string, resources []api.GenericResource) []api.GenericResource {
|
||||
var res []api.GenericResource
|
||||
for _, r := range resources {
|
||||
switch {
|
||||
case r.DiscreteResourceSpec != nil && r.DiscreteResourceSpec.Kind == kind:
|
||||
res = append(res, r)
|
||||
case r.NamedResourceSpec != nil && r.NamedResourceSpec.Kind == kind:
|
||||
res = append(res, r)
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
@ -1,3 +1,10 @@
|
||||
// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
|
||||
//go:build go1.24
|
||||
|
||||
// Package genericresource is a local fork of SwarmKit's [genericresource] package,
|
||||
// without protobuf dependencies.
|
||||
//
|
||||
// [genericresource]: https://github.com/moby/swarmkit/blob/v2.1.1/api/genericresource/parse.go
|
||||
package genericresource
|
||||
|
||||
import (
|
||||
@ -6,10 +13,10 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/moby/swarmkit/v2/api"
|
||||
api "github.com/moby/moby/api/types/swarm"
|
||||
)
|
||||
|
||||
func newParseError(format string, args ...interface{}) error {
|
||||
func newParseError(format string, args ...any) error {
|
||||
return fmt.Errorf("could not parse GenericResource: "+format, args...)
|
||||
}
|
||||
|
||||
@ -32,15 +39,14 @@ func allNamedResources(res []string) bool {
|
||||
}
|
||||
|
||||
// ParseCmd parses the Generic Resource command line argument
|
||||
// and returns a list of *api.GenericResource
|
||||
func ParseCmd(cmd string) ([]*api.GenericResource, error) {
|
||||
// and returns a list of api.GenericResource
|
||||
func ParseCmd(cmd string) ([]api.GenericResource, error) {
|
||||
if strings.Contains(cmd, "\n") {
|
||||
return nil, newParseError("unexpected '\\n' character")
|
||||
}
|
||||
|
||||
r := csv.NewReader(strings.NewReader(cmd))
|
||||
records, err := r.ReadAll()
|
||||
|
||||
if err != nil {
|
||||
return nil, newParseError("%v", err)
|
||||
}
|
||||
@ -53,7 +59,7 @@ func ParseCmd(cmd string) ([]*api.GenericResource, error) {
|
||||
}
|
||||
|
||||
// Parse parses a table of GenericResource resources
|
||||
func Parse(cmds []string) ([]*api.GenericResource, error) {
|
||||
func Parse(cmds []string) ([]api.GenericResource, error) {
|
||||
tokens := make(map[string][]string)
|
||||
|
||||
for _, term := range cmds {
|
||||
@ -69,7 +75,7 @@ func Parse(cmds []string) ([]*api.GenericResource, error) {
|
||||
tokens[key] = append(tokens[key], val)
|
||||
}
|
||||
|
||||
var rs []*api.GenericResource
|
||||
var rs []api.GenericResource
|
||||
for k, v := range tokens {
|
||||
if u, ok := isDiscreteResource(v); ok {
|
||||
if u < 0 {
|
||||
@ -107,5 +113,4 @@ func isDiscreteResource(values []string) (int64, bool) {
|
||||
}
|
||||
|
||||
return u, true
|
||||
|
||||
}
|
||||
65
cli/command/service/internal/genericresource/parse_test.go
Normal file
65
cli/command/service/internal/genericresource/parse_test.go
Normal file
@ -0,0 +1,65 @@
|
||||
package genericresource
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"gotest.tools/v3/assert"
|
||||
)
|
||||
|
||||
func TestParseDiscrete(t *testing.T) {
|
||||
res, err := ParseCmd("apple=3")
|
||||
assert.NilError(t, err)
|
||||
assert.Equal(t, len(res), 1)
|
||||
|
||||
apples := GetResource("apple", res)
|
||||
assert.Equal(t, len(apples), 1)
|
||||
if apples[0].DiscreteResourceSpec == nil {
|
||||
t.Fatalf("expected discrete resource spec, got nil")
|
||||
}
|
||||
assert.Equal(t, apples[0].DiscreteResourceSpec.Value, int64(3))
|
||||
|
||||
_, err = ParseCmd("apple=3\napple=4")
|
||||
assert.Assert(t, err != nil)
|
||||
|
||||
_, err = ParseCmd("apple=3,apple=4")
|
||||
assert.Assert(t, err != nil)
|
||||
|
||||
_, err = ParseCmd("apple=-3")
|
||||
assert.Assert(t, err != nil)
|
||||
}
|
||||
|
||||
func TestParseStr(t *testing.T) {
|
||||
res, err := ParseCmd("orange=red,orange=green,orange=blue")
|
||||
assert.NilError(t, err)
|
||||
assert.Equal(t, len(res), 3)
|
||||
|
||||
oranges := GetResource("orange", res)
|
||||
assert.Equal(t, len(oranges), 3)
|
||||
for _, k := range []string{"red", "green", "blue"} {
|
||||
assert.Assert(t, HasResource(NewString("orange", k), oranges))
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseDiscreteAndStr(t *testing.T) {
|
||||
res, err := ParseCmd("orange=red,orange=green,orange=blue,apple=3")
|
||||
assert.NilError(t, err)
|
||||
assert.Equal(t, len(res), 4)
|
||||
|
||||
oranges := GetResource("orange", res)
|
||||
assert.Equal(t, len(oranges), 3)
|
||||
for _, k := range []string{"red", "green", "blue"} {
|
||||
assert.Assert(t, HasResource(NewString("orange", k), oranges))
|
||||
}
|
||||
|
||||
apples := GetResource("apple", res)
|
||||
assert.Equal(t, len(apples), 1)
|
||||
if apples[0].DiscreteResourceSpec == nil {
|
||||
t.Fatalf("expected discrete resource spec, got nil")
|
||||
}
|
||||
assert.Equal(t, apples[0].DiscreteResourceSpec.Value, int64(3))
|
||||
}
|
||||
|
||||
func TestParseMixedForSameKindFails(t *testing.T) {
|
||||
_, err := ParseCmd("gpu=fast,gpu=slow,gpu=2")
|
||||
assert.Assert(t, err != nil)
|
||||
}
|
||||
29
cli/command/service/internal/genericresource/validate.go
Normal file
29
cli/command/service/internal/genericresource/validate.go
Normal file
@ -0,0 +1,29 @@
|
||||
package genericresource
|
||||
|
||||
import (
|
||||
api "github.com/moby/moby/api/types/swarm"
|
||||
)
|
||||
|
||||
// HasResource checks if there is enough "res" in the "resources" argument
|
||||
func HasResource(res api.GenericResource, resources []api.GenericResource) bool {
|
||||
for _, r := range resources {
|
||||
if equalResource(r, res) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// equalResource matches the resource *type* (named vs discrete), and then kind+value.
|
||||
func equalResource(a, b api.GenericResource) bool {
|
||||
switch {
|
||||
case a.NamedResourceSpec != nil && b.NamedResourceSpec != nil:
|
||||
return a.NamedResourceSpec.Kind == b.NamedResourceSpec.Kind &&
|
||||
a.NamedResourceSpec.Value == b.NamedResourceSpec.Value
|
||||
|
||||
case a.DiscreteResourceSpec != nil && b.DiscreteResourceSpec != nil:
|
||||
return a.DiscreteResourceSpec.Kind == b.DiscreteResourceSpec.Kind &&
|
||||
a.DiscreteResourceSpec.Value == b.DiscreteResourceSpec.Value
|
||||
}
|
||||
return false
|
||||
}
|
||||
111
vendor/github.com/moby/swarmkit/v2/api/genericresource/helpers.go
generated
vendored
111
vendor/github.com/moby/swarmkit/v2/api/genericresource/helpers.go
generated
vendored
@ -1,111 +0,0 @@
|
||||
package genericresource
|
||||
|
||||
import (
|
||||
"github.com/moby/swarmkit/v2/api"
|
||||
)
|
||||
|
||||
// NewSet creates a set object
|
||||
func NewSet(key string, vals ...string) []*api.GenericResource {
|
||||
rs := make([]*api.GenericResource, 0, len(vals))
|
||||
|
||||
for _, v := range vals {
|
||||
rs = append(rs, NewString(key, v))
|
||||
}
|
||||
|
||||
return rs
|
||||
}
|
||||
|
||||
// NewString creates a String resource
|
||||
func NewString(key, val string) *api.GenericResource {
|
||||
return &api.GenericResource{
|
||||
Resource: &api.GenericResource_NamedResourceSpec{
|
||||
NamedResourceSpec: &api.NamedGenericResource{
|
||||
Kind: key,
|
||||
Value: val,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// NewDiscrete creates a Discrete resource
|
||||
func NewDiscrete(key string, val int64) *api.GenericResource {
|
||||
return &api.GenericResource{
|
||||
Resource: &api.GenericResource_DiscreteResourceSpec{
|
||||
DiscreteResourceSpec: &api.DiscreteGenericResource{
|
||||
Kind: key,
|
||||
Value: val,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// GetResource returns resources from the "resources" parameter matching the kind key
|
||||
func GetResource(kind string, resources []*api.GenericResource) []*api.GenericResource {
|
||||
var res []*api.GenericResource
|
||||
|
||||
for _, r := range resources {
|
||||
if Kind(r) != kind {
|
||||
continue
|
||||
}
|
||||
|
||||
res = append(res, r)
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
// ConsumeNodeResources removes "res" from nodeAvailableResources
|
||||
func ConsumeNodeResources(nodeAvailableResources *[]*api.GenericResource, res []*api.GenericResource) {
|
||||
if nodeAvailableResources == nil {
|
||||
return
|
||||
}
|
||||
|
||||
w := 0
|
||||
|
||||
loop:
|
||||
for _, na := range *nodeAvailableResources {
|
||||
for _, r := range res {
|
||||
if Kind(na) != Kind(r) {
|
||||
continue
|
||||
}
|
||||
|
||||
if remove(na, r) {
|
||||
continue loop
|
||||
}
|
||||
// If this wasn't the right element then
|
||||
// we need to continue
|
||||
}
|
||||
|
||||
(*nodeAvailableResources)[w] = na
|
||||
w++
|
||||
}
|
||||
|
||||
*nodeAvailableResources = (*nodeAvailableResources)[:w]
|
||||
}
|
||||
|
||||
// Returns true if the element is to be removed from the list
|
||||
func remove(na, r *api.GenericResource) bool {
|
||||
switch tr := r.Resource.(type) {
|
||||
case *api.GenericResource_DiscreteResourceSpec:
|
||||
if na.GetDiscreteResourceSpec() == nil {
|
||||
return false // Type change, ignore
|
||||
}
|
||||
|
||||
na.GetDiscreteResourceSpec().Value -= tr.DiscreteResourceSpec.Value
|
||||
if na.GetDiscreteResourceSpec().Value <= 0 {
|
||||
return true
|
||||
}
|
||||
case *api.GenericResource_NamedResourceSpec:
|
||||
if na.GetNamedResourceSpec() == nil {
|
||||
return false // Type change, ignore
|
||||
}
|
||||
|
||||
if tr.NamedResourceSpec.Value != na.GetNamedResourceSpec().Value {
|
||||
return false // not the right item, ignore
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
203
vendor/github.com/moby/swarmkit/v2/api/genericresource/resource_management.go
generated
vendored
203
vendor/github.com/moby/swarmkit/v2/api/genericresource/resource_management.go
generated
vendored
@ -1,203 +0,0 @@
|
||||
package genericresource
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/moby/swarmkit/v2/api"
|
||||
)
|
||||
|
||||
// Claim assigns GenericResources to a task by taking them from the
|
||||
// node's GenericResource list and storing them in the task's available list
|
||||
func Claim(nodeAvailableResources, taskAssigned *[]*api.GenericResource,
|
||||
taskReservations []*api.GenericResource) error {
|
||||
var resSelected []*api.GenericResource
|
||||
|
||||
for _, res := range taskReservations {
|
||||
tr := res.GetDiscreteResourceSpec()
|
||||
if tr == nil {
|
||||
return fmt.Errorf("task should only hold Discrete type")
|
||||
}
|
||||
|
||||
// Select the resources
|
||||
nrs, err := selectNodeResources(*nodeAvailableResources, tr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
resSelected = append(resSelected, nrs...)
|
||||
}
|
||||
|
||||
ClaimResources(nodeAvailableResources, taskAssigned, resSelected)
|
||||
return nil
|
||||
}
|
||||
|
||||
// ClaimResources adds the specified resources to the task's list
|
||||
// and removes them from the node's generic resource list
|
||||
func ClaimResources(nodeAvailableResources, taskAssigned *[]*api.GenericResource,
|
||||
resSelected []*api.GenericResource) {
|
||||
*taskAssigned = append(*taskAssigned, resSelected...)
|
||||
ConsumeNodeResources(nodeAvailableResources, resSelected)
|
||||
}
|
||||
|
||||
func selectNodeResources(nodeRes []*api.GenericResource,
|
||||
tr *api.DiscreteGenericResource) ([]*api.GenericResource, error) {
|
||||
var nrs []*api.GenericResource
|
||||
|
||||
for _, res := range nodeRes {
|
||||
if Kind(res) != tr.Kind {
|
||||
continue
|
||||
}
|
||||
|
||||
switch nr := res.Resource.(type) {
|
||||
case *api.GenericResource_DiscreteResourceSpec:
|
||||
if nr.DiscreteResourceSpec.Value >= tr.Value && tr.Value != 0 {
|
||||
nrs = append(nrs, NewDiscrete(tr.Kind, tr.Value))
|
||||
}
|
||||
|
||||
return nrs, nil
|
||||
case *api.GenericResource_NamedResourceSpec:
|
||||
nrs = append(nrs, res.Copy())
|
||||
|
||||
if int64(len(nrs)) == tr.Value {
|
||||
return nrs, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(nrs) == 0 {
|
||||
return nil, fmt.Errorf("not enough resources available for task reservations: %+v", tr)
|
||||
}
|
||||
|
||||
return nrs, nil
|
||||
}
|
||||
|
||||
// Reclaim adds the resources taken by the task to the node's store
|
||||
func Reclaim(nodeAvailableResources *[]*api.GenericResource, taskAssigned, nodeRes []*api.GenericResource) error {
|
||||
err := reclaimResources(nodeAvailableResources, taskAssigned)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
sanitize(nodeRes, nodeAvailableResources)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func reclaimResources(nodeAvailableResources *[]*api.GenericResource, taskAssigned []*api.GenericResource) error {
|
||||
// The node could have been updated
|
||||
if nodeAvailableResources == nil {
|
||||
return fmt.Errorf("node no longer has any resources")
|
||||
}
|
||||
|
||||
for _, res := range taskAssigned {
|
||||
switch tr := res.Resource.(type) {
|
||||
case *api.GenericResource_DiscreteResourceSpec:
|
||||
nrs := GetResource(tr.DiscreteResourceSpec.Kind, *nodeAvailableResources)
|
||||
|
||||
// If the resource went down to 0 it's no longer in the
|
||||
// available list
|
||||
if len(nrs) == 0 {
|
||||
*nodeAvailableResources = append(*nodeAvailableResources, res.Copy())
|
||||
}
|
||||
|
||||
if len(nrs) != 1 {
|
||||
continue // Type change
|
||||
}
|
||||
|
||||
nr := nrs[0].GetDiscreteResourceSpec()
|
||||
if nr == nil {
|
||||
continue // Type change
|
||||
}
|
||||
|
||||
nr.Value += tr.DiscreteResourceSpec.Value
|
||||
case *api.GenericResource_NamedResourceSpec:
|
||||
*nodeAvailableResources = append(*nodeAvailableResources, res.Copy())
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// sanitize checks that nodeAvailableResources does not add resources unknown
|
||||
// to the nodeSpec (nodeRes) or goes over the integer bound specified
|
||||
// by the spec.
|
||||
// Note this is because the user is able to update a node's resources
|
||||
func sanitize(nodeRes []*api.GenericResource, nodeAvailableResources *[]*api.GenericResource) {
|
||||
// - We add the sanitized resources at the end, after
|
||||
// having removed the elements from the list
|
||||
|
||||
// - When a set changes to a Discrete we also need
|
||||
// to make sure that we don't add the Discrete multiple
|
||||
// time hence, the need of a map to remember that
|
||||
var sanitized []*api.GenericResource
|
||||
kindSanitized := make(map[string]struct{})
|
||||
w := 0
|
||||
|
||||
for _, na := range *nodeAvailableResources {
|
||||
ok, nrs := sanitizeResource(nodeRes, na)
|
||||
if !ok {
|
||||
if _, ok = kindSanitized[Kind(na)]; ok {
|
||||
continue
|
||||
}
|
||||
|
||||
kindSanitized[Kind(na)] = struct{}{}
|
||||
sanitized = append(sanitized, nrs...)
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
(*nodeAvailableResources)[w] = na
|
||||
w++
|
||||
}
|
||||
|
||||
*nodeAvailableResources = (*nodeAvailableResources)[:w]
|
||||
*nodeAvailableResources = append(*nodeAvailableResources, sanitized...)
|
||||
}
|
||||
|
||||
// Returns true if the element is in nodeRes and "sane"
|
||||
// Returns false if the element isn't in nodeRes and "sane" and the element(s) that should be replacing it
|
||||
func sanitizeResource(nodeRes []*api.GenericResource, res *api.GenericResource) (ok bool, nrs []*api.GenericResource) {
|
||||
switch na := res.Resource.(type) {
|
||||
case *api.GenericResource_DiscreteResourceSpec:
|
||||
nrs := GetResource(na.DiscreteResourceSpec.Kind, nodeRes)
|
||||
|
||||
// Type change or removed: reset
|
||||
if len(nrs) != 1 {
|
||||
return false, nrs
|
||||
}
|
||||
|
||||
// Type change: reset
|
||||
nr := nrs[0].GetDiscreteResourceSpec()
|
||||
if nr == nil {
|
||||
return false, nrs
|
||||
}
|
||||
|
||||
// Amount change: reset
|
||||
if na.DiscreteResourceSpec.Value > nr.Value {
|
||||
return false, nrs
|
||||
}
|
||||
case *api.GenericResource_NamedResourceSpec:
|
||||
nrs := GetResource(na.NamedResourceSpec.Kind, nodeRes)
|
||||
|
||||
// Type change
|
||||
if len(nrs) == 0 {
|
||||
return false, nrs
|
||||
}
|
||||
|
||||
for _, nr := range nrs {
|
||||
// Type change: reset
|
||||
if nr.GetDiscreteResourceSpec() != nil {
|
||||
return false, nrs
|
||||
}
|
||||
|
||||
if na.NamedResourceSpec.Value == nr.GetNamedResourceSpec().Value {
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
|
||||
// Removed
|
||||
return false, nil
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
||||
54
vendor/github.com/moby/swarmkit/v2/api/genericresource/string.go
generated
vendored
54
vendor/github.com/moby/swarmkit/v2/api/genericresource/string.go
generated
vendored
@ -1,54 +0,0 @@
|
||||
package genericresource
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/moby/swarmkit/v2/api"
|
||||
)
|
||||
|
||||
func discreteToString(d *api.GenericResource_DiscreteResourceSpec) string {
|
||||
return strconv.FormatInt(d.DiscreteResourceSpec.Value, 10)
|
||||
}
|
||||
|
||||
// Kind returns the kind key as a string
|
||||
func Kind(res *api.GenericResource) string {
|
||||
switch r := res.Resource.(type) {
|
||||
case *api.GenericResource_DiscreteResourceSpec:
|
||||
return r.DiscreteResourceSpec.Kind
|
||||
case *api.GenericResource_NamedResourceSpec:
|
||||
return r.NamedResourceSpec.Kind
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
// Value returns the value key as a string
|
||||
func Value(res *api.GenericResource) string {
|
||||
switch res := res.Resource.(type) {
|
||||
case *api.GenericResource_DiscreteResourceSpec:
|
||||
return discreteToString(res)
|
||||
case *api.GenericResource_NamedResourceSpec:
|
||||
return res.NamedResourceSpec.Value
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
// EnvFormat returns the environment string version of the resource
|
||||
func EnvFormat(res []*api.GenericResource, prefix string) []string {
|
||||
envs := make(map[string][]string)
|
||||
for _, v := range res {
|
||||
key := Kind(v)
|
||||
val := Value(v)
|
||||
envs[key] = append(envs[key], val)
|
||||
}
|
||||
|
||||
env := make([]string, 0, len(res))
|
||||
for k, v := range envs {
|
||||
k = strings.ToUpper(prefix + "_" + k)
|
||||
env = append(env, k+"="+strings.Join(v, ","))
|
||||
}
|
||||
|
||||
return env
|
||||
}
|
||||
85
vendor/github.com/moby/swarmkit/v2/api/genericresource/validate.go
generated
vendored
85
vendor/github.com/moby/swarmkit/v2/api/genericresource/validate.go
generated
vendored
@ -1,85 +0,0 @@
|
||||
package genericresource
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/moby/swarmkit/v2/api"
|
||||
)
|
||||
|
||||
// ValidateTask validates that the task only uses integers
|
||||
// for generic resources
|
||||
func ValidateTask(resources *api.Resources) error {
|
||||
for _, v := range resources.Generic {
|
||||
if v.GetDiscreteResourceSpec() != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
return fmt.Errorf("invalid argument for resource %s", Kind(v))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// HasEnough returns true if node can satisfy the task's GenericResource request
|
||||
func HasEnough(nodeRes []*api.GenericResource, taskRes *api.GenericResource) (bool, error) {
|
||||
t := taskRes.GetDiscreteResourceSpec()
|
||||
if t == nil {
|
||||
return false, fmt.Errorf("task should only hold Discrete type")
|
||||
}
|
||||
|
||||
if nodeRes == nil {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
nrs := GetResource(t.Kind, nodeRes)
|
||||
if len(nrs) == 0 {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
switch nr := nrs[0].Resource.(type) {
|
||||
case *api.GenericResource_DiscreteResourceSpec:
|
||||
if t.Value > nr.DiscreteResourceSpec.Value {
|
||||
return false, nil
|
||||
}
|
||||
case *api.GenericResource_NamedResourceSpec:
|
||||
if t.Value > int64(len(nrs)) {
|
||||
return false, nil
|
||||
}
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// HasResource checks if there is enough "res" in the "resources" argument
|
||||
func HasResource(res *api.GenericResource, resources []*api.GenericResource) bool {
|
||||
for _, r := range resources {
|
||||
if Kind(res) != Kind(r) {
|
||||
continue
|
||||
}
|
||||
|
||||
switch rtype := r.Resource.(type) {
|
||||
case *api.GenericResource_DiscreteResourceSpec:
|
||||
if res.GetDiscreteResourceSpec() == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
if res.GetDiscreteResourceSpec().Value > rtype.DiscreteResourceSpec.Value {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
case *api.GenericResource_NamedResourceSpec:
|
||||
if res.GetNamedResourceSpec() == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
if res.GetNamedResourceSpec().Value != rtype.NamedResourceSpec.Value {
|
||||
continue
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
1
vendor/modules.txt
vendored
1
vendor/modules.txt
vendored
@ -214,7 +214,6 @@ github.com/moby/patternmatcher/ignorefile
|
||||
github.com/moby/swarmkit/v2/api
|
||||
github.com/moby/swarmkit/v2/api/deepcopy
|
||||
github.com/moby/swarmkit/v2/api/defaults
|
||||
github.com/moby/swarmkit/v2/api/genericresource
|
||||
github.com/moby/swarmkit/v2/manager/raftselector
|
||||
github.com/moby/swarmkit/v2/protobuf/plugin
|
||||
# github.com/moby/sys/atomicwriter v0.1.0
|
||||
|
||||
Reference in New Issue
Block a user