func testResources() resource.Resources { r := resource.Resources{ resource.TypeMemory: resource.Spec{Limit: typeconv.Int64Ptr(resourceMem)}, resource.TypeMaxFD: resource.Spec{Limit: typeconv.Int64Ptr(resourceMaxFD)}, } resource.SetDefaults(&r) return r }
func (r *Runner) uploadToS3(file *os.File, b *Build, boundary string) string { name := fmt.Sprintf("%s-build-%s-%s.txt", b.ID, b.Commit, time.Now().Format("2006-01-02-15-04-05")) url := fmt.Sprintf("https://s3.amazonaws.com/%s/%s", logBucket, name) if _, err := file.Seek(0, os.SEEK_SET); err != nil { log.Printf("failed to seek log file: %s\n", err) return "" } stat, err := file.Stat() if err != nil { log.Printf("failed to get log file size: %s\n", err) return "" } log.Printf("uploading build log to S3: %s\n", url) if err := s3attempts.Run(func() error { contentType := "multipart/mixed; boundary=" + boundary acl := "public-read" _, err := r.s3.PutObject(&s3.PutObjectRequest{ Key: &name, Body: file, Bucket: &logBucket, ACL: &acl, ContentType: &contentType, ContentLength: typeconv.Int64Ptr(stat.Size()), }) return err }); err != nil { log.Printf("failed to upload build output to S3: %s\n", err) } return url }
func (S) TestSetDefaultsRequest(c *C) { // not specifying Request should default it to the value of Limit r := Resources{TypeMemory: Spec{Limit: typeconv.Int64Ptr(512 * units.MiB)}} SetDefaults(&r) assertDefault(c, r, TypeMaxFD) mem, ok := r[TypeMemory] if !ok { c.Fatal("memory resource not set") } c.Assert(*mem.Request, Equals, *mem.Limit) }
func runLimitSet(args *docopt.Args, client *controller.Client) error { proc := args.String["<proc>"] release, err := client.GetAppRelease(mustApp()) if err == controller.ErrNotFound { release = &ct.Release{} if proc != "" { release.Processes = make(map[string]ct.ProcessType) release.Processes[proc] = ct.ProcessType{} } } else if err != nil { return err } t, ok := release.Processes[proc] if !ok { return fmt.Errorf("unknown process type %q", proc) } if t.Resources == nil { t.Resources = resource.Defaults() } limits := args.All["<var>=<val>"].([]string) for _, limit := range limits { typVal := strings.SplitN(limit, "=", 2) if len(typVal) != 2 { return fmt.Errorf("invalid resource limit: %q", limit) } typ, ok := resource.ToType(typVal[0]) if !ok { return fmt.Errorf("invalid resource limit type: %q", typVal) } val, err := resource.ParseLimit(typ, typVal[1]) if err != nil { return fmt.Errorf("invalid resource limit value: %q", typVal[1]) } t.Resources[typ] = resource.Spec{Limit: typeconv.Int64Ptr(val)} } release.Processes[proc] = t release.ID = "" if err := client.CreateRelease(release); err != nil { return err } if err := client.DeployAppRelease(mustApp(), release.ID); err != nil { return err } fmt.Printf("Created release %s\n", release.ID) return nil }
func SetDefaults(r *Resources) { if *r == nil { *r = make(Resources, len(defaults)) } for typ, s := range defaults { spec := (*r)[typ] if spec.Limit == nil { spec.Limit = typeconv.Int64Ptr(*s.Limit) } if spec.Request == nil { spec.Request = spec.Limit } (*r)[typ] = spec } }
// TypeCPU specifies the amount of milliCPU requested. A milliCPU is // conceptually 1/1000 of a CPU core (eg 500m is half of a CPU core). In // practice, a 1000 milliCPU limit is equivalent to 1024 CPU shares. TypeCPU Type = "cpu" // TypeMaxFD specifies a value one greater than the maximum file // descriptor number that can be opened inside a container. TypeMaxFD Type = "max_fd" // TypeMaxProcs specifies the maximum number of processes which can // be started inside a container. TypeMaxProcs Type = "max_procs" ) var defaults = Resources{ TypeMemory: {Request: typeconv.Int64Ptr(1 * units.GiB), Limit: typeconv.Int64Ptr(1 * units.GiB)}, TypeCPU: {Limit: typeconv.Int64Ptr(1000)}, // results in Linux default of 1024 shares TypeMaxFD: {Request: typeconv.Int64Ptr(10000), Limit: typeconv.Int64Ptr(10000)}, } type Resources map[Type]Spec func Defaults() Resources { r := make(Resources) SetDefaults(&r) return r } func SetDefaults(r *Resources) { if *r == nil { *r = make(Resources, len(defaults))
const ( // TypeMemory specifies the available memory in bytes inside a container. TypeMemory Type = "memory" // TypeMaxFD specifies a value one greater than the maximum file // descriptor number that can be opened inside a container. TypeMaxFD Type = "max_fd" // TypeMaxProcs specifies the maximum number of processes which can // be started inside a container. TypeMaxProcs Type = "max_procs" ) var defaults = Resources{ TypeMemory: {Request: typeconv.Int64Ptr(1 * units.GiB), Limit: typeconv.Int64Ptr(1 * units.GiB)}, TypeMaxFD: {Request: typeconv.Int64Ptr(10000), Limit: typeconv.Int64Ptr(10000)}, } type Resources map[Type]Spec func Defaults() Resources { r := make(Resources) SetDefaults(&r) return r } func SetDefaults(r *Resources) { if *r == nil { *r = make(Resources, len(defaults)) }
func (s *S) TestFlynnArtifact(c *C) { manifest := &ct.ImageManifest{Type: ct.ImageManifestTypeV1} type test struct { desc string artifact *ct.Artifact manifest *ct.ImageManifest hashes map[string]string size *int64 handler http.HandlerFunc assert func(*test, error) } isValid := func(t *test, err error) { c.Assert(err, IsNil) gotArtifact, err := s.c.GetArtifact(t.artifact.ID) c.Assert(err, IsNil) c.Assert(gotArtifact, DeepEquals, t.artifact) } isValidationErr := func(field, message string) func(*test, error) { return func(t *test, err error) { c.Assert(err, NotNil) e, ok := err.(hh.JSONError) if !ok { c.Fatalf("expected JSONError, got %T", err) } c.Assert(e.Code, Equals, hh.ValidationErrorCode) c.Assert(e.Message, Matches, fmt.Sprintf("%s.*%s", field, message)) } } isHashMismatchErr := func(t *test, err error) { message := fmt.Sprintf(`expected sha512_256 hash %q but got ".*"`, manifest.Hashes()["sha512_256"]) isValidationErr("manifest", message)(t, err) } mux := http.NewServeMux() var handler http.HandlerFunc mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) { handler(w, req) }) srv := httptest.NewServer(mux) defer srv.Close() for _, t := range []*test{ { desc: "zero size", size: typeconv.Int64Ptr(0), assert: isValidationErr("size", "must be greater than zero"), }, { desc: "negative size", size: typeconv.Int64Ptr(-1), assert: isValidationErr("size", "must be greater than zero"), }, { desc: "no hashes", hashes: map[string]string{}, assert: isValidationErr("manifest", "no hashes provided"), }, { desc: "unknown algorithm", hashes: map[string]string{"foo": "bar"}, assert: isValidationErr("manifest", "no hashes provided"), }, { desc: "known and unknown algorithm", manifest: manifest, hashes: map[string]string{ "sha512_256": manifest.Hashes()["sha512_256"], "foo": "bar", }, assert: isValid, }, { desc: "non-200 HTTP response", handler: func(w http.ResponseWriter, _ *http.Request) { w.WriteHeader(500) }, assert: isValidationErr("manifest", "unexpected HTTP status: 500 Internal Server Error"), }, { desc: "manifest too short", manifest: &ct.ImageManifest{}, assert: isValidationErr("manifest", "data too short"), }, { desc: "manifest too big", manifest: &ct.ImageManifest{ Type: ct.ImageManifestTypeV1, Meta: map[string]string{"foo": "bar"}, }, assert: isHashMismatchErr, }, { desc: "manifest different bytes", manifest: &ct.ImageManifest{ Type: ct.ImageManifestType(strings.Replace(string(ct.ImageManifestTypeV1), "v", "w", 1)), }, assert: isHashMismatchErr, }, { desc: "valid manifest", manifest: manifest, assert: isValid, }, } { c.Logf("testing %s", t.desc) t.artifact = &ct.Artifact{ Type: ct.ArtifactTypeFlynn, URI: srv.URL, Hashes: t.hashes, } if t.size == nil { data, _ := cjson.Marshal(manifest) t.artifact.Size = int64(len(data)) } if t.hashes == nil { t.artifact.Hashes = manifest.Hashes() } if t.manifest != nil { handler = func(w http.ResponseWriter, req *http.Request) { w.Write(t.manifest.RawManifest()) } } else { handler = t.handler } err := s.c.CreateArtifact(t.artifact) t.assert(t, err) } }
func (r Resources) SetLimit(typ Type, size int64) { r[typ] = Spec{Request: typeconv.Int64Ptr(size), Limit: typeconv.Int64Ptr(size)} }