package deployers import ( "context" "fmt" "path/filepath" "sync/atomic" "time" "gitea.thegux.fr/hmdeploy/connection" "gitea.thegux.fr/hmdeploy/models" "github.com/rs/zerolog/log" ) type NginxDeployer struct { ctx context.Context conn connection.IConnection project *models.Project processing atomic.Bool chDone chan struct{} errFlag error } var _ IDeployer = (*NginxDeployer)(nil) func NewNginxDeployer( ctx context.Context, netInfo *models.HMNetInfo, project *models.Project, ) (*NginxDeployer, error) { var nd NginxDeployer conn, err := connection.NewSSHConn( netInfo.IP.String(), netInfo.SSH.User, netInfo.SSH.Port, netInfo.SSH.PrivKey, ) if err != nil { return &nd, err } nd.conn = &conn nd.project = project nd.ctx = ctx nd.processing = atomic.Bool{} nd.processing.Store(false) nd.chDone = make(chan struct{}, 1) return &nd, nil } func (nd *NginxDeployer) close() error { return nd.conn.Close() } func (nd *NginxDeployer) clean() (err error) { _, err = nd.conn.Execute("rm -f " + nd.project.Name + ".conf") return } func (nd *NginxDeployer) setDone(err error) { nd.chDone <- struct{}{} nd.errFlag = err } func (nd *NginxDeployer) Error() error { return nd.errFlag } func (nd *NginxDeployer) Done() <-chan struct{} { chDone := make(chan struct{}) go func() { defer func() { close(chDone) }() for { select { case <-nd.ctx.Done(): log.Warn().Str("deployer", "swarm").Msg("context done catch") timeout := time.NewTicker(10 * time.Second) //nolint:mnd //TODO: to refactor tick := time.NewTicker(time.Second) for { select { case <-timeout.C: log.Error(). Msg("timeout while waiting for graceful swarm deployer shutdown") chDone <- struct{}{} return case <-tick.C: if !nd.processing.Load() { chDone <- struct{}{} return } tick.Reset(1 * time.Second) } } case <-nd.chDone: log.Info().Str("deployer", "nginx").Msg("terminated") chDone <- struct{}{} return } } }() return chDone } func (nd *NginxDeployer) Clear() error { log.Debug().Msg("clearing nginx deployment...") if err := nd.clean(); err != nil { log.Err(err).Msg("unable to clean nginx conf remotly") } if err := nd.close(); err != nil { log.Err(err).Msg("unable to close nginx conn") } log.Debug().Msg("clear nginx deployment done") return nil } func (nd *NginxDeployer) Build() error { nd.processing.Store(true) defer nd.processing.Store(false) select { case <-nd.ctx.Done(): nd.errFlag = ErrContextDone return fmt.Errorf("%w, build nginx archive skipped", ErrContextDone) default: } nginxPath := filepath.Join(nd.project.Dir, filepath.Base(nd.project.Deps.NginxFile)) nginxConf := nd.project.Name + ".conf" log.Info().Str("nginx", nginxConf).Msg("transferring nginx conf...") if err := nd.conn.CopyFile(nginxPath, nginxConf); err != nil { nd.setDone(err) return err } log.Info().Str("nginx", nginxConf).Msg("nginx conf transferred with success") return nil } func (nd *NginxDeployer) Deploy() (err error) { nd.processing.Store(true) defer nd.processing.Store(false) select { case <-nd.ctx.Done(): nd.errFlag = ErrContextDone return fmt.Errorf("%w, nginx deployment skipped", ErrContextDone) default: } nginxConf := nd.project.Name + ".conf" log.Info().Str("nginx", nginxConf).Msg("deploying nginx conf...") _, err = nd.conn.Execute( fmt.Sprintf( "cp %s /etc/nginx/sites-available && ln -sf /etc/nginx/sites-available/%s /etc/nginx/sites-enabled/%s", nginxConf, nginxConf, nginxConf, ), ) nd.setDone(err) if err == nil { log.Info().Str("nginx", nginxConf).Msg("nginx conf successfully deployed") } return err }