예제 #1
0
파일: helper.go 프로젝트: justintung/flynn
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
}
예제 #2
0
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
}
예제 #3
0
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)
}
예제 #4
0
파일: limit.go 프로젝트: devick/flynn
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
}
예제 #5
0
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
	}
}
예제 #6
0
	// 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))
예제 #7
0
파일: resource.go 프로젝트: devick/flynn
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))
	}
예제 #8
0
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)
	}
}
예제 #9
0
파일: resource.go 프로젝트: imjorge/flynn
func (r Resources) SetLimit(typ Type, size int64) {
	r[typ] = Spec{Request: typeconv.Int64Ptr(size), Limit: typeconv.Int64Ptr(size)}
}