Merge pull request #35 from drone/implement-cpu-resource

Implement cpu resource
This commit is contained in:
Brad Rydzewski 2019-03-18 09:29:08 -07:00 committed by GitHub
commit f53100ba37
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 32 additions and 144 deletions

View File

@ -29,5 +29,5 @@ $ drone-yaml verify 642909eb4c3d47e33999235c0598353c samples/simple.yml
Compile the yaml file: Compile the yaml file:
```text ```text
$ drone-yaml compile samples/simple.yml > samples/simple.json $ drone-yaml compile samples/simple.yml samples/simple.json
``` ```

View File

@ -201,7 +201,6 @@ var (
password = compile.Flag("netrc-password", "netrc password").PlaceHolder("x-oauth-basic").String() password = compile.Flag("netrc-password", "netrc password").PlaceHolder("x-oauth-basic").String()
machine = compile.Flag("netrc-machine", "netrc machine").PlaceHolder("github.com").String() machine = compile.Flag("netrc-machine", "netrc machine").PlaceHolder("github.com").String()
memlimit = compile.Flag("mem-limit", "memory limit").PlaceHolder("1GB").Bytes() memlimit = compile.Flag("mem-limit", "memory limit").PlaceHolder("1GB").Bytes()
cpulimit = compile.Flag("cpu-limit", "cpu limit").PlaceHolder("2").Int64()
) )
func runCompile() error { func runCompile() error {
@ -269,7 +268,7 @@ func runCompile() error {
transform.WithEnviron(*environ), transform.WithEnviron(*environ),
transform.WithEnviron(defaultEnvs()), transform.WithEnviron(defaultEnvs()),
transform.WithLables(*labels), transform.WithLables(*labels),
transform.WithLimits(int64(*memlimit), int64(*cpulimit)), transform.WithLimits(int64(*memlimit), 0),
transform.WithNetrc(*machine, *username, *password), transform.WithNetrc(*machine, *username, *password),
transform.WithNetworks(*network), transform.WithNetworks(*network),
transform.WithProxy(), transform.WithProxy(),

View File

@ -84,7 +84,14 @@ func toResourceObject(from *yaml.ResourceObject) *engine.ResourceObject {
return nil return nil
} }
return &engine.ResourceObject{ return &engine.ResourceObject{
CPU: int64(from.CPU), CPU: toCPUMillis(from.CPU),
Memory: int64(from.Memory), Memory: int64(from.Memory),
} }
} }
func toCPUMillis(f float64) int64 {
if f > 0 {
f *= 1000
}
return int64(f)
}

View File

