rework err
This commit is contained in:
parent
04e14928f3
commit
771a0e50bd
@ -2,6 +2,7 @@ package connection
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
@ -20,6 +21,16 @@ type SSHConn struct {
|
|||||||
|
|
||||||
var _ IConnection = (*SSHConn)(nil)
|
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) {
|
func NewSSHConn(addr, user string, port int, privkey string) (SSHConn, error) {
|
||||||
var newconn SSHConn
|
var newconn SSHConn
|
||||||
|
|
||||||
@ -28,20 +39,17 @@ func NewSSHConn(addr, user string, port int, privkey string) (SSHConn, error) {
|
|||||||
|
|
||||||
conn, err := net.Dial("tcp", sshAddr)
|
conn, err := net.Dial("tcp", sshAddr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Err(err).Str("addr", addr).Msg("unable to dial ssh addr")
|
return newconn, fmt.Errorf("%w, addr=%s, err=%v", ErrSSHDial, addr, err)
|
||||||
return newconn, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
c, err := os.ReadFile(privkey)
|
c, err := os.ReadFile(privkey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Err(err).Str("private key", privkey).Msg("unable to read ssh private key")
|
return newconn, fmt.Errorf("%w, privkey=%s, err=%v", ErrSSHReadPrivateKey, privkey, err)
|
||||||
return newconn, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sshPrivKey, err := ssh.ParsePrivateKey(c)
|
sshPrivKey, err := ssh.ParsePrivateKey(c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Err(err).Str("private key", privkey).Msg("unable to parse ssh private key")
|
return newconn, fmt.Errorf("%w, privkey=%s, err=%v", ErrSSHParsePrivateKey, privkey, err)
|
||||||
return newconn, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sshConfig := ssh.ClientConfig{
|
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)
|
sshConn, chNewChannel, chReq, err := ssh.NewClientConn(conn, sshAddr, &sshConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Err(err).Str("addr", sshAddr).Msg("unable to establish a new connection to the swarm")
|
return newconn, fmt.Errorf("%w, addr=%s, err=%v", ErrSSHConn, sshAddr, err)
|
||||||
return newconn, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sshClient := ssh.NewClient(sshConn, chNewChannel, chReq)
|
sshClient := ssh.NewClient(sshConn, chNewChannel, chReq)
|
||||||
newconn.client = sshClient
|
newconn.client = sshClient
|
||||||
|
|
||||||
log.Info().Str("addr", addr).Int("port", port).Msg("ssh connection sucessfully initialized")
|
|
||||||
return newconn, nil
|
return newconn, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -72,21 +78,18 @@ func (c *SSHConn) Close() error {
|
|||||||
func (c *SSHConn) CopyFile(src, dest string) error {
|
func (c *SSHConn) CopyFile(src, dest string) error {
|
||||||
sshSession, err := c.client.NewSession()
|
sshSession, err := c.client.NewSession()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Err(err).Str("addr", c.addr).Msg("unable to open an ssh session")
|
return fmt.Errorf("%w, addr=%s, err=%v", ErrSSHSession, c.addr, err)
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
defer sshSession.Close()
|
defer sshSession.Close()
|
||||||
|
|
||||||
fileInfo, err := os.Stat(src)
|
fileInfo, err := os.Stat(src)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Err(err).Str("file", src).Msg("unable to stat scp source file")
|
return fmt.Errorf("unable to stat scp source file src=%s, err=%v", src, err)
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
file, err := os.Open(src)
|
file, err := os.Open(src)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Err(err).Str("file", src).Msg("unable to open scp source file")
|
return fmt.Errorf("unable to open scp source file src=%s, err=%v", src, err)
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
defer file.Close()
|
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))
|
fmt.Fprintf(w, "C0644 %d %s\n", fileInfo.Size(), filepath.Base(dest))
|
||||||
|
|
||||||
if _, err := io.Copy(w, file); err != nil {
|
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
|
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 {
|
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 fmt.Errorf("%w, addr=%s, src=%s, dest=%s, err=%v", ErrSShCopy, c.addr, src, dest, err)
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Info().Str("src", src).Str("dest", dest).Msg("file successfully uploaded")
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *SSHConn) Execute(cmd string) (string, error) {
|
func (c *SSHConn) Execute(cmd string) (string, error) {
|
||||||
sshSession, err := c.client.NewSession()
|
sshSession, err := c.client.NewSession()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Err(err).Str("addr", c.addr).Msg("unable to open an ssh session")
|
return "", fmt.Errorf("%w, addr=%s, err=%v", ErrSSHSession, c.addr, err)
|
||||||
return "", err
|
|
||||||
}
|
}
|
||||||
defer sshSession.Close()
|
defer sshSession.Close()
|
||||||
|
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
sshSession.Stdout = &buf
|
sshSession.Stdout = &buf
|
||||||
if err := sshSession.Run(cmd); err != nil {
|
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 "", fmt.Errorf("%w, addr=%s, cmd=%s, err=%v", ErrSSHExecute, c.addr, cmd, err)
|
||||||
return "", err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return "", nil
|
return "", nil
|
||||||
|
|||||||
@ -6,11 +6,10 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
"github.com/rs/zerolog/log"
|
|
||||||
|
|
||||||
"gitea.thegux.fr/hmdeploy/connection"
|
"gitea.thegux.fr/hmdeploy/connection"
|
||||||
"gitea.thegux.fr/hmdeploy/docker"
|
"gitea.thegux.fr/hmdeploy/docker"
|
||||||
"gitea.thegux.fr/hmdeploy/models"
|
"gitea.thegux.fr/hmdeploy/models"
|
||||||
|
"github.com/rs/zerolog/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
type SwarmDeployer struct {
|
type SwarmDeployer struct {
|
||||||
@ -57,12 +56,16 @@ func (sd *SwarmDeployer) clean() (err error) {
|
|||||||
func (sd *SwarmDeployer) Deploy() error {
|
func (sd *SwarmDeployer) Deploy() error {
|
||||||
defer sd.clean()
|
defer sd.clean()
|
||||||
|
|
||||||
if sd.project.ImageName != "" {
|
if imageName := sd.project.ImageName; imageName != "" {
|
||||||
tarFile, err := sd.dcli.Save(sd.project.ImageName, sd.project.Dir)
|
log.Info().Str("image", imageName).Msg("saving image for transfert...")
|
||||||
|
|
||||||
|
tarFile, err := sd.dcli.Save(imageName, sd.project.Dir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log.Info().Str("image", imageName).Str("dir", sd.project.Dir).Msg("image saved successfully")
|
||||||
|
|
||||||
defer os.Remove(tarFile)
|
defer os.Remove(tarFile)
|
||||||
|
|
||||||
tarFileBase := filepath.Base(tarFile)
|
tarFileBase := filepath.Base(tarFile)
|
||||||
@ -91,6 +94,5 @@ func (sd *SwarmDeployer) Deploy() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Info().Msg("project deployed successfully on swarm")
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,18 +1,19 @@
|
|||||||
package docker
|
package docker
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
"github.com/rs/zerolog/log"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type IClient interface {
|
type IClient interface {
|
||||||
Save(imageName, dest string) (string, error)
|
Save(imageName, dest string) (string, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var ErrDockerClientSave = errors.New("unable to save image into tar")
|
||||||
|
|
||||||
type Client struct{}
|
type Client struct{}
|
||||||
|
|
||||||
var _ IClient = (*Client)(nil)
|
var _ IClient = (*Client)(nil)
|
||||||
@ -24,12 +25,11 @@ func NewClient() Client {
|
|||||||
func (c *Client) Save(imageName, dest string) (string, error) {
|
func (c *Client) Save(imageName, dest string) (string, error) {
|
||||||
destInfo, err := os.Stat(dest)
|
destInfo, err := os.Stat(dest)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Err(err).Str("dest", dest).Msg("unable to stat dest directory")
|
return "", fmt.Errorf("unable to stat file, dir=%s, err=%v", dest, err)
|
||||||
return "", err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if !destInfo.IsDir() {
|
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)
|
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 := exec.Command("docker", "save", "-o", tarFile, imageName)
|
||||||
cmd.Dir = dest
|
cmd.Dir = dest
|
||||||
if _, err := cmd.Output(); err != nil {
|
if _, err := cmd.Output(); err != nil {
|
||||||
log.Err(err).Str("image", imageName).Str("dest", dest).Msg("unable to save image into tar")
|
return "", fmt.Errorf("%w, dir=%s, image=%s, err=%v", ErrDockerClientSave, dest, imageName, err)
|
||||||
return dest, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Info().Str("image", imageName).Str("dest", dest).Msg("image successfully saved")
|
|
||||||
return filepath.Join(dest, tarFile), nil
|
return filepath.Join(dest, tarFile), nil
|
||||||
}
|
}
|
||||||
|
|||||||
9
main.go
9
main.go
@ -59,17 +59,20 @@ func main() {
|
|||||||
|
|
||||||
project, err := models.ProjectFromDir(*projectDir)
|
project, err := models.ProjectFromDir(*projectDir)
|
||||||
if err != nil {
|
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()
|
dcli := docker.NewClient()
|
||||||
|
|
||||||
sd, err := deployers.NewSwarmDeployer(ctx, &dcli, swarmNet, &project)
|
sd, err := deployers.NewSwarmDeployer(ctx, &dcli, swarmNet, &project)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
os.Exit(1)
|
log.Fatal().Err(err).Msg("unable to init swarm deployer")
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := sd.Deploy(); err != nil {
|
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")
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,8 +2,6 @@ package models
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"net"
|
"net"
|
||||||
|
|
||||||
"github.com/rs/zerolog/log"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type HMNetInfo struct {
|
type HMNetInfo struct {
|
||||||
@ -28,7 +26,6 @@ type HMMap struct {
|
|||||||
func (hm *HMMap) GetSwarmNetInfo() *HMNetInfo {
|
func (hm *HMMap) GetSwarmNetInfo() *HMNetInfo {
|
||||||
data, ok := hm.VM["swarm"]
|
data, ok := hm.VM["swarm"]
|
||||||
if !ok {
|
if !ok {
|
||||||
log.Error().Msg("unable to get swarm net info, check your configuration")
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -21,11 +21,7 @@ const (
|
|||||||
ConfFile = "hmdeploy.json"
|
ConfFile = "hmdeploy.json"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var ErrProjectConfFile = errors.New("project error")
|
||||||
ErrInvalidEnvFile = errors.New("unable to stat .env file")
|
|
||||||
ErrInvalidComposeFile = errors.New("unable to stat compose file")
|
|
||||||
ErrInvalidNginxFile = errors.New("unable to stat nginx file")
|
|
||||||
)
|
|
||||||
|
|
||||||
func getFileInfo(baseDir, filePath string) (fs.FileInfo, error) {
|
func getFileInfo(baseDir, filePath string) (fs.FileInfo, error) {
|
||||||
var fInf fs.FileInfo
|
var fInf fs.FileInfo
|
||||||
@ -33,14 +29,14 @@ func getFileInfo(baseDir, filePath string) (fs.FileInfo, error) {
|
|||||||
filePath = filepath.Clean(filePath)
|
filePath = filepath.Clean(filePath)
|
||||||
filePath = filepath.Join(baseDir, filePath)
|
filePath = filepath.Join(baseDir, filePath)
|
||||||
|
|
||||||
composePath, err := filepath.Abs(filePath)
|
fileAbsPath, err := filepath.Abs(filePath)
|
||||||
if err != nil {
|
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 {
|
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
|
return fInf, nil
|
||||||
@ -65,23 +61,23 @@ type Project struct {
|
|||||||
func (p *Project) validate() error {
|
func (p *Project) validate() error {
|
||||||
cfs, err := getFileInfo(p.Dir, p.Deps.ComposeFile)
|
cfs, err := getFileInfo(p.Dir, p.Deps.ComposeFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("%w, %v", ErrInvalidComposeFile, err)
|
return err
|
||||||
}
|
}
|
||||||
p.Deps.ComposeFileInfo = cfs
|
p.Deps.ComposeFileInfo = cfs
|
||||||
|
|
||||||
if p.Deps.EnvFile != "" {
|
if p.Deps.EnvFile != "" {
|
||||||
efs, err := getFileInfo(p.Dir, p.Deps.EnvFile)
|
efs, err := getFileInfo(p.Dir, p.Deps.EnvFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("%w, %v", ErrInvalidEnvFile, err)
|
return err
|
||||||
}
|
}
|
||||||
p.Deps.EnvFileInfo = efs
|
p.Deps.EnvFileInfo = efs
|
||||||
} else {
|
} 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 {
|
if err != nil {
|
||||||
return fmt.Errorf("%w, %v", ErrInvalidNginxFile, err)
|
return err
|
||||||
}
|
}
|
||||||
p.Deps.NginxFileInfo = nfs
|
p.Deps.NginxFileInfo = nfs
|
||||||
|
|
||||||
@ -96,18 +92,15 @@ func ProjectFromDir(dir string) (Project, error) {
|
|||||||
|
|
||||||
content, err := os.ReadFile(filepath.Join(dir, ConfFile))
|
content, err := os.ReadFile(filepath.Join(dir, ConfFile))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Err(err).Str("dir", dir).Str("conf", ConfFile).Msg("unable to read conf file")
|
return p, fmt.Errorf("%w, unable to read conf file=%s, err=%v", ErrProjectConfFile, ConfFile, err)
|
||||||
return p, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := json.Unmarshal(content, &p); err != nil {
|
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, fmt.Errorf("%w, unable to parse conf file=%s, err=%v", ErrProjectConfFile, ConfFile, err)
|
||||||
return p, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := p.validate(); err != nil {
|
if err := p.validate(); err != nil {
|
||||||
log.Err(err).Str("dir", dir).Msg("unable to validate project")
|
return p, fmt.Errorf("%w, unable to validate project, name=%s, dir=%s, err=%v", ErrProjectConfFile, p.Name, p.Dir, err)
|
||||||
return p, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return p, nil
|
return p, nil
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user