Fix build and startup. Ping from configuration peer 9still broken)

This commit is contained in:
2024-04-04 00:41:59 +02:00
parent 08685bda47
commit f2156da671
2 changed files with 68 additions and 34 deletions

View File

@@ -1,4 +1,4 @@
FROM golang:1.21-bullseye AS builder FROM golang:1.20-alpine3.18 AS builder
WORKDIR /usr/local/src/pg_autopool WORKDIR /usr/local/src/pg_autopool
COPY go.* ./ COPY go.* ./
@@ -7,16 +7,17 @@ RUN go mod download
RUN mkdir bin/ && go build -o bin/ ./... RUN mkdir bin/ && go build -o bin/ ./...
FROM alpine FROM alpine:3.18
#RUN ca-certificates curl ldap-utils libaudit1 libbsd0 libcap-ng0 libcom-err2 libcrypt1 libedit2 libffi8 libgcc-s1 libgmp10 libgnutls30 libgssapi-krb5-2 libhogweed6 libicu72 libidn2-0 libk5crypto3 libkeyutils1 libkrb5-3 libkrb5support0 libldap-2.5-0 libldap-common liblzma5 libmd0 libnettle8 libnss-ldapd libp11-kit0 libpam-ldapd libpam0g libpq5 libsasl2-2 libssl3 libstdc++6 libtasn1-6 libtinfo6 libunistring2 libuuid1 libxml2 libxslt1.1 nslcd procps zlib1g #RUN ca-certificates curl ldap-utils libaudit1 libbsd0 libcap-ng0 libcom-err2 libcrypt1 libedit2 libffi8 libgcc-s1 libgmp10 libgnutls30 libgssapi-krb5-2 libhogweed6 libicu72 libidn2-0 libk5crypto3 libkeyutils1 libkrb5-3 libkrb5support0 libldap-2.5-0 libldap-common liblzma5 libmd0 libnettle8 libnss-ldapd libp11-kit0 libpam-ldapd libpam0g libpq5 libsasl2-2 libssl3 libstdc++6 libtasn1-6 libtinfo6 libunistring2 libuuid1 libxml2 libxslt1.1 nslcd procps zlib1g
RUN apk add --no-cache pgpool gettext postgresql-client && \ RUN apk add --no-cache pgpool gettext postgresql-client && \
mkdir /var/run/pgpool/ mkdir /var/run/pgpool/ && \
chmod 777 /var/run/pgpool
COPY --from=builder /usr/local/src/pg_autopool/bin/pg_autopool / COPY --from=builder /usr/local/src/pg_autopool/bin/pg_autopool /
#COPY ./conf /etc/pgpool #COPY ./conf /etc/pgpool
EXPOSE 5432 EXPOSE 5432
ENTRYPOINT ["/bin/sh", "/pg_autopool"] ENTRYPOINT ["/pg_autopool"]
CMD ["pgpool", "-n"] CMD ["pgpool", "-n"]

93
main.go
View File

