add destroy command
This commit is contained in:
		
							parent
							
								
									43a78573f5
								
							
						
					
					
						commit
						cfdaa9538b
					
				
							
								
								
									
										2
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								Makefile
									
									
									
									
									
								
							| @ -5,7 +5,7 @@ run: lint | |||||||
| 
 | 
 | ||||||
| build: lint | build: lint | ||||||
| 	@echo "building binary..." | 	@echo "building binary..." | ||||||
| 	@go build -o $(BIN_NAME) -race main.go && echo "$(BIN_NAME) built" | 	@go build -o $(BIN_NAME) main.go && echo "$(BIN_NAME) built" | ||||||
| 
 | 
 | ||||||
| install: | install: | ||||||
| 	@$(shell whereis $(BIN_NAME) | cut -d ' ' -f2 | xargs rm -f) | 	@$(shell whereis $(BIN_NAME) | cut -d ' ' -f2 | xargs rm -f) | ||||||
|  | |||||||
							
								
								
									
										18
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										18
									
								
								README.md
									
									
									
									
									
								
							| @ -15,12 +15,12 @@ You have an Nginx instance in front of a Docker Swarm instance (ip are here for | |||||||
| |docker swarm             |          |nginx                    |              | |docker swarm             |          |nginx                    |              | ||||||
| |                         |          |                         |              | |                         |          |                         |              | ||||||
| |ip: 10.0.0.2             |          |ip: 10.0.0.1             |              | |ip: 10.0.0.2             |          |ip: 10.0.0.1             |              | ||||||
| |                         |          |                         | HTTP Request            |  | ||||||
| |                         +----------+                         |<----------- |  | ||||||
| |                         |          |                         |             |  | ||||||
| |                         |          |                         |             |  | ||||||
| |                         |          |                         |             |  | ||||||
| |                         |          |                         |              | |                         |          |                         |              | ||||||
|  | | +------+    +------+    +----------+                         |<-----------  | ||||||
|  | | |app1  |    |app2  |    |          |                         | HTTP request | ||||||
|  | | |      |    |      |    |          |                         |              | ||||||
|  | | |:8080 |    |:8081 |    |          |                         |              | ||||||
|  | | +------+    +------+    |          |                         |              | ||||||
| |                         |          |                         |              | |                         |          |                         |              | ||||||
| |                         |          |                         |              | |                         |          |                         |              | ||||||
| +-------------------------+          +-------------------------+              | +-------------------------+          +-------------------------+              | ||||||
| @ -120,14 +120,18 @@ The binary is then installed in your **$GOPATH/bin**. | |||||||
| # you can then launch the program directly | # you can then launch the program directly | ||||||
| hmdeploy | hmdeploy | ||||||
| 
 | 
 | ||||||
| # if you want the deploy a specific project | # if you want to deploy a specific project | ||||||
| # use --path to point the project dir where `.homeserver` is located | # use --path to point the project dir where `.homeserver` is located | ||||||
| hmdeploy --path /path/my-project | hmdeploy --path /path/my-project | ||||||
|  | 
 | ||||||
|  | # if you want to undeploy a specific project | ||||||
|  | # do not worry, volumes are preserved | ||||||
|  | hmdeploy --path /path/my-project --destroy | ||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
| ## Next steps | ## Next steps | ||||||
| * Improve the CLI arguments | * Improve the CLI arguments | ||||||
| * Destroy | * ~~Destroy~~ | ||||||
| * post-install script | * post-install script | ||||||
| * Deals with bugs | * Deals with bugs | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -16,6 +16,7 @@ type IDeployer interface { | |||||||
| 	Type() DeployerType | 	Type() DeployerType | ||||||
| 	Deploy() error | 	Deploy() error | ||||||
| 	Build() error | 	Build() error | ||||||
|  | 	Destroy() error | ||||||
| 	Clear() error | 	Clear() error | ||||||
| 	Error() error | 	Error() error | ||||||
| 	Done() <-chan struct{} | 	Done() <-chan struct{} | ||||||
| @ -65,7 +66,7 @@ func newDeployer(ctx context.Context, type_ DeployerType, project *models.Projec | |||||||
| 
 | 
 | ||||||
| func (d *deployer) setDone(err error) { | func (d *deployer) setDone(err error) { | ||||||
| 	d.chDone <- struct{}{} | 	d.chDone <- struct{}{} | ||||||
| 	d.errFlag = err | 	d.errFlag = errors.Join(d.ctx.Err(), err) | ||||||
| 	if err != nil && d.fnCancel != nil { | 	if err != nil && d.fnCancel != nil { | ||||||
| 		d.fnCancel() | 		d.fnCancel() | ||||||
| 	} | 	} | ||||||
| @ -110,6 +111,10 @@ func (d *deployer) Done() <-chan struct{} { | |||||||
| 
 | 
 | ||||||
| 				timeout := time.NewTicker(GracefulTimeout) | 				timeout := time.NewTicker(GracefulTimeout) | ||||||
| 				tick := time.NewTicker(time.Second) | 				tick := time.NewTicker(time.Second) | ||||||
|  | 
 | ||||||
|  | 				defer tick.Stop() | ||||||
|  | 				defer timeout.Stop() | ||||||
|  | 
 | ||||||
| 				for { | 				for { | ||||||
| 					select { | 					select { | ||||||
| 					case <-timeout.C: | 					case <-timeout.C: | ||||||
|  | |||||||
| @ -70,7 +70,7 @@ func (nd *NginxDeployer) Build() error { | |||||||
| 
 | 
 | ||||||
| 	select { | 	select { | ||||||
| 	case <-nd.ctx.Done(): | 	case <-nd.ctx.Done(): | ||||||
| 		nd.errFlag = ErrContextDone | 		nd.setDone(nil) | ||||||
| 		return fmt.Errorf("%w, build nginx archive skipped", ErrContextDone) | 		return fmt.Errorf("%w, build nginx archive skipped", ErrContextDone) | ||||||
| 	default: | 	default: | ||||||
| 	} | 	} | ||||||
| @ -94,7 +94,7 @@ func (nd *NginxDeployer) Deploy() (err error) { | |||||||
| 
 | 
 | ||||||
| 	select { | 	select { | ||||||
| 	case <-nd.ctx.Done(): | 	case <-nd.ctx.Done(): | ||||||
| 		nd.errFlag = ErrContextDone | 		nd.setDone(nil) | ||||||
| 		return fmt.Errorf("%w, nginx deployment skipped", ErrContextDone) | 		return fmt.Errorf("%w, nginx deployment skipped", ErrContextDone) | ||||||
| 	default: | 	default: | ||||||
| 	} | 	} | ||||||
| @ -119,3 +119,33 @@ func (nd *NginxDeployer) Deploy() (err error) { | |||||||
| 
 | 
 | ||||||
| 	return err | 	return err | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | func (nd *NginxDeployer) Destroy() (err error) { | ||||||
|  | 	nd.processing.Store(true) | ||||||
|  | 	defer nd.processing.Store(false) | ||||||
|  | 
 | ||||||
|  | 	select { | ||||||
|  | 	case <-nd.ctx.Done(): | ||||||
|  | 		nd.setDone(nil) | ||||||
|  | 		return fmt.Errorf("%w, nginx destroy skipped", ErrContextDone) | ||||||
|  | 	default: | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	nginxConf := nd.project.Name + ".conf" | ||||||
|  | 
 | ||||||
|  | 	log.Info().Str("nginx", nginxConf).Msg("destroying nginx conf...") | ||||||
|  | 
 | ||||||
|  | 	_, err = nd.conn.Execute( | ||||||
|  | 		fmt.Sprintf( | ||||||
|  | 			"unlink /etc/nginx/sites-enabled/%s", | ||||||
|  | 			nginxConf, | ||||||
|  | 		), | ||||||
|  | 	) | ||||||
|  | 	nd.setDone(err) | ||||||
|  | 
 | ||||||
|  | 	if err == nil { | ||||||
|  | 		log.Info().Str("nginx", nginxConf).Msg("nginx conf successfully destroyed") | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return err | ||||||
|  | } | ||||||
|  | |||||||
| @ -56,7 +56,9 @@ func (sd *SwarmDeployer) close() error { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (sd *SwarmDeployer) clean() (err error) { | func (sd *SwarmDeployer) clean() (err error) { | ||||||
| 	defer os.Remove(sd.archivePath) //nolint: errcheck // defered | 	if err := os.Remove(sd.archivePath); err != nil { | ||||||
|  | 		log.Err(err).Str("archive", sd.archivePath).Msg("unable to clean local swarm archive file") | ||||||
|  | 	} | ||||||
| 	_, err = sd.conn.Execute( | 	_, err = sd.conn.Execute( | ||||||
| 		fmt.Sprintf("rm -f %s %s *.tar.gz *.tar", models.ComposeFile, models.EnvFile), | 		fmt.Sprintf("rm -f %s %s *.tar.gz *.tar", models.ComposeFile, models.EnvFile), | ||||||
| 	) | 	) | ||||||
| @ -89,7 +91,7 @@ func (sd *SwarmDeployer) Build() error { | |||||||
| 
 | 
 | ||||||
| 	select { | 	select { | ||||||
| 	case <-sd.ctx.Done(): | 	case <-sd.ctx.Done(): | ||||||
| 		sd.errFlag = ErrContextDone | 		sd.setDone(nil) | ||||||
| 		return fmt.Errorf("%w, swarm project build skipped", ErrContextDone) | 		return fmt.Errorf("%w, swarm project build skipped", ErrContextDone) | ||||||
| 	default: | 	default: | ||||||
| 	} | 	} | ||||||
| @ -148,7 +150,7 @@ func (sd *SwarmDeployer) Deploy() error { | |||||||
| 
 | 
 | ||||||
| 	select { | 	select { | ||||||
| 	case <-sd.ctx.Done(): | 	case <-sd.ctx.Done(): | ||||||
| 		sd.errFlag = ErrContextDone | 		sd.setDone(nil) | ||||||
| 		return fmt.Errorf("%w, swarm deployment skipped", ErrContextDone) | 		return fmt.Errorf("%w, swarm deployment skipped", ErrContextDone) | ||||||
| 	default: | 	default: | ||||||
| 	} | 	} | ||||||
| @ -186,3 +188,19 @@ func (sd *SwarmDeployer) Deploy() error { | |||||||
| 	sd.setDone(nil) | 	sd.setDone(nil) | ||||||
| 	return 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.conn.Execute(fmt.Sprintf("docker stack rm %s", sd.project.Name)); err != nil { | ||||||
|  | 		sd.setDone(err) | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	log.Info().Msg("swarm undeployment done with success") | ||||||
|  | 
 | ||||||
|  | 	sd.setDone(nil) | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  | |||||||
							
								
								
									
										24
									
								
								main.go
									
									
									
									
									
								
							
							
						
						
									
										24
									
								
								main.go
									
									
									
									
									
								
							| @ -136,7 +136,7 @@ func initDeployers( | |||||||
| // generateTasksTree returns a list of linked `Task` to submit. | // generateTasksTree returns a list of linked `Task` to submit. | ||||||
| // | // | ||||||
| // It's here that all tasks are linked each other to provide the deployment ordering. | // It's here that all tasks are linked each other to provide the deployment ordering. | ||||||
| func generateTasksTree(deployers []deployers.IDeployer) ([]*scheduler.Task, error) { | func generateTasksTree(deployers []deployers.IDeployer, destroy bool) ([]*scheduler.Task, error) { | ||||||
| 	if len(deployers) != MaxDeployers { | 	if len(deployers) != MaxDeployers { | ||||||
| 		return nil, fmt.Errorf("%w, deployers len should be equals to 2", ErrGenerateTasksTree) | 		return nil, fmt.Errorf("%w, deployers len should be equals to 2", ErrGenerateTasksTree) | ||||||
| 	} | 	} | ||||||
| @ -146,6 +146,13 @@ func generateTasksTree(deployers []deployers.IDeployer) ([]*scheduler.Task, erro | |||||||
| 
 | 
 | ||||||
| 	tasks := []*scheduler.Task{} | 	tasks := []*scheduler.Task{} | ||||||
| 
 | 
 | ||||||
|  | 	if destroy { | ||||||
|  | 		swarmDestroy := scheduler.NewTask("swarm-destroy", sd.Destroy) | ||||||
|  | 		destroyTask := scheduler.NewTask("nginx-destroy", nd.Destroy, swarmDestroy) | ||||||
|  | 		tasks = append(tasks, destroyTask) | ||||||
|  | 		return tasks, nil | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	var swarmTask *scheduler.Task | 	var swarmTask *scheduler.Task | ||||||
| 	if nd != nil { | 	if nd != nil { | ||||||
| 		deployNginx := scheduler.NewTask("nginx-deploy", nd.Deploy) | 		deployNginx := scheduler.NewTask("nginx-deploy", nd.Deploy) | ||||||
| @ -164,7 +171,11 @@ func generateTasksTree(deployers []deployers.IDeployer) ([]*scheduler.Task, erro | |||||||
| // | // | ||||||
| // After the completion, deployers `Clear` methods are executed to clean all ressources. | // After the completion, deployers `Clear` methods are executed to clean all ressources. | ||||||
| // Then the scheduler is stopped to terminate the engine. | // Then the scheduler is stopped to terminate the engine. | ||||||
| func waitForCompletion(deployers []deployers.IDeployer, s *scheduler.Scheduler) error { | func waitForCompletion( | ||||||
|  | 	deployers []deployers.IDeployer, | ||||||
|  | 	s *scheduler.Scheduler, | ||||||
|  | 	destroy bool, | ||||||
|  | ) error { | ||||||
| 	var wg sync.WaitGroup | 	var wg sync.WaitGroup | ||||||
| 
 | 
 | ||||||
| 	for idx := range deployers { | 	for idx := range deployers { | ||||||
| @ -183,7 +194,9 @@ func waitForCompletion(deployers []deployers.IDeployer, s *scheduler.Scheduler) | |||||||
| 	for idx := range deployers { | 	for idx := range deployers { | ||||||
| 		if d := deployers[idx]; d != nil { | 		if d := deployers[idx]; d != nil { | ||||||
| 			errs = append(errs, d.Error()) | 			errs = append(errs, d.Error()) | ||||||
| 			s.Submit(scheduler.NewTask(string(d.Type()), d.Clear)) //nolint: errcheck // TODO | 			if !destroy { | ||||||
|  | 				s.Submit(scheduler.NewTask(string(d.Type()), d.Clear)) //nolint: errcheck // TODO | ||||||
|  | 			} | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| @ -204,6 +217,7 @@ func main() { | |||||||
| 	log.Info().Msg("hmdeploy started") | 	log.Info().Msg("hmdeploy started") | ||||||
| 
 | 
 | ||||||
| 	projectDir := flag.String("path", ".", "define the .homeserver project root dir") | 	projectDir := flag.String("path", ".", "define the .homeserver project root dir") | ||||||
|  | 	destroy := flag.Bool("destroy", false, "delete the deployed project") | ||||||
| 	flag.Parse() | 	flag.Parse() | ||||||
| 
 | 
 | ||||||
| 	hmmap, err := loadHMMap() | 	hmmap, err := loadHMMap() | ||||||
| @ -225,7 +239,7 @@ func main() { | |||||||
| 		log.Fatal().Err(err).Msg("unable to init deployers") | 		log.Fatal().Err(err).Msg("unable to init deployers") | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	tasks, err := generateTasksTree(deployers) | 	tasks, err := generateTasksTree(deployers, *destroy) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		log.Fatal().Err(err).Msg("unable to generate tasks tree") | 		log.Fatal().Err(err).Msg("unable to generate tasks tree") | ||||||
| 	} | 	} | ||||||
| @ -237,7 +251,7 @@ func main() { | |||||||
| 		tasks..., | 		tasks..., | ||||||
| 	) | 	) | ||||||
| 
 | 
 | ||||||
| 	if err := waitForCompletion(deployers, s); err != nil { | 	if err := waitForCompletion(deployers, s, *destroy); err != nil { | ||||||
| 		log.Fatal(). | 		log.Fatal(). | ||||||
| 			Err(err). | 			Err(err). | ||||||
| 			Str("name", project.Name). | 			Str("name", project.Name). | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 rmanach
						rmanach