diff --git a/cmd/example-mysql/docker/Dockerfile b/cmd/example-mysql/docker/Dockerfile new file mode 100644 index 00000000..0857cfe6 --- /dev/null +++ b/cmd/example-mysql/docker/Dockerfile @@ -0,0 +1,16 @@ +FROM golang:1.22.5-bookworm@sha256:af9b40f2b1851be993763b85288f8434af87b5678af04355b1e33ff530b5765f as build + +WORKDIR /build + +# pre-copy/cache go.mod for pre-downloading dependencies and only redownloading them in subsequent builds if they change +COPY go.mod go.sum ./ +RUN go mod download && go mod verify + +COPY . . +RUN CGO_ENABLED=0 go build -v ./cmd/example-mysql + +FROM alpine:3.20@sha256:0a4eaa0eecf5f8c050e5bba433f58c052be7587ee8af3e8b3910ef9ab5fbe9f5 + +COPY --from=build /build/example-mysql /build/cmd/example-mysql/docker/testdata/key /build/cmd/example-mysql/docker/testdata/key.pub /build/storage/mysql/schema.sql / + +ENTRYPOINT ["/example-mysql"] diff --git a/cmd/example-mysql/docker/compose.yaml b/cmd/example-mysql/docker/compose.yaml new file mode 100644 index 00000000..f9618509 --- /dev/null +++ b/cmd/example-mysql/docker/compose.yaml @@ -0,0 +1,37 @@ +services: + + tessera-example-mysql-db: + container_name: tessera-mysql-db + image: "mysql:8.4" + ports: + - "3306:3306" + environment: + - MYSQL_ROOT_PASSWORD=tessera + - MYSQL_DATABASE=tessera + - MYSQL_USER=tessera + - MYSQL_PASSWORD=tessera + restart: always + healthcheck: + test: mysql --user=$$MYSQL_USER --password=$$MYSQL_PASSWORD --silent --execute "SHOW DATABASES;" + interval: 5s + timeout: 5s + retries: 10 + + tessera-example-mysql: + container_name: tessera-example-mysql + build: + context: ../../../ + dockerfile: ./cmd/example-mysql/docker/Dockerfile + ports: + - "2024:2024" + command: [ + "--mysql_uri=tessera:tessera@tcp(tessera-example-mysql-db:3306)/tessera", + "--init_schema_path=/schema.sql", + "--private_key_path=/key", + "--public_key_path=/key.pub", + "--alsologtostderr", + ] + restart: always + depends_on: + tessera-example-mysql-db: + condition: service_healthy diff --git a/cmd/example-mysql/docker/testdata/key b/cmd/example-mysql/docker/testdata/key new file mode 100644 index 00000000..1b687879 --- /dev/null +++ b/cmd/example-mysql/docker/testdata/key @@ -0,0 +1 @@ +PRIVATE+KEY+Test-Betty+df84580a+Afge8kCzBXU7jb3cV2Q363oNXCufJ6u9mjOY1BGRY9E2 \ No newline at end of file diff --git a/cmd/example-mysql/docker/testdata/key.pub b/cmd/example-mysql/docker/testdata/key.pub new file mode 100644 index 00000000..6794e261 --- /dev/null +++ b/cmd/example-mysql/docker/testdata/key.pub @@ -0,0 +1 @@ +Test-Betty+df84580a+AQQASqPUZoIHcJAF5mBOryctwFdTV1E0GRY4kEAtTzwB \ No newline at end of file diff --git a/cmd/example-mysql/main.go b/cmd/example-mysql/main.go index 4ba5461f..7ed6a1cc 100644 --- a/cmd/example-mysql/main.go +++ b/cmd/example-mysql/main.go @@ -38,6 +38,7 @@ var ( dbConnMaxLifetime = flag.Duration("db_conn_max_lifetime", 3*time.Minute, "") dbMaxOpenConns = flag.Int("db_max_open_conns", 64, "") dbMaxIdleConns = flag.Int("db_max_idle_conns", 64, "") + initSchemaPath = flag.String("init_schema_path", "", "Location of the schema file if database initialization is needed") listen = flag.String("listen", ":2024", "Address:port to listen on") privateKeyPath = flag.String("private_key_path", "", "Location of private key file") publicKeyPath = flag.String("public_key_path", "", "Location of public key file") @@ -56,6 +57,8 @@ func main() { db.SetMaxOpenConns(*dbMaxOpenConns) db.SetMaxIdleConns(*dbMaxIdleConns) + initDatabaseSchema(ctx) + rawPrivateKey, err := os.ReadFile(*privateKeyPath) if err != nil { klog.Exitf("Failed to read private key file %q: %v", *privateKeyPath, err) @@ -242,3 +245,29 @@ func parseTileIndexWidth(index string) (uint64, uint64, error) { return i, w, nil } + +func initDatabaseSchema(ctx context.Context) { + if *initSchemaPath != "" { + klog.Infof("Initializing database schema") + + db, err := sql.Open("mysql", *mysqlURI+"?multiStatements=true") + if err != nil { + klog.Exitf("Failed to connect to DB: %v", err) + } + defer func() { + if err := db.Close(); err != nil { + klog.Warningf("Failed to close db: %v", err) + } + }() + + rawSchema, err := os.ReadFile(*initSchemaPath) + if err != nil { + klog.Exitf("Failed to read init schema file %q: %v", *initSchemaPath, err) + } + if _, err := db.ExecContext(ctx, string(rawSchema)); err != nil { + klog.Exitf("Failed to execute init database schema: %v", err) + } + + klog.Infof("Database schema initialized") + } +}