rework err

This commit is contained in:
rmanach 2025-04-02 11:18:23 +02:00
parent 04e14928f3
commit 771a0e50bd
6 changed files with 54 additions and 62 deletions

View File

@ -2,6 +2,7 @@ package connection
import (
"bytes"
"errors"
"fmt"
"io"
"net"
@ -20,6 +21,16 @@ type SSHConn struct {
var _ IConnection = (*SSHConn)(nil)
var (
ErrSSHDial = errors.New("unable to dial ssh addr")
ErrSSHConn = errors.New("unable to establish a new connection")
ErrSShCopy = errors.New("unable to copy file")
ErrSSHSession = errors.New("unable to open a new session")
ErrSSHReadPrivateKey = errors.New("unable to read private key")
ErrSSHParsePrivateKey = errors.New("unable to read private key")
ErrSSHExecute = errors.New("unable")
)
func NewSSHConn(addr, user string, port int, privkey string) (SSHConn, error) {
var newconn SSHConn
@ -28,20 +39,17 @@ func NewSSHConn(addr, user string, port int, privkey string) (SSHConn, error) {
conn, err := net.Dial("tcp", sshAddr)
if err != nil {
log.Err(err).Str("addr", addr).Msg("unable to dial ssh addr")
return newconn, err
return newconn, fmt.Errorf("%w, addr=%s, err=%v", ErrSSHDial, addr, err)
}
c, err := os.ReadFile(privkey)
if err != nil {
log.Err(err).Str("private key", privkey).Msg("unable to read ssh private key")
return newconn, err
return newconn, fmt.Errorf("%w, privkey=%s, err=%v", ErrSSHReadPrivateKey, privkey, err)
}
sshPrivKey, err := ssh.ParsePrivateKey(c)
if err != nil {
log.Err(err).Str("private key", privkey).Msg("unable to parse ssh private key")
return newconn, err
return newconn, fmt.Errorf("%w, privkey=%s, err=%v", ErrSSHParsePrivateKey, privkey, err)
}
sshConfig := ssh.ClientConfig{
@ -54,14 +62,12 @@ func NewSSHConn(addr, user string, port int, privkey string) (SSHConn, error) {
sshConn, chNewChannel, chReq, err := ssh.NewClientConn(conn, sshAddr, &sshConfig)
if err != nil {
log.Err(err).Str("addr", sshAddr).Msg("unable to establish a new connection to the swarm")
return newconn, err
return newconn, fmt.Errorf("%w, addr=%s, err=%v", ErrSSHConn, sshAddr, err)
}
sshClient := ssh.NewClient(sshConn, chNewChannel, chReq)
newconn.client = sshClient
log.Info().Str("addr", addr).Int("port", port).Msg("ssh connection sucessfully initialized")
return newconn, nil
}
@ -72,21 +78,18 @@ func (c *SSHConn) Close() error {
func (c *SSHConn) CopyFile(src, dest string) error {
sshSession, err := c.client.NewSession()
if err != nil {
log.Err(err).Str("addr", c.addr).Msg("unable to open an ssh session")
return err
return fmt.Errorf("%w, addr=%s, err=%v", ErrSSHSession, c.addr, err)
}
defer sshSession.Close()
fileInfo, err := os.Stat(src)
if err != nil {
log.Err(err).Str("file", src).Msg("unable to stat scp source file")
return err
return fmt.Errorf("unable to stat scp source file src=%s, err=%v", src, err)
}
file, err := os.Open(src)
if err != nil {
log.Err(err).Str("file", src).Msg("unable to open scp source file")
return err
return fmt.Errorf("unable to open scp source file src=%s, err=%v", src, err)
}
defer file.Close()
@ -97,7 +100,7 @@ func (c *SSHConn) CopyFile(src, dest string) error {
fmt.Fprintf(w, "C0644 %d %s\n", fileInfo.Size(), filepath.Base(dest))
if _, err := io.Copy(w, file); err != nil {
log.Err(err).Str("src", src).Str("dest", dest).Msg("unable to scp src to dest")
log.Debug().Err(err).Str("src", src).Str("dest", dest).Msg("unable to scp src to dest")
return
}
@ -105,27 +108,23 @@ func (c *SSHConn) CopyFile(src, dest string) error {
}()
if err := sshSession.Run(fmt.Sprintf("scp -t %s", dest)); err != nil {
log.Err(err).Str("addr", c.addr).Str("dest", dest).Msg("unable to run scp command")
return err
return fmt.Errorf("%w, addr=%s, src=%s, dest=%s, err=%v", ErrSShCopy, c.addr, src, dest, err)
}
log.Info().Str("src", src).Str("dest", dest).Msg("file successfully uploaded")
return nil
}
func (c *SSHConn) Execute(cmd string) (string, error) {
sshSession, err := c.client.NewSession()
if err != nil {
log.Err(err).Str("addr", c.addr).Msg("unable to open an ssh session")
return "", err
return "", fmt.Errorf("%w, addr=%s, err=%v", ErrSSHSession, c.addr, err)
}
defer sshSession.Close()
var buf bytes.Buffer
sshSession.Stdout = &buf
if err := sshSession.Run(cmd); err != nil {
log.Err(err).Str("addr", c.addr).Str("command", cmd).Msg("unable to execute an ssh command")
return "", err
return "", fmt.Errorf("%w, addr=%s, cmd=%s, err=%v", ErrSSHExecute, c.addr, cmd, err)
}
return "", nil

View File

@ -6,11 +6,10 @@ import (
"os"
"path/filepath"
"github.com/rs/zerolog/log"
"gitea.thegux.fr/hmdeploy/connection"
"gitea.thegux.fr/hmdeploy/docker"
"gitea.thegux.fr/hmdeploy/models"
"github.com/rs/zerolog/log"
)
type SwarmDeployer struct {
@ -57,12 +56,16 @@ func (sd *SwarmDeployer) clean() (err error) {
func (sd *SwarmDeployer) Deploy() error {
defer sd.clean()
if sd.project.ImageName != "" {
tarFile, err := sd.dcli.Save(sd.project.ImageName, sd.project.Dir)
if imageName := sd.project.ImageName; imageName != "" {
log.Info().Str("image", imageName).Msg("saving image for transfert...")
tarFile, err := sd.dcli.Save(imageName, sd.project.Dir)
if err != nil {
return err
}
log.Info().Str("image", imageName).Str("dir", sd.project.Dir).Msg("image saved successfully")
defer os.Remove(tarFile)
tarFileBase := filepath.Base(tarFile)
@ -91,6 +94,5 @@ func (sd *SwarmDeployer) Deploy() error {
return err
}
log.Info().Msg("project deployed successfully on swarm")
return nil
}

View File

@ -1,18 +1,19 @@
package docker
import (
"errors"
"fmt"
"os"
"os/exec"
"path/filepath"
"github.com/rs/zerolog/log"
)
type IClient interface {
Save(imageName, dest string) (string, error)
}
var ErrDockerClientSave = errors.New("unable to save image into tar")
type Client struct{}
var _ IClient = (*Client)(nil)
@ -24,12 +25,11 @@ func NewClient() Client {
func (c *Client) Save(imageName, dest string) (string, error) {
destInfo, err := os.Stat(dest)
if err != nil {
log.Err(err).Str("dest", dest).Msg("unable to stat dest directory")
return "", err
return "", fmt.Errorf("unable to stat file, dir=%s, err=%v", dest, err)
}
if !destInfo.IsDir() {
log.Err(err).Str("dest", dest).Msg("dest directory must be a directory")
return "", fmt.Errorf("dest file must be a directory, dir=%s, err=%v", dest, err)
}
tarFile := fmt.Sprintf("%s.tar", imageName)
@ -37,10 +37,8 @@ func (c *Client) Save(imageName, dest string) (string, error) {
cmd := exec.Command("docker", "save", "-o", tarFile, imageName)
cmd.Dir = dest
if _, err := cmd.Output(); err != nil {
log.Err(err).Str("image", imageName).Str("dest", dest).Msg("unable to save image into tar")
return dest, err
return "", fmt.Errorf("%w, dir=%s, image=%s, err=%v", ErrDockerClientSave, dest, imageName, err)
}
log.Info().Str("image", imageName).Str("dest", dest).Msg("image successfully saved")
return filepath.Join(dest, tarFile), nil
}

View File

@ -59,17 +59,20 @@ func main() {
project, err := models.ProjectFromDir(*projectDir)
if err != nil {
os.Exit(1)
log.Fatal().Str("dir", *projectDir).Err(err).Msg("unable to init project from directory")
}
log.Info().Str("dir", project.Dir).Str("name", project.Name).Msg("project initialized with success")
dcli := docker.NewClient()
sd, err := deployers.NewSwarmDeployer(ctx, &dcli, swarmNet, &project)
if err != nil {
os.Exit(1)
log.Fatal().Err(err).Msg("unable to init swarm deployer")
}
if err := sd.Deploy(); err != nil {
os.Exit(1)
log.Fatal().Err(err).Msg("unable to deploy project")
}
log.Info().Str("name", project.Name).Msg("project deployed successfully")
}

View File

@ -2,8 +2,6 @@ package models
import (
"net"
"github.com/rs/zerolog/log"
)
type HMNetInfo struct {
@ -28,7 +26,6 @@ type HMMap struct {
func (hm *HMMap) GetSwarmNetInfo() *HMNetInfo {
data, ok := hm.VM["swarm"]
if !ok {
log.Error().Msg("unable to get swarm net info, check your configuration")
return nil
}

View File

@ -21,11 +21,7 @@ const (
ConfFile = "hmdeploy.json"
)
var (
ErrInvalidEnvFile = errors.New("unable to stat .env file")
ErrInvalidComposeFile = errors.New("unable to stat compose file")
ErrInvalidNginxFile = errors.New("unable to stat nginx file")
)
var ErrProjectConfFile = errors.New("project error")
func getFileInfo(baseDir, filePath string) (fs.FileInfo, error) {
var fInf fs.FileInfo
@ -33,14 +29,14 @@ func getFileInfo(baseDir, filePath string) (fs.FileInfo, error) {
filePath = filepath.Clean(filePath)
filePath = filepath.Join(baseDir, filePath)
composePath, err := filepath.Abs(filePath)
fileAbsPath, err := filepath.Abs(filePath)
if err != nil {
return fInf, fmt.Errorf("%w, %v", ErrInvalidComposeFile, err)
return fInf, fmt.Errorf("%w, file=%s, err=%v", ErrProjectConfFile, fileAbsPath, err)
}
fInf, err = os.Stat(composePath)
fInf, err = os.Stat(fileAbsPath)
if err != nil {
return fInf, fmt.Errorf("%w, %v", ErrInvalidComposeFile, err)
return fInf, fmt.Errorf("%w, unable to stat file=%s, err=%v", ErrProjectConfFile, fileAbsPath, err)
}
return fInf, nil
@ -65,23 +61,23 @@ type Project struct {
func (p *Project) validate() error {
cfs, err := getFileInfo(p.Dir, p.Deps.ComposeFile)
if err != nil {
return fmt.Errorf("%w, %v", ErrInvalidComposeFile, err)
return err
}
p.Deps.ComposeFileInfo = cfs
if p.Deps.EnvFile != "" {
efs, err := getFileInfo(p.Dir, p.Deps.EnvFile)
if err != nil {
return fmt.Errorf("%w, %v", ErrInvalidEnvFile, err)
return err
}
p.Deps.EnvFileInfo = efs
} else {
log.Warn().Msg("no .env file provided, hoping one is set elsewhere...")
log.Warn().Msg("no .env file provided, hoping one it's set elsewhere...")
}
nfs, err := getFileInfo(p.Dir, p.Deps.EnvFile)
nfs, err := getFileInfo(p.Dir, p.Deps.NginxFile)
if err != nil {
return fmt.Errorf("%w, %v", ErrInvalidNginxFile, err)
return err
}
p.Deps.NginxFileInfo = nfs
@ -96,18 +92,15 @@ func ProjectFromDir(dir string) (Project, error) {
content, err := os.ReadFile(filepath.Join(dir, ConfFile))
if err != nil {
log.Err(err).Str("dir", dir).Str("conf", ConfFile).Msg("unable to read conf file")
return p, err
return p, fmt.Errorf("%w, unable to read conf file=%s, err=%v", ErrProjectConfFile, ConfFile, err)
}
if err := json.Unmarshal(content, &p); err != nil {
log.Err(err).Str("dir", dir).Str("conf", ConfFile).Msg("unable to parse conf file")
return p, err
return p, fmt.Errorf("%w, unable to parse conf file=%s, err=%v", ErrProjectConfFile, ConfFile, err)
}
if err := p.validate(); err != nil {
log.Err(err).Str("dir", dir).Msg("unable to validate project")
return p, err
return p, fmt.Errorf("%w, unable to validate project, name=%s, dir=%s, err=%v", ErrProjectConfFile, p.Name, p.Dir, err)
}
return p, nil