dbservice

package
v2.4.9 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 11, 2024 License: Apache-2.0 Imports: 16 Imported by: 0

Documentation

Overview

Package dbservice implements database setup, connection, and migration

Index

Examples

Constants

View Source
const (
	DBTypeMySQL   = "mysql"
	DBTypeSQLite3 = "sqlite3"
)

Variables

This section is empty.

Functions

func New

func New(logger lager.Logger) *gorm.DB

New instantiates the db connection without running migrations

func NewWithMigrations added in v2.0.2

func NewWithMigrations(logger lager.Logger) *gorm.DB

NewWithMigrations instantiates the db connection and runs migrations

func RunMigrations

func RunMigrations(db *gorm.DB) error

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

func SetupDB(logger lager.Logger) *gorm.DB

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'"))
		})

		It("succeeds when VCAP_SERVICES has multiple lists but only one with a 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"
      ],
      "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"
      }
    }
  ],
  "user-provided": [
  	{
      "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())
		})
	})

	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

func ValidateLastMigration(lastMigration int) error

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)

Directories

Path Synopsis
Package models implements database object models for use with GORM
Package models implements database object models for use with GORM

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL