-
Notifications
You must be signed in to change notification settings - Fork 3
Add support for setting DATABASE_URL from vcap services #123
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,48 @@ | ||
| package databaseuri | ||
|
|
||
| import ( | ||
| "encoding/json" | ||
| "net/url" | ||
| ) | ||
|
|
||
| func ParseDatabaseURI(services string) (string, error) { | ||
| if services == "" { | ||
| return "", nil | ||
| } | ||
|
|
||
| data := map[string][]struct { | ||
| Credentials struct { | ||
| Uri string `json:"uri"` | ||
| } `json:"credentials"` | ||
| }{} | ||
| if err := json.Unmarshal([]byte(services), &data); err != nil { | ||
| return "", err | ||
| } | ||
|
|
||
| var creds []string | ||
| for _, v1 := range data { | ||
| for _, v2 := range v1 { | ||
| if v2.Credentials.Uri != "" { | ||
| creds = append(creds, v2.Credentials.Uri) | ||
| } | ||
| } | ||
| } | ||
|
|
||
| schemes := map[string]string{ | ||
| "mysql": "mysql2", | ||
| "mysql2": "", | ||
| "postgres": "", | ||
| "postgresql": "postgres", | ||
| } | ||
| for _, service_uri := range creds { | ||
| if uri, err := url.Parse(service_uri); err == nil { | ||
| if val, ok := schemes[uri.Scheme]; ok { | ||
| if val != "" { | ||
| uri.Scheme = val | ||
| } | ||
| return uri.String(), nil | ||
| } | ||
| } | ||
| } | ||
| return "", nil | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,110 @@ | ||
| package databaseuri_test | ||
|
|
||
| import ( | ||
| "testing" | ||
|
|
||
| "code.cloudfoundry.org/cnbapplifecycle/pkg/databaseuri" | ||
| . "github.com/onsi/ginkgo/v2" | ||
| . "github.com/onsi/gomega" | ||
| ) | ||
|
|
||
| func TestDatabaseuri(t *testing.T) { | ||
| RegisterFailHandler(Fail) | ||
| RunSpecs(t, "Databaseuri Suite") | ||
| } | ||
|
|
||
| var _ = Describe("ParseDatabaseURI", func() { | ||
| It("ignores services without credentials.uri", func() { | ||
| services := `{"eg":[{}]}` | ||
| uri, err := databaseuri.ParseDatabaseURI(services) | ||
| Expect(err).NotTo(HaveOccurred()) | ||
| Expect(uri).To(BeEmpty()) | ||
| }) | ||
|
|
||
| It("returns empty when there are non relational database services", func() { | ||
| services := `{"eg":[{"credentials":{"uri":"sendgrid://foo:bar@host/db"}}]}` | ||
| uri, err := databaseuri.ParseDatabaseURI(services) | ||
| Expect(err).NotTo(HaveOccurred()) | ||
| Expect(uri).To(BeEmpty()) | ||
| }) | ||
|
|
||
| It("returns empty when there are no services", func() { | ||
| services := "{}" | ||
| uri, err := databaseuri.ParseDatabaseURI(services) | ||
| Expect(err).NotTo(HaveOccurred()) | ||
| Expect(uri).To(BeEmpty()) | ||
| }) | ||
|
|
||
| It("returns empty when services are empty", func() { | ||
| services := "" | ||
| uri, err := databaseuri.ParseDatabaseURI(services) | ||
| Expect(err).NotTo(HaveOccurred()) | ||
| Expect(uri).To(BeEmpty()) | ||
| }) | ||
|
|
||
| Context("when there are relational database services", func() { | ||
| Context("with a mysql URI", func() { | ||
| It("changes the scheme to mysql2", func() { | ||
| services := `{"eg":[{"credentials":{"uri":"mysql://username:password@host/db"}}]}` | ||
| uri, err := databaseuri.ParseDatabaseURI(services) | ||
| Expect(err).NotTo(HaveOccurred()) | ||
| Expect(uri).To(Equal("mysql2://username:password@host/db")) | ||
| }) | ||
| }) | ||
| Context("with a mysql2 URI", func() { | ||
| It("returns the URI unchanged", func() { | ||
| services := `{"eg":[{"credentials":{"uri":"mysql2://username:password@host/db"}}]}` | ||
| uri, err := databaseuri.ParseDatabaseURI(services) | ||
| Expect(err).NotTo(HaveOccurred()) | ||
| Expect(uri).To(Equal("mysql2://username:password@host/db")) | ||
| }) | ||
| }) | ||
| Context("with a postgres URI", func() { | ||
| It("returns the URI unchanged", func() { | ||
| services := `{"eg":[{"credentials":{"uri":"postgres://username:password@host/db"}}]}` | ||
| uri, err := databaseuri.ParseDatabaseURI(services) | ||
| Expect(err).NotTo(HaveOccurred()) | ||
| Expect(uri).To(Equal("postgres://username:password@host/db")) | ||
| }) | ||
| }) | ||
| Context("with a postgresql URI", func() { | ||
| It("changes the scheme to postgres", func() { | ||
| services := `{"eg":[{"credentials":{"uri":"postgresql://username:password@host/db"}}]}` | ||
| uri, err := databaseuri.ParseDatabaseURI(services) | ||
| Expect(err).NotTo(HaveOccurred()) | ||
| Expect(uri).To(Equal("postgres://username:password@host/db")) | ||
| }) | ||
| }) | ||
| Context("with multiple relational database URIs", func() { | ||
| It("returns the first one found", func() { | ||
| services := `{ | ||
| "abc":[{"credentials":{"uri":"postgres://username:password@host/db1"}}, | ||
| {"credentials":{"uri":"postgres://username:password@host/db2"}}] | ||
| }` | ||
| uri, err := databaseuri.ParseDatabaseURI(services) | ||
| Expect(err).NotTo(HaveOccurred()) | ||
| Expect(uri).To(Equal("postgres://username:password@host/db1")) | ||
| }) | ||
| }) | ||
| Context("with an invalid URI", func() { | ||
| It("returns an empty string", func() { | ||
| services := `{"eg":[{"credentials":{"uri":"postgresql://invalid:password@host/%a"}}]}` | ||
| uri, err := databaseuri.ParseDatabaseURI(services) | ||
| Expect(err).NotTo(HaveOccurred()) | ||
| Expect(uri).To(Equal("")) | ||
| }) | ||
| }) | ||
| }) | ||
|
|
||
| It("handles multiple services correctly", func() { | ||
| services := `{ | ||
| "abc":[{"credentials":{"uri":"u1"}}], | ||
| "def":[{"other":"data"}], | ||
| "ghi":[{"credentials":{"other":"data"}}], | ||
| "jkl":[{},{"credentials":{"uri":"mysql://username:password@host/db"}}] | ||
| }` | ||
| uri, err := databaseuri.ParseDatabaseURI(services) | ||
| Expect(err).NotTo(HaveOccurred()) | ||
| Expect(uri).To(Equal("mysql2://username:password@host/db")) | ||
| }) | ||
| }) |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@tomkennedy513 is there an option to have a reusable version of this function? As you mentioned, this code must be the same across all existing lifecycles. It seems that the
dockerapplifecycleimports some functions from thebuildpackapplifecycle. Should this be extracted to a new repository which contains shared logic?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I copied it over (though I did tweak it a bit) because I remember when I did the credhub interpolation there was a strong desire to not have any cross lifecycle dependencies. A third repo make senses but obviously requires a lot more coordination to get this change in
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since we already have quite a lot of common things between the lifecycles, I believe it's time to introduce the library repository. What is your opinion on that?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think adding a library makes sense, but I think that should be separate from getting this fix in to unblock us.