Fix build and startup. Ping from configuration peer 9still broken)
This commit is contained in:
@@ -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
93
main.go
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user