Skip to content

Commit

Permalink
Read bindings from VCAP_SERVICES (#228)
Browse files Browse the repository at this point in the history
Read bindings from VCAP_SERVICES

Signed-off-by: Ralf Pannemans <[email protected]>
  • Loading branch information
c0d1ngm0nk3y authored May 5, 2023
1 parent 8b7f797 commit 60df949
Show file tree
Hide file tree
Showing 3 changed files with 135 additions and 0 deletions.
40 changes: 40 additions & 0 deletions platform.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package libcnb

import (
"encoding/json"
"fmt"
"os"
"path/filepath"
Expand All @@ -41,6 +42,9 @@ const (
// See the Service Binding Specification for Kubernetes for more details - https://k8s-service-bindings.github.io/spec/
EnvServiceBindings = "SERVICE_BINDING_ROOT"

// EnvVcapServices is the name of the environment variable that contains the bindings in cloudfoundry
EnvVcapServices = "VCAP_SERVICES"

// EnvCNBBindings is the name of the environment variable that contains the path to the CNB bindings directory.
// See the CNB bindings extension spec for more details - https://github.com/buildpacks/spec/blob/main/extensions/bindings.md
//
Expand Down Expand Up @@ -113,6 +117,34 @@ func NewBindingFromPath(path string) (Binding, error) {
return NewBinding(filepath.Base(path), path, secret), nil
}

type vcapServicesBinding struct {
Name string `json:"name"`
Credentials map[string]string `json:"credentials"`
}

// NewBindingsFromVcapServicesEnv creates a new instance from all the bindings given from the VCAP_SERVICES.
func NewBindingsFromVcapServicesEnv(content string) (Bindings, error) {
var contentTyped map[string][]vcapServicesBinding

err := json.Unmarshal([]byte(content), &contentTyped)
if err != nil {
return Bindings{}, nil
}

bindings := Bindings{}
for t, bArray := range contentTyped {
for _, b := range bArray {
bindings = append(bindings, Binding{
Name: b.Name,
Type: t,
Secret: b.Credentials,
})
}
}

return bindings, nil
}

func (b Binding) String() string {
var s []string
for k := range b.Secret {
Expand Down Expand Up @@ -163,6 +195,10 @@ func NewBindingsForLaunch() (Bindings, error) {
return NewBindingsFromPath(path)
}

if content, ok := os.LookupEnv(EnvVcapServices); ok {
return NewBindingsFromVcapServicesEnv(content)
}

return Bindings{}, nil
}

Expand Down Expand Up @@ -201,6 +237,10 @@ func NewBindingsForBuild(platformDir string) (Bindings, error) {
if path, ok := os.LookupEnv(EnvCNBBindings); ok {
return NewBindingsFromPath(path)
}

if content, ok := os.LookupEnv(EnvVcapServices); ok {
return NewBindingsFromVcapServicesEnv(content)
}
return NewBindingsFromPath(filepath.Join(platformDir, "bindings"))
}

Expand Down
51 changes: 51 additions & 0 deletions platform_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,57 @@ func testPlatform(t *testing.T, context spec.G, it spec.S) {
path = filepath.Join(platformPath, "bindings")
})

context("Cloudfoundry VCAP_SERVICES", func() {
context("Build", func() {
it("creates a bindings from VCAP_SERVICES", func() {
content, err := os.ReadFile("testdata/vcap_services.json")
Expect(err).NotTo(HaveOccurred())
t.Setenv(libcnb.EnvVcapServices, string(content))

bindings, err := libcnb.NewBindingsForBuild("")
Expect(err).NotTo(HaveOccurred())

Expect(bindings).To(HaveLen(2))

types := []string{bindings[0].Type, bindings[1].Type}
Expect(types).To(ContainElements("elephantsql", "sendgrid"))
})

it("creates empty bindings from empty VCAP_SERVICES", func() {
t.Setenv(libcnb.EnvVcapServices, "{}")

bindings, err := libcnb.NewBindingsForBuild("")
Expect(err).NotTo(HaveOccurred())

Expect(bindings).To(HaveLen(0))
})
})

context("Launch", func() {
it("creates a bindings from VCAP_SERVICES", func() {
content, err := os.ReadFile("testdata/vcap_services.json")
Expect(err).NotTo(HaveOccurred())
t.Setenv(libcnb.EnvVcapServices, string(content))

bindings, err := libcnb.NewBindingsForLaunch()
Expect(err).NotTo(HaveOccurred())

Expect(bindings).To(HaveLen(2))
types := []string{bindings[0].Type, bindings[1].Type}
Expect(types).To(ContainElements("elephantsql", "sendgrid"))
})

it("creates empty bindings from empty VCAP_SERVICES", func() {
t.Setenv(libcnb.EnvVcapServices, "{}")

bindings, err := libcnb.NewBindingsForLaunch()
Expect(err).NotTo(HaveOccurred())

Expect(bindings).To(HaveLen(0))
})
})
})

context("CNB Bindings", func() {
it.Before(func() {
Expect(os.MkdirAll(filepath.Join(path, "alpha", "metadata"), 0755)).To(Succeed())
Expand Down
44 changes: 44 additions & 0 deletions testdata/vcap_services.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
{
"elephantsql": [
{
"name": "elephantsql-binding-c6c60",
"binding_guid": "44ceb72f-100b-4f50-87a2-7809c8b42b8d",
"binding_name": "elephantsql-binding-c6c60",
"instance_guid": "391308e8-8586-4c42-b464-c7831aa2ad22",
"instance_name": "elephantsql-c6c60",
"label": "elephantsql",
"tags": [
"postgres",
"postgresql",
"relational"
],
"plan": "turtle",
"credentials": {
"uri": "postgres://exampleuser:[email protected]:5432/exampleuser"
},
"syslog_drain_url": null,
"volume_mounts": []
}
],
"sendgrid": [
{
"name": "mysendgrid",
"binding_guid": "6533b1b6-7916-488d-b286-ca33d3fa0081",
"binding_name": null,
"instance_guid": "8c907d0f-ec0f-44e4-87cf-e23c9ba3925d",
"instance_name": "mysendgrid",
"label": "sendgrid",
"tags": [
"smtp"
],
"plan": "free",
"credentials": {
"hostname": "smtp.example.com",
"username": "QvsXMbJ3rK",
"password": "HCHMOYluTv"
},
"syslog_drain_url": null,
"volume_mounts": []
}
]
}

0 comments on commit 60df949

Please sign in to comment.