// Copyright (C) The Arvados Authors. All rights reserved. // // SPDX-License-Identifier: AGPL-3.0 package boot import ( "bytes" "context" "database/sql" "fmt" "os" "os/exec" "path/filepath" "strings" "time" "git.arvados.org/arvados.git/sdk/go/arvados" "github.com/lib/pq" ) type runPostgreSQL struct{} func (runPostgreSQL) String() string { return "postgresql" } func (runPostgreSQL) Run(ctx context.Context, fail func(error), boot *Booter) error { err := boot.wait(ctx, createCertificates{}) if err != nil { return err } buf := bytes.NewBuffer(nil) err = boot.RunProgram(ctx, boot.tempdir, buf, nil, "pg_config", "--bindir") if err != nil { return err } datadir := filepath.Join(boot.tempdir, "pgdata") err = os.Mkdir(datadir, 0755) if err != nil { return err } bindir := strings.TrimSpace(buf.String()) err = boot.RunProgram(ctx, boot.tempdir, nil, nil, filepath.Join(bindir, "initdb"), "-D", datadir) if err != nil { return err } err = boot.RunProgram(ctx, boot.tempdir, nil, nil, "cp", "server.crt", "server.key", datadir) if err != nil { return err } port := boot.cluster.PostgreSQL.Connection["port"] go func() { fail(boot.RunProgram(ctx, boot.tempdir, nil, nil, filepath.Join(bindir, "postgres"), "-l", // enable ssl "-D", datadir, // data dir "-k", datadir, // socket dir "-p", boot.cluster.PostgreSQL.Connection["port"], )) }() for { if ctx.Err() != nil { return ctx.Err() } if exec.CommandContext(ctx, "pg_isready", "--timeout=10", "--host="+boot.cluster.PostgreSQL.Connection["host"], "--port="+port).Run() == nil { break } time.Sleep(time.Second / 2) } db, err := sql.Open("postgres", arvados.PostgreSQLConnection{ "host": datadir, "port": port, "dbname": "postgres", }.String()) if err != nil { return fmt.Errorf("db open failed: %s", err) } defer db.Close() conn, err := db.Conn(ctx) if err != nil { return fmt.Errorf("db conn failed: %s", err) } defer conn.Close() _, err = conn.ExecContext(ctx, `CREATE USER `+pq.QuoteIdentifier(boot.cluster.PostgreSQL.Connection["user"])+` WITH SUPERUSER ENCRYPTED PASSWORD `+pq.QuoteLiteral(boot.cluster.PostgreSQL.Connection["password"])) if err != nil { return fmt.Errorf("createuser failed: %s", err) } _, err = conn.ExecContext(ctx, `CREATE DATABASE `+pq.QuoteIdentifier(boot.cluster.PostgreSQL.Connection["dbname"])) if err != nil { return fmt.Errorf("createdb failed: %s", err) } return nil }