@ -136,9 +136,11 @@ func Test_toResources(t *testing.T) {
Resources: &yaml.Resources{ Resources: &yaml.Resources{
Limits: &yaml.ResourceObject{ Limits: &yaml.ResourceObject{
Memory: yaml.BytesSize(1000), Memory: yaml.BytesSize(1000),
CPU: 4,
}, },
Requests: &yaml.ResourceObject{ Requests: &yaml.ResourceObject{
Memory: yaml.BytesSize(2000), Memory: yaml.BytesSize(2000),
CPU: 0.1,
}, },
}, },
} }
@ -146,9 +148,11 @@ func Test_toResources(t *testing.T) {
b = &engine.Resources{ b = &engine.Resources{
Limits: &engine.ResourceObject{ Limits: &engine.ResourceObject{
Memory: 1000, Memory: 1000,
CPU: 4000,
}, },
Requests: &engine.ResourceObject{ Requests: &engine.ResourceObject{
Memory: 2000, Memory: 2000,
CPU: 100,
}, },
} }
if diff := cmp.Diff(a, b); diff != "" { if diff := cmp.Diff(a, b); diff != "" {

View File

@ -1,4 +1,3 @@
// Copyright Jesse Haka.
// Copyright the Drone Authors. // Copyright the Drone Authors.
// //
// Licensed under the Apache License, Version 2.0 (the "License"); // Licensed under the Apache License, Version 2.0 (the "License");
@ -19,7 +18,7 @@ import "github.com/drone/drone-runtime/engine"
// WithLimits is a transform function that applies // WithLimits is a transform function that applies
// resource limits to the container processes. // resource limits to the container processes.
func WithLimits(memlimit int64, cpulimit int64) func(*engine.Spec) { func WithLimits(memlimit, cpulimit int64) func(*engine.Spec) {
return func(spec *engine.Spec) { return func(spec *engine.Spec) {
// if no limits are defined exit immediately. // if no limits are defined exit immediately.
if memlimit == 0 && cpulimit == 0 { if memlimit == 0 && cpulimit == 0 {
@ -34,12 +33,8 @@ func WithLimits(memlimit int64, cpulimit int64) func(*engine.Spec) {
if step.Resources.Limits == nil { if step.Resources.Limits == nil {
step.Resources.Limits = &engine.ResourceObject{} step.Resources.Limits = &engine.ResourceObject{}
} }
if memlimit != 0 {
step.Resources.Limits.Memory = memlimit step.Resources.Limits.Memory = memlimit
} step.Resources.Limits.CPU = cpulimit
if cpulimit != 0 {
step.Resources.Limits.CPU = cpulimit * 1000
}
} }
} }
} }

View File

@ -1,4 +1,3 @@
// Copyright Jesse Haka.
// Copyright the Drone Authors. // Copyright the Drone Authors.
// //
// Licensed under the Apache License, Version 2.0 (the "License"); // Licensed under the Apache License, Version 2.0 (the "License");
@ -36,47 +35,7 @@ func TestWithLimits(t *testing.T) {
if got, want := step.Resources.Limits.Memory, int64(1); got != want { if got, want := step.Resources.Limits.Memory, int64(1); got != want {
t.Errorf("Want memory limit %v, got %v", want, got) t.Errorf("Want memory limit %v, got %v", want, got)
} }
if got, want := step.Resources.Limits.CPU, int64(2000); got != want { if got, want := step.Resources.Limits.CPU, int64(2); got != want {
t.Errorf("Want cpu limit %v, got %v", want, got)
}
}
func TestWithMemory(t *testing.T) {
step := &engine.Step{
Metadata: engine.Metadata{
UID: "1",
Name: "build",
},
Docker: &engine.DockerStep{},
}
spec := &engine.Spec{
Steps: []*engine.Step{step},
}
WithLimits(1, 0)(spec)
if got, want := step.Resources.Limits.Memory, int64(1); got != want {
t.Errorf("Want memory limit %v, got %v", want, got)
}
if got, want := step.Resources.Limits.CPU, int64(0); got != want {
t.Errorf("Want cpu limit %v, got %v", want, got)
}
}
func TestWithCPU(t *testing.T) {
step := &engine.Step{
Metadata: engine.Metadata{
UID: "1",
Name: "build",
},
Docker: &engine.DockerStep{},
}
spec := &engine.Spec{
Steps: []*engine.Step{step},
}
WithLimits(0, 3)(spec)
if got, want := step.Resources.Limits.Memory, int64(0); got != want {
t.Errorf("Want memory limit %v, got %v", want, got)
}
if got, want := step.Resources.Limits.CPU, int64(3000); got != want {
t.Errorf("Want cpu limit %v, got %v", want, got) t.Errorf("Want cpu limit %v, got %v", want, got)
} }
} }

View File

@ -97,7 +97,7 @@ type (
// ResourceObject describes compute resource // ResourceObject describes compute resource
// requirements. // requirements.
ResourceObject struct { ResourceObject struct {
CPU MilliSize `json:"cpu"` CPU float64 `json:"cpu" yaml:"cpu"`
Memory BytesSize `json:"memory"` Memory BytesSize `json:"memory"`
} }

View File

@ -11,5 +11,5 @@ steps:
cpu: 2 cpu: 2
memory: '100Mi' memory: '100Mi'
requests: requests:
cpu: 100m cpu: 1
memory: '50Mi' memory: '50Mi'

View File

@ -13,10 +13,10 @@ steps:
- go build - go build
resources: resources:
limits: limits:
cpu: 2000 cpu: 2
memory: 100MiB memory: 100MiB
requests: requests:
cpu: 100 cpu: 1
memory: 50MiB memory: 50MiB
... ...

View File

@ -18,12 +18,10 @@ import "github.com/drone/drone-yaml/yaml"
func isPrimative(v interface{}) bool { func isPrimative(v interface{}) bool {
switch v.(type) { switch v.(type) {
case bool, string, int, float64: case bool, string, int, int64, float64:
return true return true
case yaml.BytesSize: case yaml.BytesSize:
return true return true
case yaml.MilliSize:
return true
default: default:
return false return false
} }

View File

@ -183,6 +183,12 @@ func writeInt(w writer, v int) {
) )
} }
func writeInt64(w writer, v int64) {
w.WriteString(
strconv.FormatInt(v, 10),
)
}
func writeEncode(w writer, v string) { func writeEncode(w writer, v string) {
if len(v) == 0 { if len(v) == 0 {
w.WriteByte('"') w.WriteByte('"')
@ -204,7 +210,7 @@ func writeValue(w writer, v interface{}) {
return return
} }
switch v := v.(type) { switch v := v.(type) {
case bool, int, float64, string: case bool, int, int64, float64, string:
writeScalar(w, v) writeScalar(w, v)
case []interface{}: case []interface{}:
writeSequence(w, v) writeSequence(w, v)
@ -216,8 +222,6 @@ func writeValue(w writer, v interface{}) {
writeMappingStr(w, v) writeMappingStr(w, v)
case yaml.BytesSize: case yaml.BytesSize:
writeValue(w, v.String()) writeValue(w, v.String())
case yaml.MilliSize:
writeValue(w, v.String())
} }
} }
@ -227,6 +231,8 @@ func writeScalar(w writer, v interface{}) {
writeBool(w, v) writeBool(w, v)
case int: case int:
writeInt(w, v) writeInt(w, v)
case int64:
writeInt64(w, v)
case float64: case float64:
writeFloat(w, v) writeFloat(w, v)
case string: case string:

View File

@ -1,4 +1,3 @@
// Copyright Jesse Haka.
// Copyright the Drone Authors. // Copyright the Drone Authors.
// //
// Licensed under the Apache License, Version 2.0 (the "License"); // Licensed under the Apache License, Version 2.0 (the "License");
@ -16,9 +15,6 @@
package yaml package yaml
import ( import (
"strconv"
"strings"
"github.com/docker/go-units" "github.com/docker/go-units"
) )
@ -53,39 +49,3 @@ func (b *BytesSize) UnmarshalYAML(unmarshal func(interface{}) error) error {
func (b BytesSize) String() string { func (b BytesSize) String() string {
return units.BytesSize(float64(b)) return units.BytesSize(float64(b))
} }
// MilliSize will convert cpus to millicpus as int64.
// for instance "1" will be converted to 1000 and "100m" to 100
type MilliSize int64
// UnmarshalYAML implements yaml unmarshalling.
func (m *MilliSize) UnmarshalYAML(unmarshal func(interface{}) error) error {
var intType int64
if err := unmarshal(&intType); err == nil {
*m = MilliSize(intType * 1000)
return nil
}
var stringType string
if err := unmarshal(&stringType); err != nil {
return err
}
if len(stringType) > 0 {
lastChar := string(stringType[len(stringType)-1:])
if lastChar == "m" {
// convert to int64
i, err := strconv.ParseInt(strings.TrimSuffix(stringType, "m"), 10, 64)
if err != nil {
return err
}
*m = MilliSize(i)
}
}
return nil
}
// String returns a human-readable cpu millis,
// (eg. "1000", "10").
func (m MilliSize) String() string {
return strconv.FormatInt(int64(m), 10)
}

View File

@ -1,4 +1,3 @@
// Copyright Jesse Haka.
// Copyright the Drone Authors. // Copyright the Drone Authors.
// //
// Licensed under the Apache License, Version 2.0 (the "License"); // Licensed under the Apache License, Version 2.0 (the "License");
@ -59,42 +58,3 @@ func TestBytesSize(t *testing.T) {
} }
} }
} }
func TestMilliSize(t *testing.T) {
tests := []struct {
yaml string
size int64
text string
}{
{
yaml: "100m",
size: 100,
text: "100",
},
{
yaml: "1",
size: 1000,
text: "1000",
},
{
yaml: "0m",
size: 0,
text: "0",
},
}
for _, test := range tests {
in := []byte(test.yaml)
out := MilliSize(0)
err := yaml.Unmarshal(in, &out)
if err != nil {
t.Error(err)
return
}
if got, want := int64(out), test.size; got != want {
t.Errorf("Want millis %d, got %d", want, got)
}
if got, want := out.String(), test.text; got != want {
t.Errorf("Want text %s, got %s", want, got)
}
}
}