121 lines
3.0 KiB
Go
121 lines
3.0 KiB
Go
package pg
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
"path/filepath"
|
|
"time"
|
|
|
|
"github.com/balabanovds/pgcli/internal/core"
|
|
"github.com/balabanovds/pgcli/internal/kube"
|
|
)
|
|
|
|
type PgPassHandler struct {
|
|
orig string
|
|
bckp string
|
|
deleteOriginal bool
|
|
}
|
|
|
|
func NewPgPassHandler() (*PgPassHandler, error) {
|
|
if core.Homedir() == "" {
|
|
return nil, fmt.Errorf("unable to figure out your home dir")
|
|
}
|
|
|
|
h := &PgPassHandler{}
|
|
|
|
h.orig = filepath.Join(core.Homedir(), ".pgpass")
|
|
h.bckp = fmt.Sprintf("%s-%d", h.orig, time.Now().UnixMilli())
|
|
if !h.fileExists(h.orig) {
|
|
_, err := os.Create(h.orig)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to create .pgpass file for portforward: %w", err)
|
|
}
|
|
h.deleteOriginal = true
|
|
} else {
|
|
err := h.copyFile(h.orig, h.bckp)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to copy original file %s to backup %s: %w", h.orig, h.bckp, err)
|
|
}
|
|
}
|
|
|
|
return h, nil
|
|
}
|
|
|
|
func (h *PgPassHandler) Close() error {
|
|
if err := h.deleteFile(h.orig); err != nil {
|
|
return fmt.Errorf("failed to delete file %s: %w", h.orig, err)
|
|
}
|
|
|
|
if err := h.copyFile(h.bckp, h.orig); err != nil {
|
|
return fmt.Errorf("failed to copy file from %s to %s: %w", h.bckp, h.orig, err)
|
|
}
|
|
|
|
if h.deleteOriginal {
|
|
if err := h.deleteFile(h.orig); err != nil {
|
|
return fmt.Errorf("failed to delete file %s: %w", h.orig, err)
|
|
}
|
|
}
|
|
|
|
if err := h.deleteFile(h.bckp); err != nil {
|
|
return fmt.Errorf("failed to delete file %s: %w", h.bckp, err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (h *PgPassHandler) Append(sec *kube.Secret, localhost string, localport int) error {
|
|
f, err := os.OpenFile(h.orig, os.O_APPEND|os.O_WRONLY, 0o600)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to append data to file %s: %w", h.orig, err)
|
|
}
|
|
defer func() {
|
|
if cerr := f.Close(); cerr != nil {
|
|
fmt.Printf("failed to close file %s during appendL %s", h.orig, cerr)
|
|
}
|
|
}()
|
|
|
|
_, err = fmt.Fprintf(f, "# added by programm pgpf\n%s:%d:%s:%s:%s\n", localhost, localport, sec.DBName, sec.User, sec.Password)
|
|
|
|
return err
|
|
}
|
|
|
|
func (h *PgPassHandler) copyFile(src, dst string) error {
|
|
src = filepath.Clean(src)
|
|
fsrc, err := os.Open(src)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to open file %s: %w", src, err)
|
|
}
|
|
defer func() {
|
|
if cerr := fsrc.Close(); cerr != nil {
|
|
fmt.Printf("failed to close source file %s during copy: %s\n", src, cerr)
|
|
}
|
|
}()
|
|
|
|
dst = filepath.Clean(dst)
|
|
fdst, err := os.OpenFile(dst, os.O_CREATE|os.O_WRONLY, 0o600)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to open file %s: %w", dst, err)
|
|
}
|
|
defer func() {
|
|
if cerr := fdst.Close(); cerr != nil {
|
|
fmt.Printf("faled to close destination file %s during copy: %s\n", dst, cerr)
|
|
}
|
|
}()
|
|
|
|
_, err = io.Copy(fdst, fsrc)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to copy file from %s to %s: %w", src, dst, err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (h *PgPassHandler) fileExists(src string) bool {
|
|
_, err := os.Stat(src)
|
|
return err == nil || errors.Is(err, os.ErrNotExist)
|
|
}
|
|
|
|
func (h *PgPassHandler) deleteFile(src string) error {
|
|
return os.Remove(src)
|
|
}
|