Implement server deletion
This commit is contained in:
		
							parent
							
								
									038436c781
								
							
						
					
					
						commit
						0866b84d8e
					
				
							
								
								
									
										48
									
								
								http.go
									
									
									
									
									
								
							
							
						
						
									
										48
									
								
								http.go
									
									
									
									
									
								
							| 
						 | 
				
			
			@ -474,6 +474,53 @@ func (rt *Router) routeSystemInformation(w http.ResponseWriter, r *http.Request,
 | 
			
		|||
	json.NewEncoder(w).Encode(s)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (rt *Router) routeServerDelete(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
 | 
			
		||||
	s := rt.GetServer(ps.ByName("server"))
 | 
			
		||||
	defer r.Body.Close()
 | 
			
		||||
 | 
			
		||||
	// Immediately suspend the server to prevent a user from attempting
 | 
			
		||||
	// to start it while this process is running.
 | 
			
		||||
	s.Suspended = true
 | 
			
		||||
 | 
			
		||||
	// Destroy the environment; in Docker this will handle a running container and
 | 
			
		||||
	// forcibly terminate it before removing the container, so we do not need to handle
 | 
			
		||||
	// that here.
 | 
			
		||||
	if err := s.Environment.Destroy(); err != nil {
 | 
			
		||||
		zap.S().Errorw("failed to destroy server environment", zap.Error(errors.WithStack(err)))
 | 
			
		||||
 | 
			
		||||
		http.Error(w, "failed to destroy server environment", http.StatusInternalServerError)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Once the environment is terminated, remove the server files from the system. This is
 | 
			
		||||
	// done in a seperate process since failure is not the end of the world and can be
 | 
			
		||||
	// manually cleaned up after the fact.
 | 
			
		||||
	//
 | 
			
		||||
	// In addition, servers with large amounts of files can take some time to finish deleting
 | 
			
		||||
	// so we don't want to block the HTTP call while waiting on this.
 | 
			
		||||
	go func(p string) {
 | 
			
		||||
		if err := os.RemoveAll(p); err != nil {
 | 
			
		||||
			zap.S().Warnw("failed to remove server files on deletion", zap.String("path", p), zap.Error(errors.WithStack(err)))
 | 
			
		||||
		}
 | 
			
		||||
	}(s.Filesystem.Path())
 | 
			
		||||
 | 
			
		||||
	var uuid = s.Uuid
 | 
			
		||||
	server.GetServers().Remove(func(s2 *server.Server) bool {
 | 
			
		||||
		return s2.Uuid == uuid
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	s = nil
 | 
			
		||||
 | 
			
		||||
	// Remove the configuration file stored on the Daemon for this server.
 | 
			
		||||
	go func(u string) {
 | 
			
		||||
		if err := os.Remove("data/servers/" + u + ".yml"); err != nil {
 | 
			
		||||
			zap.S().Warnw("failed to delete server configuration file on deletion", zap.String("server", u), zap.Error(errors.WithStack(err)))
 | 
			
		||||
		}
 | 
			
		||||
	}(uuid)
 | 
			
		||||
 | 
			
		||||
	w.WriteHeader(http.StatusAccepted)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (rt *Router) ReaderToBytes(r io.Reader) []byte {
 | 
			
		||||
	buf := bytes.Buffer{}
 | 
			
		||||
	buf.ReadFrom(r)
 | 
			
		||||
| 
						 | 
				
			
			@ -506,6 +553,7 @@ func (rt *Router) ConfigureRouter() *httprouter.Router {
 | 
			
		|||
	router.POST("/api/servers/:server/power", rt.AuthenticateRequest(rt.routeServerPower))
 | 
			
		||||
	router.POST("/api/servers/:server/commands", rt.AuthenticateRequest(rt.routeServerSendCommand))
 | 
			
		||||
	router.PATCH("/api/servers/:server", rt.AuthenticateRequest(rt.routeServerUpdate))
 | 
			
		||||
	router.DELETE("/api/servers/:server", rt.AuthenticateRequest(rt.routeServerDelete))
 | 
			
		||||
 | 
			
		||||
	return router
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,7 +1,18 @@
 | 
			
		|||
package server
 | 
			
		||||
 | 
			
		||||
import "sync"
 | 
			
		||||
 | 
			
		||||
type Collection struct {
 | 
			
		||||
	items []*Server
 | 
			
		||||
	mutex *sync.Mutex
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Create a new collection from a slice of servers.
 | 
			
		||||
func NewCollection(servers []*Server) *Collection {
 | 
			
		||||
	return &Collection{
 | 
			
		||||
		items: servers,
 | 
			
		||||
		mutex: &sync.Mutex{},
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Return all of the items in the collection.
 | 
			
		||||
| 
						 | 
				
			
			@ -11,11 +22,17 @@ func (c *Collection) All() []*Server {
 | 
			
		|||
 | 
			
		||||
// Adds an item to the collection store.
 | 
			
		||||
func (c *Collection) Add(s *Server) {
 | 
			
		||||
	c.mutex.Lock()
 | 
			
		||||
	defer c.mutex.Unlock()
 | 
			
		||||
 | 
			
		||||
	c.items = append(c.items, s)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Returns only those items matching the filter criteria.
 | 
			
		||||
func (c *Collection) Filter(filter func(*Server) bool) []*Server {
 | 
			
		||||
	c.mutex.Lock()
 | 
			
		||||
	defer c.mutex.Unlock()
 | 
			
		||||
 | 
			
		||||
	r := make([]*Server, 0)
 | 
			
		||||
	for _, v := range c.items {
 | 
			
		||||
		if filter(v) {
 | 
			
		||||
| 
						 | 
				
			
			@ -37,3 +54,18 @@ func (c *Collection) Find(filter func (*Server) bool) *Server {
 | 
			
		|||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Removes all items from the collection that match the filter function.
 | 
			
		||||
func (c *Collection) Remove(filter func(*Server) bool) {
 | 
			
		||||
	c.mutex.Lock()
 | 
			
		||||
	defer c.mutex.Unlock()
 | 
			
		||||
 | 
			
		||||
	r := make([]*Server, 0)
 | 
			
		||||
	for _, v := range c.items {
 | 
			
		||||
		if !filter(v) {
 | 
			
		||||
			r = append(r, v)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	c.items = r
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -40,6 +40,10 @@ type Environment interface {
 | 
			
		|||
	// is not running no error should be returned.
 | 
			
		||||
	Terminate(signal os.Signal) error
 | 
			
		||||
 | 
			
		||||
	// Destroys the environment removing any containers that were created (in Docker
 | 
			
		||||
	// environments at least).
 | 
			
		||||
	Destroy() error
 | 
			
		||||
 | 
			
		||||
	// Returns the exit state of the process. The first result is the exit code, the second
 | 
			
		||||
	// determines if the process was killed by the system OOM killer.
 | 
			
		||||
	ExitState() (uint32, bool, error)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -325,6 +325,18 @@ func (d *DockerEnvironment) Terminate(signal os.Signal) error {
 | 
			
		|||
	)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Remove the Docker container from the machine. If the container is currently running
 | 
			
		||||
// it will be forcibly stopped by Docker.
 | 
			
		||||
func (d *DockerEnvironment) Destroy() error {
 | 
			
		||||
	ctx := context.Background()
 | 
			
		||||
 | 
			
		||||
	return d.Client.ContainerRemove(ctx, d.Server.Uuid, types.ContainerRemoveOptions{
 | 
			
		||||
		RemoveVolumes: true,
 | 
			
		||||
		RemoveLinks:   false,
 | 
			
		||||
		Force:         true,
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Determine the container exit state and return the exit code and wether or not
 | 
			
		||||
// the container was killed by the OOM killer.
 | 
			
		||||
func (d *DockerEnvironment) ExitState() (uint32, bool, error) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -158,7 +158,7 @@ func LoadDirectory(dir string, cfg *config.SystemConfiguration) error {
 | 
			
		|||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	servers = new(Collection)
 | 
			
		||||
	servers = NewCollection(nil)
 | 
			
		||||
 | 
			
		||||
	for _, file := range f {
 | 
			
		||||
		if !strings.HasSuffix(file.Name(), ".yml") || file.IsDir() {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue
	
	Block a user