From bbab3d640baf8728027a29adbae3f3a44ca874d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Garc=C3=ADa?= Date: Wed, 2 Aug 2023 18:22:10 -0500 Subject: [PATCH] add dockerfile for dsnexec and documentation (#162) Co-authored-by: Balaji Jeevan <32107263+bjeevan-ib@users.noreply.github.com> --- dsnexec/.dockerignore | 1 + dsnexec/Dockerfile | 26 ++++++++++++++++++++++++++ dsnexec/pkg/fprintf/driver.go | 10 ++++++++++ dsnexec/pkg/fprintf/file_handler.go | 2 ++ dsnexec/pkg/fprintf/templater.go | 2 ++ dsnexec/pkg/shelldb/shelldb.go | 16 +++++++++++----- dsnexec/pkg/tdb/tdb.go | 17 +++++++++++++++++ 7 files changed, 69 insertions(+), 5 deletions(-) create mode 100644 dsnexec/.dockerignore create mode 100644 dsnexec/Dockerfile diff --git a/dsnexec/.dockerignore b/dsnexec/.dockerignore new file mode 100644 index 00000000..2152e479 --- /dev/null +++ b/dsnexec/.dockerignore @@ -0,0 +1 @@ +./dsnexec diff --git a/dsnexec/Dockerfile b/dsnexec/Dockerfile new file mode 100644 index 00000000..93e012ec --- /dev/null +++ b/dsnexec/Dockerfile @@ -0,0 +1,26 @@ +FROM golang:1.20 as builder + +WORKDIR /app + +COPY go.* ./ +COPY *.go ./ +COPY pkg/ pkg/ +COPY cmd/ cmd/ +COPY test/ test/ + +RUN go mod download +RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o /dsnexec + +FROM alpine:3.18 + +RUN apk add -U --no-cache udns libevent openssl ca-certificates postgresql-client +RUN adduser -D -S -s /bin/sh dsnexec + +COPY --from=builder /dsnexec /usr/bin/dsnexec +RUN chmod +x /usr/bin/dsnexec +RUN mkdir -p /var/run/dsnexec +WORKDIR /var/run/dsnexec + +USER dsnexec + +ENTRYPOINT ["/usr/bin/dsnexec"] diff --git a/dsnexec/pkg/fprintf/driver.go b/dsnexec/pkg/fprintf/driver.go index c42fc36f..3ed387b7 100644 --- a/dsnexec/pkg/fprintf/driver.go +++ b/dsnexec/pkg/fprintf/driver.go @@ -17,6 +17,7 @@ func init() { sql.Register("fprintf", &d{}) } +// Open a new connection to the fprintf driver. func (d *d) Open(name string) (driver.Conn, error) { uri, err := url.Parse(name) if err != nil { @@ -44,10 +45,14 @@ type conn struct { templater Templater } +// Exec a query against the fprintf driver. The query represents the format string +// to use. The args are passed to the format arguments. func (c *conn) Exec(query string, args []driver.Value) (driver.Result, error) { return c.ExecContext(context.Background(), query, args) } +// ExecContext a query against the fprintf driver. The query represents the format string +// to use. The args are passed to the format arguments. The context is ignored. func (c *conn) ExecContext(ctx context.Context, query string, args []driver.Value) (driver.Result, error) { log := log.WithFields(log.Fields{ @@ -84,22 +89,27 @@ func (c *conn) ExecContext(ctx context.Context, query string, args []driver.Valu type result struct{} +// LastInsertId is used to implement the fprintf driver. It is not supported. func (r *result) LastInsertId() (int64, error) { return 0, fmt.Errorf("unsupported LastInsertId in shell driver") } +// RowsAffected is used to implement the fprintf driver. It is not supported. func (r *result) RowsAffected() (int64, error) { return 0, fmt.Errorf("unsupported RowsAffected in shell driver") } +// Prepare is used to implement the fprintf driver. It is not supported. func (c *conn) Prepare(query string) (driver.Stmt, error) { return nil, fmt.Errorf("unsupported Prepare in shell driver") } +// Begin is used to implement the fprintf driver. It is not supported. func (c *conn) Begin() (driver.Tx, error) { return nil, fmt.Errorf("unsupported Begin in shell driver") } +// Close is used to implement the fprintf driver. It is not supported. func (c *conn) Close() error { return nil } diff --git a/dsnexec/pkg/fprintf/file_handler.go b/dsnexec/pkg/fprintf/file_handler.go index 4795eba8..d833788f 100644 --- a/dsnexec/pkg/fprintf/file_handler.go +++ b/dsnexec/pkg/fprintf/file_handler.go @@ -13,6 +13,8 @@ var ( fileHandlers map[string]FileHandler = make(map[string]FileHandler) ) +// FileHandler returns an io.WriteCloser that will handle the details of writing to the given +// filename. The filename could respresent a resource, such as a database, or a file. type FileHandler func(ctx context.Context, filename string) (io.WriteCloser, error) func init() { diff --git a/dsnexec/pkg/fprintf/templater.go b/dsnexec/pkg/fprintf/templater.go index 2be38f4b..3066f535 100644 --- a/dsnexec/pkg/fprintf/templater.go +++ b/dsnexec/pkg/fprintf/templater.go @@ -9,6 +9,8 @@ var ( templaters map[string]Templater = make(map[string]Templater) ) +// Templater is a function that will write the formatted string to the writer. The +// templater is responsible for handling the templating. type Templater func(io.Writer, string, ...interface{}) (int, error) func init() { diff --git a/dsnexec/pkg/shelldb/shelldb.go b/dsnexec/pkg/shelldb/shelldb.go index e4f92c2f..08631a6e 100644 --- a/dsnexec/pkg/shelldb/shelldb.go +++ b/dsnexec/pkg/shelldb/shelldb.go @@ -17,6 +17,7 @@ func init() { sql.Register("shelldb", &d{}) } +// Open a new connection to the shell driver. func (d *d) Open(name string) (driver.Conn, error) { return &conn{ name: name, @@ -27,11 +28,8 @@ type conn struct { name string } -type ExecArgs struct { - Query string - Args []driver.Value -} - +// Exec a query against the shell driver. The query represents the command to +// run. The args are passed to the command as arguments. func (c *conn) Exec(query string, args []driver.Value) (driver.Result, error) { return c.ExecContext(context.Background(), query, args) } @@ -45,6 +43,9 @@ func (lw logWriter) Write(p []byte) (n int, err error) { return len(p), nil } +// ExecContext a query against the shell driver. The query represents the command to +// run. The args are passed to the command as arguments. The context is used to +// cancel the command if the context is canceled. func (c *conn) ExecContext(ctx context.Context, query string, args []driver.Value) (driver.Result, error) { var cmd *exec.Cmd @@ -71,22 +72,27 @@ func (c *conn) ExecContext(ctx context.Context, query string, args []driver.Valu type result struct{} +// LastInsertId is not supported by the shell driver. func (r *result) LastInsertId() (int64, error) { return 0, fmt.Errorf("unsupported LastInsertId in shell driver") } +// RowsAffected is not supported by the shell driver. func (r *result) RowsAffected() (int64, error) { return 0, fmt.Errorf("unsupported RowsAffected in shell driver") } +// Prepare is not supported by the shell driver. func (c *conn) Prepare(query string) (driver.Stmt, error) { return nil, fmt.Errorf("unsupported Prepare in shell driver") } +// Begin is not supported by the shell driver. func (c *conn) Begin() (driver.Tx, error) { return nil, fmt.Errorf("unsupported Begin in shell driver") } +// Close implements the driver.Conn interface. This is a no-op for the shell. func (c *conn) Close() error { return nil } diff --git a/dsnexec/pkg/tdb/tdb.go b/dsnexec/pkg/tdb/tdb.go index b3b34bcf..90c1adb3 100644 --- a/dsnexec/pkg/tdb/tdb.go +++ b/dsnexec/pkg/tdb/tdb.go @@ -25,6 +25,9 @@ func init() { sql.Register("tdb", defaultDriver) } +// Open returns a new connection to the mock database. The given name +// must match previously registered test case. Those cases can be registered +// by calling RegisterTestCase. func (d *d) Open(name string) (driver.Conn, error) { d.mu.RLock() defer d.mu.RUnlock() @@ -41,11 +44,14 @@ type testCase struct { execCalls []ExecArgs } +// ExecArgs is a helper struct that encapsulates the arguments based to sql.Exec. type ExecArgs struct { Query string Args []driver.Value } +// RegisterTestCase registers a new test case with the given name. The returned +// function can be used to retrieve the arguments passed to sql.Exec. func RegisterTestCase(t *testing.T, ctx context.Context, name string) func() []ExecArgs { tc := &testCase{ t: t, @@ -67,6 +73,7 @@ func (tc *testCase) getExecCalls() []ExecArgs { return execCalls } +// Exec implements the driver.Conn interface for the mock database. func (tc *testCase) Exec(query string, args []driver.Value) (driver.Result, error) { tc.t.Logf("exec: %s ; %v", query, args) tc.execCalls = append(tc.execCalls, ExecArgs{ @@ -78,22 +85,32 @@ func (tc *testCase) Exec(query string, args []driver.Value) (driver.Result, erro type result struct{} +// LastInsertId implements the driver.Result interface for the mock database. It +// is not supported. func (r *result) LastInsertId() (int64, error) { return 0, fmt.Errorf("unsupported LastInsertId in tdb") } +// RowsAffected implements the driver.Result interface for the mock database. It +// is not supported. func (r *result) RowsAffected() (int64, error) { return 0, fmt.Errorf("unsupported RowsAffected in tdb") } +// Prepare implements the driver.Conn interface for the mock database. It is not +// supported. func (tc *testCase) Prepare(query string) (driver.Stmt, error) { return nil, fmt.Errorf("unsupported Prepare in tdb") } +// Close implements the driver.Conn interface for the mock database. It is not +// supported. func (tc *testCase) Begin() (driver.Tx, error) { return nil, fmt.Errorf("unsupported Begin in tdb") } +// Close implements the driver.Conn interface for the mock database. It is not +// supported. func (tc *testCase) Close() error { return nil }