Documentation
¶
Overview ¶
Package dbservice implements database setup, connection, and migration
Index ¶
- Constants
- func New(logger lager.Logger) *gorm.DB
- func NewWithMigrations(logger lager.Logger) *gorm.DB
- func RunMigrations(db *gorm.DB) error
- func SetDatabaseCredentials(vcapService VcapService) error
- func SetupDB(logger lager.Logger) *gorm.DB
- func UseVcapServices() error
- func ValidateLastMigration(lastMigration int) error
- type VcapService
Examples ¶
Constants ¶
View Source
const ( DBTypeMySQL = "mysql" DBTypeSQLite3 = "sqlite3" )
Variables ¶
This section is empty.
Functions ¶
func NewWithMigrations ¶ added in v2.0.2
NewWithMigrations instantiates the db connection and runs migrations
func RunMigrations ¶
RunMigrations runs schema migrations on the provided service broker database to get it up to date
func SetDatabaseCredentials ¶
func SetDatabaseCredentials(vcapService VcapService) error
func SetupDB ¶
SetupDB pulls db credentials from the environment, connects to the db, and returns the db connection
func UseVcapServices ¶
func UseVcapServices() error
Example ¶
package main
import (
"fmt"
"os"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
"github.com/spf13/viper"
)
func main() {
_ = os.Setenv("VCAP_SERVICES", `{
"p.mysql": [
{
"label": "p.mysql",
"name": "my-instance",
"plan": "db-medium",
"provider": null,
"syslog_drain_url": null,
"tags": [
"mysql"
],
"credentials": {
"hostname": "10.0.0.20",
"jdbcUrl": "jdbc:mysql://10.0.0.20:3306/service_instance_db?user=fefcbe8360854a18a7994b870e7b0bf5\u0026password=z9z6eskdbs1rhtxt",
"name": "service_instance_db",
"password": "z9z6eskdbs1rhtxt",
"port": 3306,
"uri": "mysql://fefcbe8360854a18a7994b870e7b0bf5:z9z6eskdbs1rhtxt@10.0.0.20:3306/service_instance_db?reconnect=true",
"username": "fefcbe8360854a18a7994b870e7b0bf5"
},
"volume_mounts": []
}
]
}`)
_ = UseVcapServices()
fmt.Println(viper.Get(dbHostProp))
fmt.Println(viper.Get(dbUserProp))
fmt.Println(viper.Get(dbPassProp))
fmt.Println(viper.Get(dbNameProp))
}
var _ = Describe("VCAP", func() {
Describe("parsing VCAP_SERVICES", func() {
It("fails when VCAP_SERVICES is empty", func() {
_, err := ParseVcapServices("")
Expect(err).To(MatchError("error unmarshalling VCAP_SERVICES: unexpected end of JSON input"))
})
It("parses VCAP_SERVICES for Google Cloud", func() {
_, err := ParseVcapServices(`{
"google-cloudsql-mysql": [
{
"binding_name": "testbinding",
"instance_name": "testinstance",
"name": "kf-binding-tt2-mystorage",
"label": "google-storage",
"tags": [
"gcp",
"cloudsql",
"mysql"
],
"plan": "nearline",
"credentials": {
"CaCert": "-truncated-",
"ClientCert": "-truncated-",
"ClientKey": "-truncated-",
"Email": "pcf-binding-testbind@test-gsb.iam.gserviceaccount.com",
"Name": "pcf-binding-testbind",
"Password": "PASSWORD",
"PrivateKeyData": "PRIVATEKEY",
"ProjectId": "test-gsb",
"Sha1Fingerprint": "aa3bade266136f733642ebdb4992b89eb05f83c4",
"UniqueId": "108868434450972082663",
"UriPrefix": "",
"Username": "newuseraccount",
"database_name": "service_broker",
"host": "127.0.0.1",
"instance_name": "pcf-sb-1-1561406852899716453",
"last_master_operation_id": "",
"region": "",
"uri": "mysql://newuseraccount:PASSWORD@127.0.0.1/service_broker?ssl_mode=required"
}
}
]
}`)
Expect(err).NotTo(HaveOccurred())
})
It("parses VCAP_SERVICES for 'p.mysql' tile", func() {
_, err := ParseVcapServices(`{
"p.mysql": [
{
"label": "p.mysql",
"name": "my-instance",
"plan": "db-medium",
"provider": null,
"syslog_drain_url": null,
"tags": [
"mysql"
],
"credentials": {
"hostname": "10.0.0.20",
"jdbcUrl": "jdbc:mysql://10.0.0.20:3306/service_instance_db?user=fefcbe8360854a18a7994b870e7b0bf5\u0026password=z9z6eskdbs1rhtxt",
"name": "service_instance_db",
"password": "z9z6eskdbs1rhtxt",
"port": 3306,
"uri": "mysql://fefcbe8360854a18a7994b870e7b0bf5:z9z6eskdbs1rhtxt@10.0.0.20:3306/service_instance_db?reconnect=true",
"username": "fefcbe8360854a18a7994b870e7b0bf5"
},
"volume_mounts": []
}
]
}`)
Expect(err).NotTo(HaveOccurred())
})
It("fails when VCAP_SERVICES has more than one MySQL tag", func() {
_, err := ParseVcapServices(`{
"google-cloudsql-mysql": [
{
"binding_name": "testbinding",
"instance_name": "testinstance",
"name": "kf-binding-tt2-mystorage",
"label": "google-storage",
"tags": [
"gcp",
"cloudsql",
"mysql"
],
"plan": "nearline",
"credentials": {
"CaCert": "-truncated-",
"ClientCert": "-truncated-",
"ClientKey": "-truncated-",
"Email": "pcf-binding-testbind@test-gsb.iam.gserviceaccount.com",
"Name": "pcf-binding-testbind",
"Password": "PASSWORD",
"PrivateKeyData": "PRIVATEKEY",
"ProjectId": "test-gsb",
"Sha1Fingerprint": "aa3bade266136f733642ebdb4992b89eb05f83c4",
"UniqueId": "108868434450972082663",
"UriPrefix": "",
"Username": "newuseraccount",
"database_name": "service_broker",
"host": "127.0.0.1",
"instance_name": "pcf-sb-1-1561406852899716453",
"last_master_operation_id": "",
"region": "",
"uri": "mysql://newuseraccount:PASSWORD@127.0.0.1/service_broker?ssl_mode=required"
}
},
{
"label": "p.mysql",
"name": "my-instance",
"plan": "db-medium",
"provider": null,
"syslog_drain_url": null,
"tags": [
"mysql"
],
"credentials": {
"hostname": "10.0.0.20",
"jdbcUrl": "jdbc:mysql://10.0.0.20:3306/service_instance_db?user=fefcbe8360854a18a7994b870e7b0bf5\u0026password=z9z6eskdbs1rhtxt",
"name": "service_instance_db",
"password": "z9z6eskdbs1rhtxt",
"port": 3306,
"uri": "mysql://fefcbe8360854a18a7994b870e7b0bf5:z9z6eskdbs1rhtxt@10.0.0.20:3306/service_instance_db?reconnect=true",
"username": "fefcbe8360854a18a7994b870e7b0bf5"
},
"volume_mounts": []
}
]
}`)
Expect(err).To(MatchError("error finding MySQL tag: the variable VCAP_SERVICES must have one VCAP service with a tag of 'mysql'. There are currently 2 VCAP services with the tag 'mysql'"))
})
It("fails when VCAP_SERVICES has zero MySQL tag", func() {
_, err := ParseVcapServices(`{
"p.mysql": [
{
"label": "p.mysql",
"name": "my-instance",
"plan": "db-medium",
"provider": null,
"syslog_drain_url": null,
"tags": [
"notmysql"
],
"credentials": {
"hostname": "10.0.0.20",
"jdbcUrl": "jdbc:mysql://10.0.0.20:3306/service_instance_db?user=fefcbe8360854a18a7994b870e7b0bf5\u0026password=z9z6eskdbs1rhtxt",
"name": "service_instance_db",
"password": "z9z6eskdbs1rhtxt",
"port": 3306,
"uri": "mysql://fefcbe8360854a18a7994b870e7b0bf5:z9z6eskdbs1rhtxt@10.0.0.20:3306/service_instance_db?reconnect=true",
"username": "fefcbe8360854a18a7994b870e7b0bf5"
},
"volume_mounts": []
}
]
}
`)
Expect(err).To(MatchError("error finding MySQL tag: the variable VCAP_SERVICES must have one VCAP service with a tag of 'mysql'. There are currently 0 VCAP services with the tag 'mysql'"))
})
})
Describe("setting database credentials", func() {
It("succeeds when the parsed VCAP_SERVICES is empty", func() {
Expect(SetDatabaseCredentials(VcapService{})).To(Succeed())
})
It("succeeds when the parsed VCAP_SERVICES represents a valid Google Cloud service", func() {
vs := VcapService{
BindingName: "testbinding",
InstanceName: "testinstance",
Name: "kf-binding-tt2-mystorage",
Label: "google-storage",
Tags: []string{"gcp", "cloudsql", "mysql"},
Plan: "nearline",
Credentials: map[string]any{
"CaCert": "-truncated-",
"ClientCert": "-truncated-",
"ClientKey": "-truncated-",
"Email": "pcf-binding-testbind@test-gsb.iam.gserviceaccount.com",
"Name": "pcf-binding-testbind",
"Password": "Ukd7QEmrfC7xMRqNmTzHCbNnmBtNceys1olOzLoSm4k",
"PrivateKeyData": "-truncated-",
"ProjectId": "test-gsb",
"Sha1Fingerprint": "aa3bade266136f733642ebdb4992b89eb05f83c4",
"UniqueId": "108868434450972082663",
"UriPrefix": "",
"Username": "newuseraccount",
"database_name": "service_broker",
"host": "104.154.90.3",
"instance_name": "pcf-sb-1-1561406852899716453",
"last_master_operation_id": "",
"region": "",
"uri": "mysql://newuseraccount:Ukd7QEmrfC7xMRqNmTzHCbNnmBtNceys1olOzLoSm4k@104.154.90.3/service_broker?ssl_mode=required",
},
}
Expect(SetDatabaseCredentials(vs)).To(Succeed())
})
It("succeeds when the parsed VCAP_SERVICES represents a valid 'p.mysql' tile service", func() {
vs := VcapService{
BindingName: "",
InstanceName: "",
Name: "my-instance",
Label: "p.mysql",
Tags: []string{"mysql"},
Plan: "db-medium",
Credentials: map[string]any{
"hostname": "10.0.0.20",
"jdbcUrl": "jdbc:mysql://10.0.0.20:3306/service_instance_db?user=fefcbe8360854a18a7994b870e7b0bf5&password=z9z6eskdbs1rhtxt",
"name": "service_instance_db",
"password": "z9z6eskdbs1rhtxt",
"port": 3306,
"uri": "mysql://fefcbe8360854a18a7994b870e7b0bf5:z9z6eskdbs1rhtxt@10.0.0.20:3306/service_instance_db?reconnect=true",
"username": "fefcbe8360854a18a7994b870e7b0bf5",
},
}
Expect(SetDatabaseCredentials(vs)).To(Succeed())
})
It("fails when there is an malformed URI", func() {
vs := VcapService{
BindingName: "",
InstanceName: "",
Name: "my-instance",
Label: "p.mysql",
Tags: []string{"mysql"},
Plan: "db-medium",
Credentials: map[string]any{
"hostname": "10.0.0.20",
"jdbcUrl": "jdbc:mysql://10.0.0.20:3306/service_instance_db?user=fefcbe8360854a18a7994b870e7b0bf5&password=z9z6eskdbs1rhtxt",
"name": "service_instance_db",
"password": "z9z6eskdbs1rhtxt",
"port": 3306,
"uri": "mys@!ql://fefcbe8360854a18a7994b870e7b0bf5:z9z6eskdbs1rhtxt@10.0.0.20:3306/service_instance_db?reconnect=true",
"username": "fefcbe8360854a18a7994b870e7b0bf5",
},
}
Expect(SetDatabaseCredentials(vs)).To(MatchError(`error parsing credentials uri field: parse "mys@!ql://fefcbe8360854a18a7994b870e7b0bf5:z9z6eskdbs1rhtxt@10.0.0.20:3306/service_instance_db?reconnect=true": first path segment in URL cannot contain colon`))
})
})
})
Output: 10.0.0.20 fefcbe8360854a18a7994b870e7b0bf5 z9z6eskdbs1rhtxt service_instance_db
func ValidateLastMigration ¶
ValidateLastMigration returns an error if the database version is newer than this tool supports or is too old to be updated.
Types ¶
type VcapService ¶
type VcapService struct {
BindingName string `json:"binding_name"` // The name assigned to the service binding by the user.
InstanceName string `json:"instance_name"` // The name assigned to the service instance by the user.
Name string `json:"name"` // The binding_name if it exists; otherwise the instance_name.
Label string `json:"label"` // The name of the service offering.
Tags []string `json:"tags"` // An array of strings an app can use to identify a service instance.
Plan string `json:"plan"` // The service plan selected when the service instance was created.
Credentials map[string]any `json:"credentials"` // The service-specific credentials needed to access the service instance.
}
func ParseVcapServices ¶
func ParseVcapServices(vcapServicesData string) (VcapService, error)
Click to show internal directories.
Click to hide internal directories.