Skip to content

Commit d600cb5

Browse files
menehune23ForestEckhardt
authored andcommitted
Adds service binding resolver
Signed-off-by: Brayan Henao <bhenao@vmware.com>
1 parent 6b22133 commit d600cb5

12 files changed

+1001
-163
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
.DS_Store
22
.idea
3+
coverage.out

postal/fakes/mapping_resolver.go

+5-5
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@ import "sync"
44

55
type MappingResolver struct {
66
FindDependencyMappingCall struct {
7-
sync.Mutex
7+
mutex sync.Mutex
88
CallCount int
99
Receives struct {
1010
SHA256 string
11-
BindingPath string
11+
PlatformDir string
1212
}
1313
Returns struct {
1414
String string
@@ -19,11 +19,11 @@ type MappingResolver struct {
1919
}
2020

2121
func (f *MappingResolver) FindDependencyMapping(param1 string, param2 string) (string, error) {
22-
f.FindDependencyMappingCall.Lock()
23-
defer f.FindDependencyMappingCall.Unlock()
22+
f.FindDependencyMappingCall.mutex.Lock()
23+
defer f.FindDependencyMappingCall.mutex.Unlock()
2424
f.FindDependencyMappingCall.CallCount++
2525
f.FindDependencyMappingCall.Receives.SHA256 = param1
26-
f.FindDependencyMappingCall.Receives.BindingPath = param2
26+
f.FindDependencyMappingCall.Receives.PlatformDir = param2
2727
if f.FindDependencyMappingCall.Stub != nil {
2828
return f.FindDependencyMappingCall.Stub(param1, param2)
2929
}

postal/internal/dependency_mappings.go

+20-35
Original file line numberDiff line numberDiff line change
@@ -2,51 +2,36 @@ package internal
22

33
import (
44
"fmt"
5-
"os"
6-
"path/filepath"
7-
"strings"
5+
"github.com/paketo-buildpacks/packit/servicebindings"
86
)
97

10-
type DependencyMappingResolver struct{}
8+
//go:generate faux --interface BindingResolver --output fakes/binding_resolver.go
9+
type BindingResolver interface {
10+
Resolve(typ, provider, platformDir string) ([]servicebindings.Binding, error)
11+
}
1112

12-
func NewDependencyMappingResolver() DependencyMappingResolver {
13-
return DependencyMappingResolver{}
13+
type DependencyMappingResolver struct {
14+
bindingResolver BindingResolver
1415
}
1516

16-
// Reference file structure for bindings directory
17-
// - bindings
18-
// - some-binding
19-
// - type -> dependency-mapping
20-
// - some-sha -> some-uri
21-
// - other-sha -> other-uri
17+
func NewDependencyMappingResolver(bindingResolver BindingResolver) DependencyMappingResolver {
18+
return DependencyMappingResolver{
19+
bindingResolver: bindingResolver,
20+
}
21+
}
2222

23-
// Given a target dependency, look up if there is a matching dependency mapping at the given binding path
24-
func (d DependencyMappingResolver) FindDependencyMapping(sha256, bindingPath string) (string, error) {
25-
allBindings, err := filepath.Glob(filepath.Join(bindingPath, "*"))
23+
// FindDependencyMapping looks up if there is a matching dependency mapping
24+
func (d DependencyMappingResolver) FindDependencyMapping(sha256, platformDir string) (string, error) {
25+
bindings, err := d.bindingResolver.Resolve("dependency-mapping", "", platformDir)
2626
if err != nil {
27-
return "", err
27+
return "", fmt.Errorf("failed to resolve 'dependency-mapping' binding: %w", err)
2828
}
2929

30-
for _, binding := range allBindings {
31-
bindType, err := os.ReadFile(filepath.Join(binding, "type"))
32-
if err != nil {
33-
return "", fmt.Errorf("couldn't read binding type: %w", err)
34-
}
35-
36-
if strings.TrimSpace(string(bindType)) == "dependency-mapping" {
37-
if _, err := os.Stat(filepath.Join(binding, sha256)); err != nil {
38-
if !os.IsNotExist(err) {
39-
return "", err
40-
}
41-
continue
42-
}
43-
44-
uri, err := os.ReadFile(filepath.Join(binding, sha256))
45-
if err != nil {
46-
return "", err
47-
}
48-
return strings.TrimSpace(string(uri)), nil
30+
for _, binding := range bindings {
31+
if uri, ok := binding.Entries[sha256]; ok {
32+
return uri.ReadString()
4933
}
5034
}
35+
5136
return "", nil
5237
}

postal/internal/dependency_mappings_test.go

+43-68
Original file line numberDiff line numberDiff line change
@@ -6,106 +6,81 @@ import (
66
"testing"
77

88
"github.com/paketo-buildpacks/packit/postal/internal"
9+
"github.com/paketo-buildpacks/packit/postal/internal/fakes"
10+
"github.com/paketo-buildpacks/packit/servicebindings"
911
"github.com/sclevine/spec"
1012

1113
. "github.com/onsi/gomega"
1214
)
1315

1416
func testDependencyMappings(t *testing.T, context spec.G, it spec.S) {
1517
var (
16-
Expect = NewWithT(t).Expect
17-
path string
18-
resolver internal.DependencyMappingResolver
19-
bindingPath string
20-
err error
18+
Expect = NewWithT(t).Expect
19+
tmpDir string
20+
resolver internal.DependencyMappingResolver
21+
bindingResolver *fakes.BindingResolver
22+
err error
2123
)
2224

2325
it.Before(func() {
24-
resolver = internal.NewDependencyMappingResolver()
25-
bindingPath, err = os.MkdirTemp("", "bindings")
26+
tmpDir, err = os.MkdirTemp("", "dependency-mappings")
27+
Expect(err).NotTo(HaveOccurred())
28+
Expect(os.WriteFile(filepath.Join(tmpDir, "entry-data"), []byte("dependency-mapping-entry.tgz"), os.ModePerm))
29+
30+
bindingResolver = &fakes.BindingResolver{}
31+
resolver = internal.NewDependencyMappingResolver(bindingResolver)
2632
Expect(err).NotTo(HaveOccurred())
2733
})
2834

2935
it.After(func() {
30-
Expect(os.RemoveAll(path)).To(Succeed())
36+
Expect(os.RemoveAll(tmpDir)).To(Succeed())
3137
})
3238

3339
context("FindDependencyMapping", func() {
3440
it.Before(func() {
35-
Expect(os.MkdirAll(filepath.Join(bindingPath, "some-binding"), 0700)).To(Succeed())
36-
Expect(os.WriteFile(filepath.Join(bindingPath, "some-binding", "type"), []byte("dependency-mapping"), 0600)).To(Succeed())
37-
Expect(os.WriteFile(filepath.Join(bindingPath, "some-binding", "some-sha"), []byte("dependency-mapping-entry.tgz"), 0600)).To(Succeed())
38-
39-
Expect(os.MkdirAll(filepath.Join(bindingPath, "other-binding"), 0700)).To(Succeed())
40-
Expect(os.WriteFile(filepath.Join(bindingPath, "other-binding", "type"), []byte("dependency-mapping"), 0600)).To(Succeed())
41-
Expect(os.WriteFile(filepath.Join(bindingPath, "other-binding", "other-sha"), []byte("dependency-mapping-entry.tgz"), 0600)).To(Succeed())
42-
43-
Expect(os.MkdirAll(filepath.Join(bindingPath, "another-binding"), 0700)).To(Succeed())
44-
Expect(os.WriteFile(filepath.Join(bindingPath, "another-binding", "type"), []byte("another type"), 0600)).To(Succeed())
45-
Expect(os.WriteFile(filepath.Join(bindingPath, "another-binding", "some-sha"), []byte("entry.tgz"), 0600)).To(Succeed())
41+
bindingResolver.ResolveCall.Returns.BindingSlice = []servicebindings.Binding{
42+
{
43+
Name: "some-binding",
44+
Path: "some-path",
45+
Type: "dependency-mapping",
46+
Entries: map[string]*servicebindings.Entry{
47+
"some-sha": servicebindings.NewEntry(filepath.Join(tmpDir, "entry-data")),
48+
},
49+
},
50+
{
51+
Name: "other-binding",
52+
Path: "other-path",
53+
Type: "dependency-mapping",
54+
Entries: map[string]*servicebindings.Entry{
55+
"other-sha": servicebindings.NewEntry("some-entry-path"),
56+
},
57+
},
58+
{
59+
Name: "another-binding",
60+
Path: "another-path",
61+
Type: "another-type",
62+
Entries: map[string]*servicebindings.Entry{},
63+
},
64+
}
4665
})
4766

4867
context("given a set of bindings and a dependency", func() {
4968
it("finds a matching dependency mappings in the platform bindings if there is one", func() {
50-
boundDependency, err := resolver.FindDependencyMapping("some-sha", bindingPath)
69+
boundDependency, err := resolver.FindDependencyMapping("some-sha", "some-platform-dir")
5170
Expect(err).ToNot(HaveOccurred())
71+
Expect(bindingResolver.ResolveCall.Receives.Typ).To(Equal("dependency-mapping"))
72+
Expect(bindingResolver.ResolveCall.Receives.Provider).To(BeEmpty())
73+
Expect(bindingResolver.ResolveCall.Receives.PlatformDir).To(Equal("some-platform-dir"))
5274
Expect(boundDependency).To(Equal("dependency-mapping-entry.tgz"))
5375
})
5476
})
5577

5678
context("given a set of bindings and a dependency", func() {
5779
it("returns an empty DependencyMapping if there is no match", func() {
58-
boundDependency, err := resolver.FindDependencyMapping("unmatched-sha", bindingPath)
80+
boundDependency, err := resolver.FindDependencyMapping("unmatched-sha", "")
5981
Expect(err).ToNot(HaveOccurred())
6082
Expect(boundDependency).To(Equal(""))
6183
})
6284
})
6385
})
64-
65-
context("failure cases", func() {
66-
context("when the binding path is a bad pattern", func() {
67-
it("errors", func() {
68-
_, err := resolver.FindDependencyMapping("some-sha", "///")
69-
Expect(err).To(HaveOccurred())
70-
})
71-
})
72-
73-
context("when type file cannot be opened", func() {
74-
it.Before(func() {
75-
Expect(os.MkdirAll(filepath.Join(bindingPath, "some-binding"), 0700)).To(Succeed())
76-
Expect(os.WriteFile(filepath.Join(bindingPath, "some-binding", "type"), []byte("dependency-mapping"), 0000)).To(Succeed())
77-
Expect(os.WriteFile(filepath.Join(bindingPath, "some-binding", "some-sha"), []byte("dependency-mapping-entry.tgz"), 0600)).To(Succeed())
78-
})
79-
it("errors", func() {
80-
_, err := resolver.FindDependencyMapping("some-sha", bindingPath)
81-
Expect(err).To(HaveOccurred())
82-
Expect(err).To(MatchError(ContainSubstring("couldn't read binding type")))
83-
})
84-
})
85-
86-
context("when SHA256 file cannot be stat", func() {
87-
it.Before(func() {
88-
Expect(os.MkdirAll(filepath.Join(bindingPath, "new-binding"), 0700)).To(Succeed())
89-
Expect(os.WriteFile(filepath.Join(bindingPath, "new-binding", "type"), []byte("dependency-mapping"), 0644)).To(Succeed())
90-
Expect(os.WriteFile(filepath.Join(bindingPath, "new-binding", "some-sha"), []byte("dependency-mapping-entry.tgz"), 0644)).To(Succeed())
91-
Expect(os.Chmod(filepath.Join(bindingPath, "new-binding", "some-sha"), 0000)).To(Succeed())
92-
})
93-
it("errors", func() {
94-
_, err := resolver.FindDependencyMapping("some-sha", bindingPath)
95-
Expect(err).To(HaveOccurred())
96-
})
97-
})
98-
99-
context("when SHA256 contents cannot be opened", func() {
100-
it.Before(func() {
101-
Expect(os.MkdirAll(filepath.Join(bindingPath, "some-binding"), 0700)).To(Succeed())
102-
Expect(os.WriteFile(filepath.Join(bindingPath, "some-binding", "type"), []byte("dependency-mapping"), 0600)).To(Succeed())
103-
Expect(os.WriteFile(filepath.Join(bindingPath, "some-binding", "some-sha"), []byte("dependency-mapping-entry.tgz"), 0000)).To(Succeed())
104-
})
105-
it("errors", func() {
106-
_, err := resolver.FindDependencyMapping("some-sha", bindingPath)
107-
Expect(err).To(HaveOccurred())
108-
})
109-
})
110-
})
11186
}
+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package fakes
2+
3+
import (
4+
"sync"
5+
6+
"github.com/paketo-buildpacks/packit/servicebindings"
7+
)
8+
9+
type BindingResolver struct {
10+
ResolveCall struct {
11+
mutex sync.Mutex
12+
CallCount int
13+
Receives struct {
14+
Typ string
15+
Provider string
16+
PlatformDir string
17+
}
18+
Returns struct {
19+
BindingSlice []servicebindings.Binding
20+
Error error
21+
}
22+
Stub func(string, string, string) ([]servicebindings.Binding, error)
23+
}
24+
}
25+
26+
func (f *BindingResolver) Resolve(param1 string, param2 string, param3 string) ([]servicebindings.Binding, error) {
27+
f.ResolveCall.mutex.Lock()
28+
defer f.ResolveCall.mutex.Unlock()
29+
f.ResolveCall.CallCount++
30+
f.ResolveCall.Receives.Typ = param1
31+
f.ResolveCall.Receives.Provider = param2
32+
f.ResolveCall.Receives.PlatformDir = param3
33+
if f.ResolveCall.Stub != nil {
34+
return f.ResolveCall.Stub(param1, param2, param3)
35+
}
36+
return f.ResolveCall.Returns.BindingSlice, f.ResolveCall.Returns.Error
37+
}

postal/service.go

+10-6
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,11 @@ import (
1010
"time"
1111

1212
"github.com/Masterminds/semver/v3"
13+
1314
"github.com/paketo-buildpacks/packit"
1415
"github.com/paketo-buildpacks/packit/cargo"
1516
"github.com/paketo-buildpacks/packit/postal/internal"
17+
"github.com/paketo-buildpacks/packit/servicebindings"
1618
"github.com/paketo-buildpacks/packit/vacation"
1719
)
1820

@@ -26,9 +28,9 @@ type Transport interface {
2628

2729
//go:generate faux --interface MappingResolver --output fakes/mapping_resolver.go
2830
// MappingResolver serves as the interface that looks up platform binding provided
29-
// dependency mappings given a SHA256 and a path to search for bindings
31+
// dependency mappings given a SHA256
3032
type MappingResolver interface {
31-
FindDependencyMapping(SHA256, bindingPath string) (string, error)
33+
FindDependencyMapping(SHA256, platformDir string) (string, error)
3234
}
3335

3436
// Service provides a mechanism for resolving and installing dependencies given
@@ -38,11 +40,13 @@ type Service struct {
3840
mappingResolver MappingResolver
3941
}
4042

41-
// NewService creates an instance of a Servicel given a Transport.
43+
// NewService creates an instance of a Service given a Transport.
4244
func NewService(transport Transport) Service {
4345
return Service{
44-
transport: transport,
45-
mappingResolver: internal.NewDependencyMappingResolver(),
46+
transport: transport,
47+
mappingResolver: internal.NewDependencyMappingResolver(
48+
servicebindings.NewResolver(),
49+
),
4650
}
4751
}
4852

@@ -140,7 +144,7 @@ func (s Service) Resolve(path, id, version, stack string) (Dependency, error) {
140144
// validated against the checksum value provided on the Dependency and will
141145
// error if there are inconsistencies in the fetched result.
142146
func (s Service) Deliver(dependency Dependency, cnbPath, layerPath, platformPath string) error {
143-
dependencyMappingURI, err := s.mappingResolver.FindDependencyMapping(dependency.SHA256, filepath.Join(platformPath, "bindings"))
147+
dependencyMappingURI, err := s.mappingResolver.FindDependencyMapping(dependency.SHA256, platformPath)
144148
if err != nil {
145149
return fmt.Errorf("failure checking for dependency mappings: %s", err)
146150
}

0 commit comments

Comments
 (0)