Skip to content
This repository was archived by the owner on Nov 16, 2020. It is now read-only.

Commit

Permalink
Move source out of function entity and into its own entity store (#548)
Browse files Browse the repository at this point in the history
* Move source out of function entity and into its own entity store.

* Moved source url out of source entity and into function entity.

Removed the need for a separate sourceEntityHandler controller.
  • Loading branch information
rjew authored and berndtj committed Jul 17, 2018
1 parent 423d27f commit 937dff1
Show file tree
Hide file tree
Showing 12 changed files with 321 additions and 47 deletions.
18 changes: 3 additions & 15 deletions pkg/api/v1/function.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,11 @@ import (
type Function struct {

// source
// Required: true
Source strfmt.Base64 `json:"source,omitempty"`

// sourceURL
SourceURL string `json:"sourceURL,omitempty"`

// only used in seed.yaml
SourcePath string `json:"sourcePath,omitempty"`

Expand Down Expand Up @@ -87,11 +89,6 @@ type Function struct {
func (m *Function) Validate(formats strfmt.Registry) error {
var res []error

if err := m.validateSource(formats); err != nil {
// prop
res = append(res, err)
}

if err := m.validateFaasID(formats); err != nil {
// prop
res = append(res, err)
Expand Down Expand Up @@ -148,15 +145,6 @@ func (m *Function) Validate(formats strfmt.Registry) error {
return nil
}

func (m *Function) validateSource(formats strfmt.Registry) error {

if err := validate.Required("source", "body", m.Source); err != nil {
return err
}

return nil
}

func (m *Function) validateFaasID(formats strfmt.Registry) error {

if swag.IsZero(m.FaasID) { // not required
Expand Down
51 changes: 50 additions & 1 deletion pkg/function-manager/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,12 @@ func (h *funcEntityHandler) Add(ctx context.Context, obj entitystore.Entity) (er
h.Store.UpdateWithError(ctx, e, err)
}()

code, err := h.resolveSourceURL(ctx, e.OrganizationID, e.SourceURL)
if err != nil {
log.Debugf("failed to retrieve source because of %s", err)
return errors.Wrap(err, "store error when retrieving source")
}

img, err := h.getImage(ctx, e.OrganizationID, e.ImageName)
if err != nil {
return errors.Wrapf(err, "Error when fetching image for function %s", e.Name)
Expand All @@ -70,7 +76,7 @@ func (h *funcEntityHandler) Add(ctx context.Context, obj entitystore.Entity) (er
e.Status = entitystore.StatusCREATING
h.Store.UpdateWithError(ctx, e, nil)

e.FunctionImageURL, err = h.ImageBuilder.BuildImage(ctx, e)
e.FunctionImageURL, err = h.ImageBuilder.BuildImage(ctx, e, code)
if err != nil {
return errors.Wrapf(err, "Error building image for function '%s'", e.ID)
}
Expand All @@ -84,6 +90,33 @@ func (h *funcEntityHandler) Add(ctx context.Context, obj entitystore.Entity) (er
return
}

func (h *funcEntityHandler) resolveSourceURL(ctx context.Context, organizationID string, sourceURL string) ([]byte, error) {
span, ctx := trace.Trace(ctx, "")
defer span.Finish()

scheme, err := getScheme(sourceURL)
if err != nil {
return nil, errors.Wrapf(err, "Error when parsing scheme from source url %s", sourceURL)
}
switch scheme {
case entityScheme:
s := new(functions.Source)
sourceName, err := getURLWithoutScheme(sourceURL)
if err != nil {
return nil, errors.Wrapf(err, "Error when parsing source url %s", sourceURL)
}

if err := h.Store.Get(ctx, organizationID, sourceName, entitystore.Options{}, s); err != nil {
log.Debugf("Error returned by h.Store.Get: %+v", err)
return nil, errors.Wrapf(err, "Failed to retreive source %s", sourceName)
}

return s.Code, nil
default:
return nil, errors.Errorf("Received non-supported source url %s", sourceURL)
}
}

// Update updates functions (and function images) for the configured FaaS
// TODO: we are leaking images... the images should be deleted from the image
// repository
Expand Down Expand Up @@ -119,6 +152,22 @@ func (h *funcEntityHandler) Delete(ctx context.Context, obj entitystore.Entity)
}
}

scheme, err := getScheme(e.SourceURL)
if err != nil {
return errors.Wrapf(err, "Error when parsing scheme from source url %s", e.SourceURL)
}
if scheme == entityScheme {
sourceName, err := getURLWithoutScheme(e.SourceURL)
if err != nil {
return errors.Wrapf(err, "Error when parsing source url %s", e.SourceURL)
}
var s functions.Source
if err := h.Store.Delete(ctx, e.OrganizationID, sourceName, &s); err != nil {
log.Debugf("fail to delete entity because of %s", err)
return errors.Wrap(err, "store error when deleting source")
}
}

log.Debugf("trying to delete entity=%s, org=%s, id=%s, status=%s\n", e.Name, e.OrganizationID, e.ID, e.Status)
if err := h.Store.Delete(ctx, e.OrganizationID, e.Name, e); err != nil {
log.Debugf("fail to delete entity because of %s", err)
Expand Down
28 changes: 25 additions & 3 deletions pkg/function-manager/controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,13 @@ func TestFuncEntityHandler_Add_ImageNotReady(t *testing.T) {
Status: v1.StatusINITIALIZED,
}, nil)
faas := &fnmocks.FaaSDriver{}
source := &functions.Source{
BaseEntity: entitystore.BaseEntity{
Name: "sourceName",
OrganizationID: testOrgID,
},
Code: []byte("some source"),
}
function := &functions.Function{
BaseEntity: entitystore.BaseEntity{
Name: "testFunction",
Expand All @@ -39,6 +46,7 @@ func TestFuncEntityHandler_Add_ImageNotReady(t *testing.T) {
},
ImageName: "testImage",
Handler: "main",
SourceURL: entityScheme + schemeSeparator + source.Name,
}

h := &funcEntityHandler{
Expand All @@ -47,7 +55,10 @@ func TestFuncEntityHandler_Add_ImageNotReady(t *testing.T) {
ImgClient: imgMgr,
}

_, err := h.Store.Add(context.Background(), function)
_, err := h.Store.Add(context.Background(), source)
require.NoError(t, err)

_, err = h.Store.Add(context.Background(), function)
require.NoError(t, err)

require.NoError(t, h.Add(context.Background(), function))
Expand All @@ -65,6 +76,13 @@ func TestFuncEntityHandler_Add_ImageReady(t *testing.T) {
Status: v1.StatusREADY,
}, nil)
faas := &fnmocks.FaaSDriver{}
source := &functions.Source{
BaseEntity: entitystore.BaseEntity{
Name: "sourceName",
OrganizationID: testOrgID,
},
Code: []byte("some source"),
}
function := &functions.Function{
BaseEntity: entitystore.BaseEntity{
Name: "testFunction",
Expand All @@ -74,11 +92,12 @@ func TestFuncEntityHandler_Add_ImageReady(t *testing.T) {
ImageName: "testImage",
ImageURL: "test/image:latest",
Handler: "main",
SourceURL: entityScheme + schemeSeparator + source.Name,
}
faas.On("Create", mock.Anything, function).Return(nil)

imageBuilder := &fnmocks.ImageBuilder{}
imageBuilder.On("BuildImage", mock.Anything, mock.Anything).Return("fake-image:latest", nil)
imageBuilder.On("BuildImage", mock.Anything, mock.Anything, mock.Anything).Return("fake-image:latest", nil)

h := &funcEntityHandler{
Store: helpers.MakeEntityStore(t),
Expand All @@ -87,7 +106,10 @@ func TestFuncEntityHandler_Add_ImageReady(t *testing.T) {
ImageBuilder: imageBuilder,
}

_, err := h.Store.Add(context.Background(), function)
_, err := h.Store.Add(context.Background(), source)
require.NoError(t, err)

_, err = h.Store.Add(context.Background(), function)
require.NoError(t, err)

require.NoError(t, h.Add(context.Background(), function))
Expand Down
6 changes: 5 additions & 1 deletion pkg/function-manager/gen/restapi/embedded_spec.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 937dff1

Please sign in to comment.