176 lines
		
	
	
		
			4.1 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			176 lines
		
	
	
		
			4.1 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package deployers
 | |
| 
 | |
| import (
 | |
| 	"context"
 | |
| 	"errors"
 | |
| 	"fmt"
 | |
| 	"os"
 | |
| 	"path/filepath"
 | |
| 
 | |
| 	"gitea.thegux.fr/hmdeploy/connection"
 | |
| 	"gitea.thegux.fr/hmdeploy/docker"
 | |
| 	"gitea.thegux.fr/hmdeploy/models"
 | |
| 	"gitea.thegux.fr/hmdeploy/utils"
 | |
| 	"github.com/rs/zerolog/log"
 | |
| )
 | |
| 
 | |
| var ErrSwarmDeployerNoArchive = errors.New("no archive found to be deployed")
 | |
| 
 | |
| // SwarmDeployer handles the deployment of a Docker service on the swarm instance.
 | |
| type SwarmDeployer struct {
 | |
| 	*deployer
 | |
| 	conn connection.IConnection
 | |
| 	dloc docker.IClient
 | |
| 	drem *docker.RemoteClient
 | |
| }
 | |
| 
 | |
| var _ IDeployer = (*SwarmDeployer)(nil)
 | |
| 
 | |
| func NewSwarmDeployer(
 | |
| 	ctx context.Context,
 | |
| 	project *models.Project,
 | |
| 	netInfo *models.HMNetInfo,
 | |
| 	dloc docker.IClient,
 | |
| 	drem *docker.RemoteClient,
 | |
| ) (SwarmDeployer, error) {
 | |
| 	var sd SwarmDeployer
 | |
| 
 | |
| 	sd.dloc = dloc
 | |
| 	sd.drem = drem
 | |
| 
 | |
| 	deployer, err := newDeployer(ctx, Swarm, project, netInfo)
 | |
| 	if err != nil {
 | |
| 		return sd, err
 | |
| 	}
 | |
| 	sd.deployer = deployer
 | |
| 
 | |
| 	return sd, nil
 | |
| }
 | |
| 
 | |
| func (sd SwarmDeployer) getComposePath() string {
 | |
| 	return sd.project.GetComposePath()
 | |
| }
 | |
| 
 | |
| func (sd SwarmDeployer) getEnvPath() string {
 | |
| 	return sd.project.GetEnvPath()
 | |
| }
 | |
| 
 | |
| // Build builds the archive with mandatory files to deploy a swarm service.
 | |
| //
 | |
| // After the build, the path of the local archive built is set in
 | |
| // the `archivePath` field.
 | |
| func (sd *SwarmDeployer) Build() error {
 | |
| 	sd.processing.Store(true)
 | |
| 	defer sd.processing.Store(false)
 | |
| 
 | |
| 	select {
 | |
| 	case <-sd.ctx.Done():
 | |
| 		sd.setDone(nil)
 | |
| 		return fmt.Errorf("%w, swarm project build skipped", ErrContextDone)
 | |
| 	default:
 | |
| 	}
 | |
| 
 | |
| 	log.Info().Msg("building swarm archive for deployment...")
 | |
| 
 | |
| 	filesToArchive := []string{}
 | |
| 	for idx := range sd.project.Deps.Swarm.ImageNames {
 | |
| 		tarFile, err := sd.dloc.Save(sd.project.Deps.Swarm.ImageNames[idx], sd.project.Dir)
 | |
| 		if err != nil {
 | |
| 			sd.setDone(err)
 | |
| 			return err
 | |
| 		}
 | |
| 
 | |
| 		defer os.Remove(tarFile) //nolint: errcheck // defered
 | |
| 
 | |
| 		// copy the file directly instead of adding it in the tar archive
 | |
| 		log.Info().Str("image", tarFile).Msg("Transferring image...")
 | |
| 		if err := sd.conn.CopyFile(tarFile, filepath.Base(tarFile)); err != nil {
 | |
| 			return err
 | |
| 		}
 | |
| 		log.Info().Str("image", tarFile).Msg("image transferred with success")
 | |
| 	}
 | |
| 
 | |
| 	if envFilePath := sd.getEnvPath(); envFilePath != "" {
 | |
| 		filesToArchive = append(
 | |
| 			filesToArchive,
 | |
| 			envFilePath,
 | |
| 		)
 | |
| 		log.Info().Msg(".env file added to the archive for deployment")
 | |
| 	}
 | |
| 
 | |
| 	filesToArchive = append(
 | |
| 		filesToArchive,
 | |
| 		sd.getComposePath(),
 | |
| 	)
 | |
| 
 | |
| 	archivePath, err := utils.CreateArchive(
 | |
| 		sd.project.Dir,
 | |
| 		fmt.Sprintf("%s-%s", sd.project.Name, "swarm"),
 | |
| 		filesToArchive...)
 | |
| 	if err != nil {
 | |
| 		sd.setDone(err)
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	sd.archivePath = archivePath
 | |
| 
 | |
| 	log.Info().Str("archive", archivePath).Msg("swarm archive built")
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| func (sd *SwarmDeployer) Deploy() error {
 | |
| 	sd.processing.Store(true)
 | |
| 	defer sd.processing.Store(false)
 | |
| 
 | |
| 	select {
 | |
| 	case <-sd.ctx.Done():
 | |
| 		sd.setDone(nil)
 | |
| 		return fmt.Errorf("%w, swarm deployment skipped", ErrContextDone)
 | |
| 	default:
 | |
| 	}
 | |
| 
 | |
| 	if sd.archivePath == "" {
 | |
| 		sd.setDone(ErrSwarmDeployerNoArchive)
 | |
| 		return ErrSwarmDeployerNoArchive
 | |
| 	}
 | |
| 
 | |
| 	log.Info().Str("archive", sd.archivePath).Msg("deploying archive to swarm...")
 | |
| 
 | |
| 	if err := sd.drem.LoadImages(sd.project.Deps.Swarm.ImageNames...); err != nil {
 | |
| 		sd.setDone(err)
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	if err := sd.copyUntarArchive(); err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	log.Info().Str("project", sd.project.Name).Msg("deploying swarm project...")
 | |
| 	composeFileBase := filepath.Base(sd.getComposePath())
 | |
| 	if err := sd.drem.DeployStack(sd.ctx, sd.project.Name, composeFileBase, docker.WithCheckState(), docker.WithBaseDir(sd.deploymentDir)); err != nil {
 | |
| 		sd.setDone(err)
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	log.Info().Msg("swarm deployment done with success")
 | |
| 
 | |
| 	sd.setDone(nil)
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| func (sd *SwarmDeployer) Destroy() error {
 | |
| 	sd.processing.Store(true)
 | |
| 	defer sd.processing.Store(false)
 | |
| 
 | |
| 	log.Info().Str("project", sd.project.Name).Msg("destroying swarm project...")
 | |
| 	if err := sd.drem.DestroyStack(sd.ctx, sd.project.Name, docker.WithCheckState()); err != nil {
 | |
| 		sd.setDone(err)
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	log.Info().Msg("swarm undeployment done with success")
 | |
| 
 | |
| 	sd.setDone(nil)
 | |
| 	return nil
 | |
| }
 | 