@@ -2,7 +2,6 @@ package main
import ( import (
"encoding/json" "encoding/json"
"flag"
"fmt" "fmt"
"net" "net"
"net/http" "net/http"
@@ -10,13 +9,15 @@ import (
"os/exec" "os/exec"
"strconv" "strconv"
"strings" "strings"
"sync"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
) )
const version = "1.0" const version = "1.0"
const DefaultSocketPath = "/var/run/pg_autoconfig.sock" const DefaultSocketPath = "/var/run/pg_autoconfig.sock"
const PgpoolConfigPath = "/etc/pgpool/pgpool.conf" const WorkDir = "/var/run/pgpool"
const PgpoolConfigPath = WorkDir + "/pgpool.conf"
type pgpoolConfigMessage struct { type pgpoolConfigMessage struct {
Instances []pgpoolInstance Instances []pgpoolInstance
@@ -30,6 +31,10 @@ type pgpoolInstance struct {
IsReadOnly bool IsReadOnly bool
} }
type pgpoolPingMessage struct {
NeedsConfig bool
}
type pgpoolForcedKey struct { type pgpoolForcedKey struct {
hostName string hostName string
port int port int
@@ -54,8 +59,6 @@ type pgpoolNodeInfo struct {
} }
func main() { func main() {
flag.Parse()
// Logging // Logging
var logLevelS string var logLevelS string
if logLevelS = os.Getenv("AUTOPOOL_LOG_LEVEL"); logLevelS == "" { if logLevelS = os.Getenv("AUTOPOOL_LOG_LEVEL"); logLevelS == "" {
@@ -72,13 +75,10 @@ func main() {
nextIsSocket := false nextIsSocket := false
socketPath := DefaultSocketPath socketPath := DefaultSocketPath
var argsLeft []string for _, j := range os.Args[1:] {
for i, j := range os.Args {
if nextIsSocket { if nextIsSocket {
nextIsSocket = false nextIsSocket = false
socketPath = j socketPath = j
} else if j == "--" {
argsLeft = os.Args[i+1:]
} else { } else {
switch j { switch j {
case "--socket": case "--socket":
@@ -89,24 +89,49 @@ func main() {
} }
} }
if len(argsLeft) == 0 { // Set permissions as we usually run as non-root
log.Info("No inner command found to execute. Will execute pgpool -n") if err := os.Chown(WorkDir, os.Getuid(), os.Getgid()); err != nil {
argsLeft = []string{"pgpool", "-n"} log.WithFields(log.Fields{"dir": WorkDir, "uid": os.Getuid(), "gid": os.Getgid()}).Warn("Failed to set owner of the work directory to the current user.")
}
if err := os.Chmod(WorkDir, 700); err != nil {
log.WithFields(log.Fields{"dir": WorkDir, "uid": os.Getuid(), "gid": os.Getgid()}).Warn("Failed to chmod the working directory.")
} }
// Run the configuration change listener // Run the configuration change listener
// Note: we must remember all IP/port pairs that appeared during // Note: we must remember all IP/port pairs that appeared during
// the runtime of the pgpool instance so we can properly report // the runtime of the pgpool instance so we can properly report
// former nodes are down. // former nodes are down.
var intialConfigWait sync.WaitGroup
intialConfigWait.Add(1)
initialConfigDone := false
nodes := make(map[pgpoolNodeKey]pgpoolNodeInfo) nodes := make(map[pgpoolNodeKey]pgpoolNodeInfo)
handler := http.NewServeMux() handler := http.NewServeMux()
handler.HandleFunc("/ping", func(w http.ResponseWriter, r *http.Request) {
log.Trace("Received a ping")
var msg pgpoolPingMessage
msg.NeedsConfig = !initialConfigDone
if msgS, err := json.Marshal(msg); err != nil {
log.WithFields(log.Fields{"msg": msg}).Warn("Failed to serializeping message")
} else {
w.Header()["Content-Type"] = []string{"application/json"}
w.Header()["Content-Length"] = []string{strconv.Itoa(len(msgS))}
w.WriteHeader(http.StatusOK)
w.Write(msgS)
}
})
handler.HandleFunc("/config", func(w http.ResponseWriter, r *http.Request) { handler.HandleFunc("/config", func(w http.ResponseWriter, r *http.Request) {
var msg pgpoolConfigMessage var msg pgpoolConfigMessage
if err = json.NewDecoder(r.Body).Decode(&msg); err != nil { if err = json.NewDecoder(r.Body).Decode(&msg); err != nil {
http.Error(w, err.Error(), http.StatusBadRequest) http.Error(w, err.Error(), http.StatusBadRequest)
} }
configure(msg, nodes) log.Info("Received a new configuration")
configure(msg, nodes, !initialConfigDone)
if !initialConfigDone {
initialConfigDone = true
intialConfigWait.Done()
}
w.WriteHeader(http.StatusOK) w.WriteHeader(http.StatusOK)
w.Write([]byte("OK")) w.Write([]byte("OK"))
@@ -115,6 +140,7 @@ func main() {
Handler: handler, Handler: handler,
} }
go func() { go func() {
os.Remove(socketPath)
if listener, err := net.Listen("unix", socketPath); err != nil { if listener, err := net.Listen("unix", socketPath); err != nil {
log.WithError(err).Fatal("Failed to start config change listener") log.WithError(err).Fatal("Failed to start config change listener")
} else { } else {
@@ -123,8 +149,12 @@ func main() {
}() }()
// Start the inner executable (usually starting with "pg_autoctl create postgres" or "pg_autoctl create monitor") // Start the inner executable (usually starting with "pg_autoctl create postgres" or "pg_autoctl create monitor")
log.WithFields(log.Fields{"name": argsLeft[0], "args": argsLeft[1:]}).Info("Handling over to inner process.") log.Info("Waiting for the initial configuration to arrive")
cmd := exec.Command(argsLeft[0], argsLeft[1:]...) intialConfigWait.Wait()
log.Info("Handling over to the inner pgpool process")
cmd := exec.Command("pgpool", "-n", "--config-file", PgpoolConfigPath)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
//cmd.Env = os.Environ() //cmd.Env = os.Environ()
cmd.Run() cmd.Run()
@@ -132,7 +162,7 @@ func main() {
server.Close() server.Close()
} }
func configure(msg pgpoolConfigMessage, nodesHistory map[pgpoolNodeKey]pgpoolNodeInfo) { func configure(msg pgpoolConfigMessage, nodesHistory map[pgpoolNodeKey]pgpoolNodeInfo, isInitial bool) {
conf := make(map[string]string) conf := make(map[string]string)
// Note: We are mostly compatible with the bitnami pgpool docker regarding env vars // Note: We are mostly compatible with the bitnami pgpool docker regarding env vars
@@ -249,7 +279,7 @@ func configure(msg pgpoolConfigMessage, nodesHistory map[pgpoolNodeKey]pgpoolNod
conf["ssl_ca_cert"] = val conf["ssl_ca_cert"] = val
} }
conf["ssl_cert"] = getEnvOrDefault("PGPOOL_TLS_CERT_FILE", "") conf["ssl_cert"] = getEnvOrDefault("PGPOOL_TLS_CERT_FILE", "")
conf["ssl_cert"] = getEnvOrDefault("PGPOOL_TLS_KEY_FILE", "") conf["ssl_key"] = getEnvOrDefault("PGPOOL_TLS_KEY_FILE", "")
} }
// //
@@ -326,6 +356,7 @@ func configure(msg pgpoolConfigMessage, nodesHistory map[pgpoolNodeKey]pgpoolNod
// //
// Write the config file // Write the config file
// //
log.WithFields(log.Fields{"conf": conf}).Trace("New configuration")
if configFile, err := os.Create(PgpoolConfigPath); err != nil { if configFile, err := os.Create(PgpoolConfigPath); err != nil {
log.WithError(err).Fatal("Cannot open the pgpool config file.") log.WithError(err).Fatal("Cannot open the pgpool config file.")
} else { } else {
@@ -339,27 +370,29 @@ func configure(msg pgpoolConfigMessage, nodesHistory map[pgpoolNodeKey]pgpoolNod
configFile.Sync() configFile.Sync()
} }
// Reload config if !isInitial {
reloadCmd := exec.Command("pcp_reload_config", "-h", tmpDir, "-p", pgpoolPort, "--no-password") // Reload config
if err := reloadCmd.Run(); err != nil { reloadCmd := exec.Command("pcp_reload_config", "-h", tmpDir, "-p", pgpoolPort, "--no-password")
log.WithError(err).Warn("Failed to force config reload.") if err := reloadCmd.Run(); err != nil {
} log.WithError(err).Warn("Failed to force config reload.")
}
// Attach nodes // Attach nodes
for _, j := range msg.Instances { for _, j := range msg.Instances {
if info, exists := nodesHistory[pgpoolNodeKey{address: j.IpAddress.String(), port: j.Port}]; !exists { if info, exists := nodesHistory[pgpoolNodeKey{address: j.IpAddress.String(), port: j.Port}]; !exists {
log.WithFields(log.Fields{"address": j.IpAddress, "Port": j.Port}).Warn("Failed to resolve node number. Skipping attach.") log.WithFields(log.Fields{"address": j.IpAddress, "Port": j.Port}).Warn("Failed to resolve node number. Skipping attach.")
} else { } else {
attachCmd := exec.Command("pcp_attach_node", "-h", tmpDir, "-p", pgpoolPort, "--no-password", strconv.Itoa(info.num)) attachCmd := exec.Command("pcp_attach_node", "-h", tmpDir, "-p", pgpoolPort, "--no-password", strconv.Itoa(info.num))
if err := attachCmd.Run(); err != nil { if err := attachCmd.Run(); err != nil {
log.WithError(err).WithFields(log.Fields{"address": j.IpAddress, "Port": j.Port}).Warn("Node attach failed.") log.WithError(err).WithFields(log.Fields{"address": j.IpAddress, "Port": j.Port}).Warn("Node attach failed.")
}
} }
} }
} }
} }
func getEnvOrDefault(name string, defaultValue string) string { func getEnvOrDefault(name string, defaultValue string) string {
if val := os.Getenv(name); name != "" { if val := os.Getenv(name); val != "" {
return val return val
} else { } else {
return defaultValue return defaultValue