### Install sqlx Source: https://github.com/cloudfoundry/cf-networking-helpers/blob/main/vendor/github.com/jmoiron/sqlx/README.md Use the go get command to add the sqlx library to your project. ```bash go get github.com/jmoiron/sqlx ``` -------------------------------- ### Install utfbom Package Source: https://github.com/cloudfoundry/cf-networking-helpers/blob/main/vendor/go.step.sm/crypto/internal/utils/utfbom/README.md Use 'go get' to install the utfbom package. This command fetches and installs the package and its dependencies. ```bash go get -u github.com/dimchansky/utfbom ``` -------------------------------- ### Install the YAML package Source: https://github.com/cloudfoundry/cf-networking-helpers/blob/main/vendor/go.yaml.in/yaml/v3/README.md Use the go get command to add the package to your project. ```bash go get go.yaml.in/yaml/v3 ``` -------------------------------- ### Install Go-MySQL-Driver Source: https://github.com/cloudfoundry/cf-networking-helpers/blob/main/vendor/github.com/go-sql-driver/mysql/README.md Use the go tool to install the driver package into your GOPATH. ```bash go get -u github.com/go-sql-driver/mysql ``` -------------------------------- ### Run Tests with Docker Compose Source: https://github.com/cloudfoundry/cf-networking-helpers/blob/main/vendor/github.com/lib/pq/README.md Example command to start PostgreSQL using Docker Compose for running tests. Adjust 'pg' for specific PostgreSQL versions. ```bash docker compose up -d ``` -------------------------------- ### Example output Source: https://github.com/cloudfoundry/cf-networking-helpers/blob/main/vendor/go.yaml.in/yaml/v3/README.md The expected output generated by the provided Go example code. ```text --- t: {Easy! {2 [3 4]}} --- t dump: a: Easy! b: c: 2 d: [3, 4] --- m: map[a:Easy! b:map[c:2 d:[3 4]]] --- m dump: a: Easy! b: c: 2 d: - 3 - 4 ``` -------------------------------- ### Convert Format String Logs to Structured Key-Value Pairs Source: https://github.com/cloudfoundry/cf-networking-helpers/blob/main/vendor/github.com/go-logr/logr/README.md Examples demonstrating the migration of standard format-string logging to structured logging using key-value pairs. ```go klog.V(4).Infof("Client is returning errors: code %v, error %v", responseCode, err) ``` ```go logger.Error(err, "client returned an error", "code", responseCode) ``` ```go klog.V(4).Infof("Got a Retry-After %ds response for attempt %d to %v", seconds, retries, url) ``` ```go logger.V(4).Info("got a retry-after response when requesting url", "attempt", retries, "after seconds", seconds, "url", url) ``` ```go log.Printf("unable to reflect over type %T") ``` ```go logger.Info("unable to reflect over type", "type", fmt.Sprintf("%T")) ``` -------------------------------- ### Development and Testing Commands Source: https://github.com/cloudfoundry/cf-networking-helpers/blob/main/vendor/github.com/onsi/ginkgo/v2/CONTRIBUTING.md Commands for installing, testing, and vetting the Ginkgo codebase. ```bash make ``` ```bash go install ./... ``` ```bash ginkgo -r -p ``` ```bash go vet ./... ``` ```bash bundle && bundle exec jekyll serve ``` -------------------------------- ### Ginkgo Spec Structure Example Source: https://github.com/cloudfoundry/cf-networking-helpers/blob/main/vendor/github.com/onsi/ginkgo/v2/README.md Demonstrates a typical Ginkgo test structure with Describe, BeforeEach, When, Context, and It blocks. Imports are required from Ginkgo and Gomega. Use SpecTimeout for setting test durations. ```go import ( . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" ... ) var _ = Describe("Checking books out of the library", Label("library"), func() { var library *libraries.Library var book *books.Book var valjean *users.User BeforeEach(func() { library = libraries.NewClient() book = &books.Book{ Title: "Les Miserables", Author: "Victor Hugo", } valjean = users.NewUser("Jean Valjean") }) When("the library has the book in question", func() { BeforeEach(func(ctx SpecContext) { Expect(library.Store(ctx, book)).To(Succeed()) }) Context("and the book is available", func() { It("lends it to the reader", func(ctx SpecContext) { Expect(valjean.Checkout(ctx, library, "Les Miserables")).To(Succeed()) Expect(valjean.Books()).To(ContainElement(book)) Expect(library.UserWithBook(ctx, book)).To(Equal(valjean)) }, SpecTimeout(time.Second * 5)) }) Context("but the book has already been checked out", func() { var javert *users.User BeforeEach(func(ctx SpecContext) { javert = users.NewUser("Javert") Expect(javert.Checkout(ctx, library, "Les Miserables")).To(Succeed()) }) It("tells the user", func(ctx SpecContext) { err := valjean.Checkout(ctx, library, "Les Miserables") Expect(err).To(MatchError("Les Miserables is currently checked out")) }, SpecTimeout(time.Second * 5)) It("lets the user place a hold and get notified later", func(ctx SpecContext) { Expect(valjean.Hold(ctx, library, "Les Miserables")).To(Succeed()) Expect(valjean.Holds(ctx)).To(ContainElement(book)) By("when Javert returns the book") Expect(javert.Return(ctx, library, book)).To(Succeed()) By("it eventually informs Valjean") notification := "Les Miserables is ready for pick up" Eventually(ctx, valjean.Notifications).Should(ContainElement(notification)) Expect(valjean.Checkout(ctx, library, "Les Miserables")).To(Succeed()) Expect(valjean.Books(ctx)).To(ContainElement(book)) Expect(valjean.Holds(ctx)).To(BeEmpty()) }, SpecTimeout(time.Second * 10)) }) }) When("the library does not have the book in question", func() { It("tells the reader the book is unavailable", func(ctx SpecContext) { err := valjean.Checkout(ctx, library, "Les Miserables") Expect(err).To(MatchError("Les Miserables is not in the library catalog")) }, SpecTimeout(time.Second * 5)) }) }) ``` -------------------------------- ### DSN Format Examples Source: https://github.com/cloudfoundry/cf-networking-helpers/blob/main/vendor/github.com/go-sql-driver/mysql/README.md Various formats for defining a Data Source Name, ranging from full connection strings to minimal or empty configurations. ```text [username[:password]@][protocol[(address)]]/dbname[?param1=value1&...¶mN=valueN] ``` ```text username:password@protocol(address)/dbname?param=value ``` ```text /dbname ``` ```text / ``` ```text ``` ```text /dbname%2Fwithslash ``` -------------------------------- ### Set System Variables Source: https://github.com/cloudfoundry/cf-networking-helpers/blob/main/vendor/github.com/go-sql-driver/mysql/README.md Examples of passing system variables through the DSN, requiring URL encoding for string values. ```text * `autocommit=1`: `SET autocommit=1` * [`time_zone=%27Europe%2FParis%27`](https://dev.mysql.com/doc/refman/5.5/en/time-zone-support.html): `SET time_zone='Europe/Paris'` * [`transaction_isolation=%27REPEATABLE-READ%27`](https://dev.mysql.com/doc/refman/5.7/en/server-system-variables.html#sysvar_transaction_isolation): `SET transaction_isolation='REPEATABLE-READ'` ``` -------------------------------- ### Initialize MySQL Connection Source: https://github.com/cloudfoundry/cf-networking-helpers/blob/main/vendor/github.com/go-sql-driver/mysql/README.md Import the driver and use sql.Open to establish a connection, followed by recommended connection pool settings. ```go import ( "database/sql" "time" _ "github.com/go-sql-driver/mysql" ) // ... db, err := sql.Open("mysql", "user:password@/dbname") if err != nil { panic(err) } // See "Important settings" section. db.SetConnMaxLifetime(time.Minute * 3) db.SetMaxOpenConns(10) db.SetMaxIdleConns(10) ``` -------------------------------- ### Configure connection string parameters Source: https://github.com/cloudfoundry/cf-networking-helpers/blob/main/vendor/github.com/lib/pq/README.md Demonstrates passing run-time parameters directly in the DSN or using the libpq options style. ```go sql.Open("postgres", "dbname=pqgo work_mem=100kB search_path=xyz") ``` ```go sql.Open("postgres", "dbname=pqgo options='-c work_mem=100kB -c search_path=xyz'") ``` -------------------------------- ### Connect to PostgreSQL using sql.Open Source: https://github.com/cloudfoundry/cf-networking-helpers/blob/main/vendor/github.com/lib/pq/README.md Establishes a connection pool using a DSN string. Always call Ping() to verify the connection is active. ```go package main import ( "database/sql" "log" _ "github.com/lib/pq" // To register the driver. ) func main() { // Or as URL: postgresql://localhost/pqgo db, err := sql.Open("postgres", "host=localhost dbname=pqgo") if err != nil { log.Fatal(err) } defer db.Close() // db.Open() only creates a connection pool, and doesn't actually establish // a connection. To ensure the connection works you need to do *something* // with a connection. err = db.Ping() if err != nil { log.Fatal(err) } } ``` -------------------------------- ### SQL Query with Ambiguous Columns Source: https://github.com/cloudfoundry/cf-networking-helpers/blob/main/vendor/github.com/jmoiron/sqlx/README.md Example of a SQL query that may cause ambiguity when scanning into structs or maps due to duplicate column names. ```sql SELECT a.id, a.name, b.id, b.name FROM foos AS a JOIN foos AS b ON a.parent = b.id; ``` -------------------------------- ### Connect to PostgreSQL using pq.Config Source: https://github.com/cloudfoundry/cf-networking-helpers/blob/main/vendor/github.com/lib/pq/README.md Uses the pq.Config struct to define connection parameters and create a connector for sql.OpenDB. ```go cfg := pq.Config{ Host: "localhost", Port: 5432, User: "pqgo", } // Or: create a new Config from the defaults, environment, and DSN. // cfg, err := pq.NewConfig("host=postgres dbname=pqgo") // if err != nil { // log.Fatal(err) // } c, err := pq.NewConnectorConfig(cfg) if err != nil { log.Fatal(err) } // Create connection pool. db := sql.OpenDB(c) defer db.Close() // Make sure it works. err = db.Ping() if err != nil { log.Fatal(err) } ``` -------------------------------- ### Show mkall.sh Commands (Old Build System) Source: https://github.com/cloudfoundry/cf-networking-helpers/blob/main/vendor/golang.org/x/sys/unix/README.md Run this command to see the build commands that will be executed by mkall.sh without actually running them. Useful for debugging or understanding the process. ```bash mkall.sh -n ``` -------------------------------- ### Run mkall.sh to Build sys/unix Files Source: https://github.com/cloudfoundry/cf-networking-helpers/blob/main/vendor/golang.org/x/sys/unix/README.md Use this command to generate the Go files for your current OS and architecture using the old build system. Ensure GOOS and GOARCH are set correctly. ```bash mkall.sh ``` -------------------------------- ### Create and Run Metrics Emitter Source: https://context7.com/cloudfoundry/cf-networking-helpers/llms.txt Sets up a periodic metrics emitter using custom metric sources. Ensure logger, interval, and metric sources are configured. Runs as an ifrit process. ```go package main import ( "os" "time" "code.cloudfoundry.org/cf-networking-helpers/metrics" "code.cloudfoundry.org/lager/v3" "github.com/tedsuo/ifrit" ) func main() { logger := lager.NewLogger("myservice") // Define custom metric sources metricSources := []metrics.MetricSource{ { Name: "activeConnections", Unit: "count", Getter: func() (float64, error) { return float64(getActiveConnectionCount()), nil }, }, { Name: "queueDepth", Unit: "items", Getter: func() (float64, error) { return float64(getQueueDepth()), nil }, }, } // Create metrics emitter (emits every 30 seconds) emitter := metrics.NewMetricsEmitter(logger, 30*time.Second, metricSources...) // Run as ifrit process process := ifrit.Invoke(emitter) // Wait for termination signal err := <-process.Wait() if err != nil { logger.Error("metrics-emitter-failed", err) } } func getActiveConnectionCount() int { return 42 } func getQueueDepth() int { return 100 } ``` -------------------------------- ### Connect to PostgreSQL and Execute Schema Source: https://github.com/cloudfoundry/cf-networking-helpers/blob/main/vendor/github.com/jmoiron/sqlx/README.md Establishes a connection to a PostgreSQL database using sqlx.Connect and executes a predefined schema. Ensure the database is accessible and credentials are correct. ```go package main import ( "database/sql" "fmt" "log" _ "github.com/lib/pq" "github.com/jmoiron/sqlx" ) var schema = ` CREATE TABLE person ( first_name text, last_name text, email text ); CREATE TABLE place ( country text, city text NULL, telcode integer )` type Person struct { FirstName string `db:"first_name"` LastName string `db:"last_name"` Email string } type Place struct { Country string City sql.NullString TelCode int } func main() { // this Pings the database trying to connect // use sqlx.Open() for sql.Open() semantics db, err := sqlx.Connect("postgres", "user=foo dbname=bar sslmode=disable") if err != nil { log.Fatalln(err) } // exec the schema or fail; multi-statement Exec behavior varies between // database drivers; pq will exec them all, sqlite3 won't, ymmv db.MustExec(schema) tx := db.MustBegin() tx.MustExec("INSERT INTO person (first_name, last_name, email) VALUES ($1, $2, $3)", "Jason", "Moiron", "jmoiron@jmoiron.net") tx.MustExec("INSERT INTO person (first_name, last_name, email) VALUES ($1, $2, $3)", "John", "Doe", "johndoeDNE@gmail.net") tx.MustExec("INSERT INTO place (country, city, telcode) VALUES ($1, $2, $3)", "United States", "New York", "1") tx.MustExec("INSERT INTO place (country, telcode) VALUES ($1, $2)", "Hong Kong", "852") tx.MustExec("INSERT INTO place (country, telcode) VALUES ($1, $2)", "Singapore", "65") // Named queries can use structs, so if you have an existing struct (i.e. person := &Person{}) that you have populated, you can pass it in as &person tx.NamedExec("INSERT INTO person (first_name, last_name, email) VALUES (:first_name, :last_name, :email)", &Person{"Jane", "Citizen", "jane.citzen@example.com"}) tx.Commit() // Query the database, storing results in a []Person (wrapped in []interface{}) people := []Person{} db.Select(&people, "SELECT * FROM person ORDER BY first_name ASC") jason, john := people[0], people[1] fmt.Printf("%#v\n%#v", jason, john) // Person{FirstName:"Jason", LastName:"Moiron", Email:"jmoiron@jmoiron.net"} // Person{FirstName:"John", LastName:"Doe", Email:"johndoeDNE@gmail.net"} // You can also get a single result, a la QueryRow jason = Person{} err = db.Get(&jason, "SELECT * FROM person WHERE first_name=$1", "Jason") fmt.Printf("%#v\n", jason) // Person{FirstName:"Jason", LastName:"Moiron", Email:"jmoiron@jmoiron.net"} // if you have null fields and use SELECT *, you must use sql.Null* in your struct places := []Place{} err = db.Select(&places, "SELECT * FROM place ORDER BY telcode ASC") if err != nil { fmt.Println(err) return } usa, singsing, honkers := places[0], places[1], places[2] fmt.Printf("%#v\n%#v\n%#v\n", usa, singsing, honkers) // Place{Country:"United States", City:sql.NullString{String:"New York", Valid:true}, TelCode:1} // Place{Country:"Singapore", City:sql.NullString{String:"", Valid:false}, TelCode:65} // Place{Country:"Hong Kong", City:sql.NullString{String:"", Valid:false}, TelCode:852} // Loop through rows using only one struct place := Place{} rows, err := db.Queryx("SELECT * FROM place") for rows.Next() { err := rows.StructScan(&place) if err != nil { log.Fatalln(err) } fmt.Printf("%#v\n", place) } // Place{Country:"United States", City:sql.NullString{String:"New York", Valid:true}, TelCode:1} // Place{Country:"Hong Kong", City:sql.NullString{String:"", Valid:false}, TelCode:852} // Place{Country:"Singapore", City:sql.NullString{String:"", Valid:false}, TelCode:65} // Named queries, using `:name` as the bindvar. Automatic bindvar support // which takes into account the dbtype based on the driverName on sqlx.Open/Connect _, err = db.NamedExec(`INSERT INTO person (first_name,last_name,email) VALUES (:first,:last,:email)`, map[string]interface{}{ "first": "Bin", "last": "Smuth", "email": "bensmith@allblacks.nz", }) // Selects Mr. Smith from the database rows, err = db.NamedQuery(`SELECT * FROM person WHERE first_name=:fn`, map[string]interface{}{"fn": "Bin"}) // Named queries can also use structs. Their bind names follow the same rules // as the name -> db mapping, so struct fields are lowercased and the `db` tag // is taken into consideration. rows, err = db.NamedQuery(`SELECT * FROM person WHERE first_name=:first_name`, jason) // batch insert // batch insert with structs personStructs := []Person{ {FirstName: "Ardie", LastName: "Savea", Email: "asavea@ab.co.nz"}, ``` -------------------------------- ### Create Root Logger Source: https://github.com/cloudfoundry/cf-networking-helpers/blob/main/vendor/github.com/go-logr/logr/README.md Initialize the root logger with a chosen implementation and initial parameters early in the application's lifecycle. ```go func main() { // ... other setup code ... // Create the "root" logger. We have chosen the "logimpl" implementation, // which takes some initial parameters and returns a logr.Logger. logger := logimpl.New(param1, param2) // ... other setup code ... } ``` -------------------------------- ### Run Tests with Binary Parameters Source: https://github.com/cloudfoundry/cf-networking-helpers/blob/main/vendor/github.com/lib/pq/README.md Command to run Go tests with binary parameters enabled. This adds 'binary_parameters=yes' to connection strings. ```bash PQTEST_BINARY_PARAMETERS=1 go test ``` -------------------------------- ### Run Tests with Pgpool Source: https://github.com/cloudfoundry/cf-networking-helpers/blob/main/vendor/github.com/lib/pq/README.md Instructions to run tests against a PostgreSQL instance managed by pgpool. Note the custom PGPORT. ```bash docker compose up -d pgpool pg18 PGPORT=7432 go test ./... ``` -------------------------------- ### Establish Database Connection Pool in Go Source: https://context7.com/cloudfoundry/cf-networking-helpers/llms.txt Configures and initializes a database connection pool with support for MySQL or PostgreSQL, including SSL/TLS settings and query monitoring. ```go package main import ( "context" "fmt" "time" "code.cloudfoundry.org/cf-networking-helpers/db" "code.cloudfoundry.org/lager/v3" ) func main() { logger := lager.NewLogger("myapp") // Configure database connection config := db.Config{ Type: "postgres", // or "mysql" User: "admin", Password: "secret", Host: "localhost", Port: 5432, DatabaseName: "mydb", Timeout: 30, // seconds RequireSSL: true, CACert: "/path/to/ca.crt", // required when RequireSSL=true } // Create connection pool with retry logic pool, err := db.NewConnectionPool( config, 10, // maxOpenConnections 5, // maxIdleConnections time.Hour, // connMaxLifetime "myapp", // logPrefix "worker", // jobPrefix logger, ) if err != nil { logger.Fatal("db-connect-failed", err) } defer pool.Close() // Execute queries with monitoring rows, err := pool.Query("SELECT id, name FROM users WHERE active = $1", true) if err != nil { logger.Error("query-failed", err) return } defer rows.Close() // Use transactions with monitoring tx, err := pool.Beginx() if err != nil { logger.Error("transaction-failed", err) return } _, err = tx.Exec("INSERT INTO logs (message) VALUES ($1)", "test") if err != nil { tx.Rollback() return } tx.Commit() // Check connection stats fmt.Printf("Open connections: %d\n", pool.OpenConnections()) } ``` -------------------------------- ### Create and Check Version Constraints Source: https://github.com/cloudfoundry/cf-networking-helpers/blob/main/vendor/github.com/Masterminds/semver/v3/README.md Use `semver.NewConstraint` to create a constraint object and `semver.NewVersion` to parse a version. The `Check` method then determines if the version satisfies the constraint. Handle potential errors during parsing. ```go c, err := semver.NewConstraint(">= 1.2.3") if err != nil { // Handle constraint not being parsable. } v, err := semver.NewVersion("1.3") if err != nil { // Handle version not being parsable. } // Check if the version meets the constraints. The variable a will be true. a := c.Check(v) ``` -------------------------------- ### Run Linter Locally Source: https://github.com/cloudfoundry/cf-networking-helpers/blob/main/vendor/github.com/onsi/gomega/CONTRIBUTING.md Check for potential issues and warnings in the Go code using the `go vet` command. Ensure no warnings are present before submitting changes. ```bash go vet ./... ``` -------------------------------- ### Run Tests with Pgbouncer Source: https://github.com/cloudfoundry/cf-networking-helpers/blob/main/vendor/github.com/lib/pq/README.md Instructions to run tests against a PostgreSQL instance managed by pgbouncer. Note the custom PGPORT. ```bash docker compose up -d pgbouncer pg18 PGPORT=6432 go test ./... ``` -------------------------------- ### Configure serverPubKey Source: https://github.com/cloudfoundry/cf-networking-helpers/blob/main/vendor/github.com/go-sql-driver/mysql/README.md Registers a server public key for encrypted authentication. ```text Type: string Valid Values: Default: none ``` -------------------------------- ### Parameter Configuration Definitions Source: https://github.com/cloudfoundry/cf-networking-helpers/blob/main/vendor/github.com/go-sql-driver/mysql/README.md Definitions for various connection parameters including type, valid values, and default settings. ```text Type: bool Valid Values: true, false Default: false ``` ```text Type: bool Valid Values: true, false Default: false ``` ```text Type: bool Valid Values: true, false Default: false ``` ```text Type: bool Valid Values: true, false Default: true ``` ```text Type: bool Valid Values: true, false Default: false ``` ```text Type: string Valid Values: Default: none ``` ```text Type: bool Valid Values: true, false Default: true ``` -------------------------------- ### Listen for PostgreSQL Notifications Source: https://github.com/cloudfoundry/cf-networking-helpers/blob/main/vendor/github.com/lib/pq/README.md Demonstrates how to set up a listener for PostgreSQL notifications on a specific channel. Ensure the 'coconut' channel is being notified by the server. ```go l := pq.NewListener("dbname=pqgo", time.Second, time.Minute, nil) def l.Close() err := l.Listen("coconut") if err != nil { log.Fatal(err) } for { n := <-l.Notify: if n == nil { fmt.Println("nil notify: closing Listener") return } fmt.Printf("notification on %q with data %q\n", n.Channel, n.Extra) } ``` -------------------------------- ### Configure Mutual TLS with mutualtls Source: https://context7.com/cloudfoundry/cf-networking-helpers/llms.txt Simplifies creating TLS configurations for HTTP servers and clients. Requires paths to existing certificate, key, and CA files. ```go package main import ( "crypto/tls" "net/http" "code.cloudfoundry.org/cf-networking-helpers/mutualtls" ) func main() { certFile := "/path/to/server.crt" keyFile := "/path/to/server.key" caCertFile := "/path/to/ca.crt" // Create server TLS config (requires client certificates) serverTLSConfig, err := mutualtls.NewServerTLSConfig(certFile, keyFile, caCertFile) if err != nil { panic(err) } // Start HTTPS server with mutual TLS server := &http.Server{ Addr: ":8443", TLSConfig: serverTLSConfig, Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { // Client certificate is available via r.TLS.PeerCertificates w.Write([]byte("Hello, authenticated client!")) }), } go server.ListenAndServeTLS("", "") // Certs already in TLSConfig // Create client TLS config clientTLSConfig, err := mutualtls.NewClientTLSConfig( "/path/to/client.crt", "/path/to/client.key", caCertFile, ) if err != nil { panic(err) } // Create HTTP client with mutual TLS client := &http.Client{ Transport: &http.Transport{ TLSClientConfig: clientTLSConfig, }, } resp, err := client.Get("https://localhost:8443/") if err != nil { panic(err) } defer resp.Body.Close() } ``` -------------------------------- ### Dynamic Log Level Server in Go Source: https://context7.com/cloudfoundry/cf-networking-helpers/llms.txt Implement a server to dynamically change log levels at runtime without restarting the application. Requires a reconfigurable sink and a logger instance. ```go package main import ( "os" "time" "code.cloudfoundry.org/cf-networking-helpers/lagerlevel" "code.cloudfoundry.org/lager/v3" "github.com/tedsuo/ifrit" ) func main() { // Create reconfigurable sink for dynamic log level changes sink := lager.NewReconfigurableSink( lager.NewWriterSink(os.Stdout, lager.DEBUG), lager.INFO, // Initial log level ) logger := lager.NewLogger("myservice") logger.RegisterSink(sink) // Create log level server logLevelServer := lagerlevel.NewServer( "127.0.0.1", // address 8081, // port 10*time.Second, // readHeaderTimeout sink, // reconfigurable sink logger, ) // Run as ifrit process process := ifrit.Invoke(logLevelServer) logger.Info("service-started") // Change log level via HTTP: // curl -X POST http://localhost:8081/log-level -d "debug" // curl -X POST http://localhost:8081/log-level -d "info" <-process.Wait() } ``` -------------------------------- ### Generate Certificates with certauthority Source: https://context7.com/cloudfoundry/cf-networking-helpers/llms.txt Use this package to create a CA and sign host or intermediate certificates. Requires a directory path for storing generated files. ```go package main import ( "fmt" "os" "code.cloudfoundry.org/cf-networking-helpers/certauthority" ) func main() { // Create a temporary directory for certificates depotDir, err := os.MkdirTemp("", "certs") if err != nil { panic(err) } defer os.RemoveAll(depotDir) // Create a new Certificate Authority ca, err := certauthority.NewCertAuthority(depotDir, "MyOrg CA") if err != nil { panic(err) } // Get CA key and certificate paths caKeyPath, caCertPath := ca.CAAndKey() fmt.Printf("CA Key: %s\nCA Cert: %s\n", caKeyPath, caCertPath) // Generate a server certificate signed by the CA serverKeyPath, serverCertPath, err := ca.GenerateSelfSignedCertAndKey( "server.example.com", // commonName []string{"server.example.com", "localhost"}, // SANs false, // intermediateCA ) if err != nil { panic(err) } fmt.Printf("Server Key: %s\nServer Cert: %s\n", serverKeyPath, serverCertPath) // Generate a client certificate clientKeyPath, clientCertPath, err := ca.GenerateSelfSignedCertAndKey( "client.example.com", []string{"client.example.com"}, false, ) if err != nil { panic(err) } fmt.Printf("Client Key: %s\nClient Cert: %s\n", clientKeyPath, clientCertPath) // Generate an intermediate CA intermediateKeyPath, intermediateCertPath, err := ca.GenerateSelfSignedCertAndKey( "Intermediate CA", nil, true, // intermediateCA = true ) if err != nil { panic(err) } fmt.Printf("Intermediate CA Key: %s\nIntermediate CA Cert: %s\n", intermediateKeyPath, intermediateCertPath) } ``` -------------------------------- ### Configure tls Source: https://github.com/cloudfoundry/cf-networking-helpers/blob/main/vendor/github.com/go-sql-driver/mysql/README.md Enables TLS/SSL encrypted connections with options for verification and fallback. ```text Type: bool / string Valid Values: true, false, skip-verify, preferred, Default: false ``` -------------------------------- ### Commit, Push, and Create GitHub Release Source: https://github.com/cloudfoundry/cf-networking-helpers/blob/main/vendor/github.com/onsi/ginkgo/v2/RELEASING.md Standard Git commands to commit changes, push to the remote repository, and create a new release on GitHub. Fetch tags to ensure local and remote are synchronized. ```bash git commit -m "vM.m.p" git push gh release create "vM.m.p" git fetch --tags origin master ``` -------------------------------- ### Implement Retriable Database Connection in Go Source: https://context7.com/cloudfoundry/cf-networking-helpers/llms.txt Wraps database connection attempts with configurable retry logic to handle transient unavailability during application startup. ```go package main import ( "context" "time" "code.cloudfoundry.org/cf-networking-helpers/db" "code.cloudfoundry.org/lager/v3" ) func main() { logger := lager.NewLogger("myapp") config := db.Config{ Type: "mysql", User: "root", Password: "password", Host: "mysql.service.internal", Port: 3306, DatabaseName: "app_db", Timeout: 10, } // Configure retriable connector connector := db.RetriableConnector{ Logger: logger, Connector: db.GetConnectionPool, Sleeper: db.SleeperFunc(time.Sleep), RetryInterval: 3 * time.Second, MaxRetries: 10, } ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second) defer cancel() // Attempt connection with retries pool, err := connector.GetConnectionPool(config, ctx) if err != nil { // RetriableError indicates a transient failure if _, ok := err.(db.RetriableError); ok { logger.Error("transient-db-error", err) } logger.Fatal("db-connection-failed", err) } defer pool.Close() logger.Info("database-connected") } ``` -------------------------------- ### Import MySQL Driver for LOAD DATA LOCAL INFILE Source: https://github.com/cloudfoundry/cf-networking-helpers/blob/main/vendor/github.com/go-sql-driver/mysql/README.md Required import path to access package-level functions for file loading features. ```go import "github.com/go-sql-driver/mysql" ``` -------------------------------- ### Using flags.DurationFlag for Configuration Source: https://context7.com/cloudfoundry/cf-networking-helpers/llms.txt Demonstrates how to use the flags.DurationFlag type for JSON-serializable duration values in configuration. Ensure the input JSON string is correctly formatted. ```go package main import ( "encoding/json" "fmt" "time" "code.cloudfoundry.org/cf-networking-helpers/flags" ) type Config struct { Timeout flags.DurationFlag `json:"timeout"` PollInterval flags.DurationFlag `json:"poll_interval"` } func main() { // Parse config from JSON jsonConfig := `{ "timeout": "30s", "poll_interval": "5m" }` var config Config err := json.Unmarshal([]byte(jsonConfig), &config) if err != nil { panic(err) } fmt.Printf("Timeout: %v\n", time.Duration(config.Timeout)) fmt.Printf("Poll Interval: %v\n", time.Duration(config.PollInterval)) // Serialize back to JSON output, _ := json.MarshalIndent(config, "", " ") fmt.Println(string(output)) // Output: // { // "timeout": "30s", // "poll_interval": "5m0s" // } } ``` -------------------------------- ### Configure and Run Poller Source: https://context7.com/cloudfoundry/cf-networking-helpers/llms.txt Initializes a poller to execute a function at a set interval, with an option to run immediately. Fatal errors can trigger process restarts. ```go package main import ( "fmt" "os" "time" "code.cloudfoundry.org/cf-networking-helpers/poller" "code.cloudfoundry.org/lager/v3" "github.com/tedsuo/ifrit" ) func main() { logger := lager.NewLogger("sync-service") // Create poller that syncs data every minute p := &poller.Poller{ Logger: logger, PollInterval: 1 * time.Minute, RunBeforeFirstInterval: true, // Run immediately on start SingleCycleFunc: func() error { logger.Info("syncing-data") // Perform sync operation err := syncData() if err != nil { // Return FatalError to terminate the process if isCriticalError(err) { return poller.FatalError(fmt.Sprintf("critical sync failure: %s", err)) } // Non-fatal errors are logged but don't stop polling return err } logger.Info("sync-complete") return nil }, } // Run as ifrit process process := ifrit.Invoke(p) // Wait for termination err := <-process.Wait() if err != nil { logger.Fatal("poller-terminated", err) os.Exit(1) } } func syncData() error { return nil } func isCriticalError(err error) bool { return false } ``` -------------------------------- ### Skip BOM and Detect Encoding in Go Source: https://github.com/cloudfoundry/cf-networking-helpers/blob/main/vendor/go.step.sm/crypto/internal/utils/utfbom/README.md Demonstrates how to use utfbom.Skip to read data, skip the BOM, and detect the encoding. It handles cases with and without a BOM. ```go package main import ( "bytes" "fmt" "io/ioutil" "github.com/dimchansky/utfbom" ) func main() { trySkip([]byte("\xEF\xBB\xBFhello")) trySkip([]byte("hello")) } func trySkip(byteData []byte) { fmt.Println("Input:", byteData) // just skip BOM output, err := ioutil.ReadAll(utfbom.SkipOnly(bytes.NewReader(byteData))) if err != nil { fmt.Println(err) return } fmt.Println("ReadAll with BOM skipping", output) // skip BOM and detect encoding sr, enc := utfbom.Skip(bytes.NewReader(byteData)) fmt.Printf("Detected encoding: %s\n", enc) output, err = ioutil.ReadAll(sr) if err != nil { fmt.Println(err) return } fmt.Println("ReadAll with BOM detection and skipping", output) fmt.Println() } ``` -------------------------------- ### Configure connectionAttributes Source: https://github.com/cloudfoundry/cf-networking-helpers/blob/main/vendor/github.com/go-sql-driver/mysql/README.md Passes user-defined key-value pairs to the server at connection time. ```text Type: comma-delimited string of user-defined "key:value" pairs Valid Values: (:,:,...) Default: none ``` -------------------------------- ### System Variables Configuration Source: https://github.com/cloudfoundry/cf-networking-helpers/blob/main/vendor/github.com/go-sql-driver/mysql/README.md How to configure MySQL system variables through the connection string. ```APIDOC ## System Variables Configuration Any other parameters are interpreted as system variables: * `=`: `SET =` * `=`: `SET =` * `%27%27`: `SET =''` Rules: * The values for string variables must be quoted with `'`. * The values must also be [url.QueryEscape](http://golang.org/pkg/net/url/#QueryEscape)'ed! (which implies values of string variables must be wrapped with `%27`). Examples: * `autocommit=1`: `SET autocommit=1` * [`time_zone=%27Europe%2FParis%27`](https://dev.mysql.com/doc/refman/5.5/en/time-zone-support.html): `SET time_zone='Europe/Paris'` * [`transaction_isolation=%27REPEATABLE-READ%27`](https://dev.mysql.com/doc/refman/5.7/en/server-system-variables.html#sysvar_transaction_isolation): `SET transaction_isolation='REPEATABLE-READ'` ``` -------------------------------- ### Enable PostgreSQL Protocol Debugging Source: https://github.com/cloudfoundry/cf-networking-helpers/blob/main/vendor/github.com/lib/pq/README.md Set the PQGO_DEBUG environment variable to 1 to print communication logs to stderr during test execution. ```bash % PQGO_DEBUG=1 go test -run TestSimpleQuery CLIENT → Startup 69 "\x00\x03\x00\x00database\x00pqgo\x00user [..]" SERVER ← (R) AuthRequest 4 "\x00\x00\x00\x00" SERVER ← (S) ParamStatus 19 "in_hot_standby\x00off\x00" [..] SERVER ← (Z) ReadyForQuery 1 "I" START conn.query START conn.simpleQuery CLIENT → (Q) Query 9 "select 1\x00" SERVER ← (T) RowDescription 29 "\x00\x01?column?\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x17\x00\x04\xff\xff\xff\xff\x00\x00" SERVER ← (D) DataRow 7 "\x00\x01\x00\x00\x00\x011" END conn.simpleQuery END conn.query SERVER ← (C) CommandComplete 9 "SELECT 1\x00" SERVER ← (Z) ReadyForQuery 1 "I" CLIENT → (X) Terminate 0 "" PASS ok github.com/lib/pq 0.010s ``` -------------------------------- ### Run Ginkgo Specs in Parallel Source: https://github.com/cloudfoundry/cf-networking-helpers/blob/main/vendor/github.com/onsi/ginkgo/v2/README.md Use the '-p' flag with the ginkgo command to run your specs in parallel. This is useful for speeding up test execution in larger suites. ```bash ginkgo -p ``` -------------------------------- ### Implement HTTP Metrics Middleware Source: https://context7.com/cloudfoundry/cf-networking-helpers/llms.txt Use MetricWrapper to collect request timing and count metrics. Metrics are emitted via the Dropsonde system. ```go package main import ( "net/http" "code.cloudfoundry.org/cf-networking-helpers/metrics" "code.cloudfoundry.org/cf-networking-helpers/middleware" "code.cloudfoundry.org/lager/v3" ) func main() { logger := lager.NewLogger("myservice") // Create metrics sender metricsSender := &metrics.MetricsSender{Logger: logger} // Create metrics wrapper metricsWrapper := &middleware.MetricWrapper{ Name: "MyAPI", MetricsSender: metricsSender, } // Your application handler appHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Write([]byte("OK")) }) // Wrap handler - emits "MyAPIRequestTime" and "MyAPIRequestCount" metrics wrappedHandler := metricsWrapper.Wrap(appHandler) http.ListenAndServe(":8080", wrappedHandler) } ``` -------------------------------- ### Security and Connection Options Source: https://github.com/cloudfoundry/cf-networking-helpers/blob/main/vendor/github.com/go-sql-driver/mysql/README.md Configuration options for security and connection attributes. ```APIDOC ## Security and Connection Options ### `rejectReadOnly` `rejectReadOnly=true` causes the driver to reject read-only connections. This is for a possible race condition during an automatic failover, where the mysql client gets connected to a read-only replica after the failover. - **Type**: bool - **Valid Values**: true, false - **Default**: false ### `serverPubKey` Server public keys can be registered with [`mysql.RegisterServerPubKey`](https://godoc.org/github.com/go-sql-driver/mysql#RegisterServerPubKey), which can then be used by the assigned name in the DSN. Public keys are used to transmit encrypted data, e.g. for authentication. If the server's public key is known, it should be set manually to avoid expensive and potentially insecure transmissions of the public key from the server to the client each time it is required. - **Type**: string - **Valid Values**: - **Default**: none ### `tls` `tls=true` enables TLS / SSL encrypted connection to the server. Use `skip-verify` if you want to use a self-signed or invalid certificate (server side) or use `preferred` to use TLS only when advertised by the server. This is similar to `skip-verify`, but additionally allows a fallback to a connection which is not encrypted. Neither `skip-verify` nor `preferred` add any reliable security. You can use a custom TLS config after registering it with [`mysql.RegisterTLSConfig`](https://godoc.org/github.com/go-sql-driver/mysql#RegisterTLSConfig). - **Type**: bool / string - **Valid Values**: true, false, skip-verify, preferred, - **Default**: false ### `connectionAttributes` [Connection attributes](https://dev.mysql.com/doc/refman/8.0/en/performance-schema-connection-attribute-tables.html) are key-value pairs that application programs can pass to the server at connect time. - **Type**: comma-delimited string of user-defined "key:value" pairs - **Valid Values**: (:,:,...) - **Default**: none ``` -------------------------------- ### Configure rejectReadOnly Source: https://github.com/cloudfoundry/cf-networking-helpers/blob/main/vendor/github.com/go-sql-driver/mysql/README.md Enables rejection of read-only connections to prevent issues during failover scenarios. ```text Type: bool Valid Values: true, false Default: false ``` -------------------------------- ### Implement HTTP Logging Middleware Source: https://context7.com/cloudfoundry/cf-networking-helpers/llms.txt Use LogWrapper to integrate request logging with UUID tracking. The middleware automatically injects a logger into the request context. ```go package main import ( "net/http" "code.cloudfoundry.org/cf-networking-helpers/middleware" "code.cloudfoundry.org/cf-networking-helpers/middleware/adapter" "code.cloudfoundry.org/lager/v3" ) func main() { logger := lager.NewLogger("myservice") logger.RegisterSink(lager.NewWriterSink(os.Stdout, lager.DEBUG)) // Create log wrapper with UUID generator logWrapper := &middleware.LogWrapper{ UUIDGenerator: adapter.UUIDAdapter{}, } // Your application handler appHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { // Retrieve logger from context requestLogger := r.Context().Value(middleware.LoggerKey).(lager.Logger) requestLogger.Info("processing-request") w.Write([]byte("Hello World")) }) // Wrap handler with logging middleware wrappedHandler := logWrapper.LogWrap(logger, appHandler) http.ListenAndServe(":8080", wrappedHandler) } ``` -------------------------------- ### Run All Gomega Tests Locally Source: https://github.com/cloudfoundry/cf-networking-helpers/blob/main/vendor/github.com/onsi/gomega/CONTRIBUTING.md Execute all tests in parallel to ensure they pass before submitting a pull request. This command is used to verify test coverage. ```bash ginkgo -r -p ``` -------------------------------- ### Configure timeout Source: https://github.com/cloudfoundry/cf-networking-helpers/blob/main/vendor/github.com/go-sql-driver/mysql/README.md Sets the dial timeout for establishing connections. ```text Type: duration Default: OS default ```