Labels done
This commit is contained in:
		
							parent
							
								
									31cdc6ef42
								
							
						
					
					
						commit
						753bd452fb
					
				
					 7 changed files with 99 additions and 18 deletions
				
			
		
							
								
								
									
										9
									
								
								api.http
									
									
									
									
									
								
							
							
						
						
									
										9
									
								
								api.http
									
									
									
									
									
								
							| 
						 | 
					@ -74,3 +74,12 @@ Content-type: application/json
 | 
				
			||||||
GET http://localhost:1323/v1/apps
 | 
					GET http://localhost:1323/v1/apps
 | 
				
			||||||
Content-type: application/json
 | 
					Content-type: application/json
 | 
				
			||||||
Authorization: Token 333ff32b-6c9e-4794-adab-c289447e66b0
 | 
					Authorization: Token 333ff32b-6c9e-4794-adab-c289447e66b0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					###
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					POST http://localhost:1323/v1/apps/test_1234/labels
 | 
				
			||||||
 | 
					Content-type: application/json
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    "Value": "userid:cx"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										44
									
								
								apps/main.go
									
									
									
									
									
								
							
							
						
						
									
										44
									
								
								apps/main.go
									
									
									
									
									
								
							| 
						 | 
					@ -16,7 +16,7 @@ func Get(name string) (*App, error) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	db := common.GetDBConnection()
 | 
						db := common.GetDBConnection()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	err := db.First(&app).Where("name = ?", name).Error
 | 
						err := db.Preload("Labels").First(&app).Where("name = ?", name).Error
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return nil, err
 | 
							return nil, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -30,7 +30,7 @@ func List() (*[]App, error) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	db := common.GetDBConnection()
 | 
						db := common.GetDBConnection()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	err := db.Find(&apps).Error
 | 
						err := db.Preload("Labels").Find(&apps).Error
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return nil, err
 | 
							return nil, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -132,3 +132,43 @@ func Delete(name string) error {
 | 
				
			||||||
	err := db.Delete(App{}).Where("name = ?", name).Error
 | 
						err := db.Delete(App{}).Where("name = ?", name).Error
 | 
				
			||||||
	return err
 | 
						return err
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// AddLabel adds label to existing application
 | 
				
			||||||
 | 
					func AddLabel(appName string, label string) error {
 | 
				
			||||||
 | 
						var app App
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						db := common.GetDBConnection()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						err := db.First(&app).Where("name = ?", appName).Error
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Check if there is such label already
 | 
				
			||||||
 | 
						var count int
 | 
				
			||||||
 | 
						err = db.Model(&Label{}).Where("value = ? AND app_id = ?", label, app.ID).Count(&count).Error
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if count > 0 {
 | 
				
			||||||
 | 
							return nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// And create the label
 | 
				
			||||||
 | 
						return db.Create(&Label{AppID: app.ID, Value: label}).Error
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// RemoveLabel removes label from existing application
 | 
				
			||||||
 | 
					func RemoveLabel(appName string, label string) error {
 | 
				
			||||||
 | 
						var app App
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						db := common.GetDBConnection()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						err := db.First(&app).Where("name = ?", appName).Error
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return db.Delete(&Label{}).Where("label = ? AND app_id = ?", label, app.ID).Error
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -21,6 +21,7 @@ func (v ValidationError) Error() string {
 | 
				
			||||||
// Label holds metadata about the application
 | 
					// Label holds metadata about the application
 | 
				
			||||||
type Label struct {
 | 
					type Label struct {
 | 
				
			||||||
	Value string `json:"value"`
 | 
						Value string `json:"value"`
 | 
				
			||||||
 | 
						AppID uint   `json:"-" gorm:"not null"`
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// AppState contains info about runnint application, it's not saved in the database
 | 
					// AppState contains info about runnint application, it's not saved in the database
 | 
				
			||||||
| 
						 | 
					@ -39,13 +40,13 @@ type App struct {
 | 
				
			||||||
	UpdatedAt time.Time  `json:"updated_at"`
 | 
						UpdatedAt time.Time  `json:"updated_at"`
 | 
				
			||||||
	DeletedAt *time.Time `sql:"index" json:"deleted_at"`
 | 
						DeletedAt *time.Time `sql:"index" json:"deleted_at"`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	Name     string `json:"name" gorm:"primary_key"`
 | 
						Name     string  `json:"name" gorm:"unique,index,not_null"`
 | 
				
			||||||
	SSHPort  int    `json:"ssh_port"`
 | 
						SSHPort  int     `json:"ssh_port"`
 | 
				
			||||||
	HTTPPort int    `json:"http_port"`
 | 
						HTTPPort int     `json:"http_port"`
 | 
				
			||||||
	Image    string `json:"image"`
 | 
						Image    string  `json:"image"`
 | 
				
			||||||
	CPU      int    `json:"cpu"`    // percentage, 200 means two CPU
 | 
						CPU      int     `json:"cpu"`                            // percentage, 200 means two CPU
 | 
				
			||||||
	Memory   int    `json:"memory"` // Limit in MB
 | 
						Memory   int     `json:"memory"`                         // Limit in MB
 | 
				
			||||||
	// Labels   []Label `json:"labels"` // username:cx or user_id:1
 | 
						Labels   []Label `json:"labels" gorm:"foreignkey:AppID"` // username:cx or user_id:1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	State           string  `json:"state"`
 | 
						State           string  `json:"state"`
 | 
				
			||||||
	CPUUsage        float64 `json:"cpu_usage"`    // in percents
 | 
						CPUUsage        float64 `json:"cpu_usage"`    // in percents
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -17,13 +17,12 @@ func du(path string) (int, int, error) {
 | 
				
			||||||
	// Occupied space
 | 
						// Occupied space
 | 
				
			||||||
	var out bytes.Buffer
 | 
						var out bytes.Buffer
 | 
				
			||||||
	var errOut bytes.Buffer
 | 
						var errOut bytes.Buffer
 | 
				
			||||||
	command := exec.Command("/usr/bin/du", "-m", "-s", path)
 | 
						command := exec.Command("/usr/bin/du", "-b", "-s", path)
 | 
				
			||||||
	command.Stdout = &out
 | 
						command.Stdout = &out
 | 
				
			||||||
	command.Stderr = &errOut
 | 
						command.Stderr = &errOut
 | 
				
			||||||
	err := command.Run()
 | 
						err := command.Run()
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		log.Println(errOut.String())
 | 
							log.Println(errOut.String())
 | 
				
			||||||
		log.Println("/usr/bin/du -m -s " + path)
 | 
					 | 
				
			||||||
		return space, inodes, err
 | 
							return space, inodes, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	fields := strings.Fields(strings.TrimSpace(out.String()))
 | 
						fields := strings.Fields(strings.TrimSpace(out.String()))
 | 
				
			||||||
| 
						 | 
					@ -44,7 +43,6 @@ func du(path string) (int, int, error) {
 | 
				
			||||||
	err = command.Run()
 | 
						err = command.Run()
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		log.Println(errOut.String())
 | 
							log.Println(errOut.String())
 | 
				
			||||||
		log.Println("/usr/bin/du --inodes -s " + path)
 | 
					 | 
				
			||||||
		return space, inodes, err
 | 
							return space, inodes, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	fields = strings.Fields(strings.TrimSpace(out.String()))
 | 
						fields = strings.Fields(strings.TrimSpace(out.String()))
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -78,7 +78,7 @@ func (c *Container) DiskUsage() (int, int, error) {
 | 
				
			||||||
	return du(c.volumeHostPath())
 | 
						return du(c.volumeHostPath())
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// ResourceUsage returns amount of memory in MB and CPU in % that the app occupies
 | 
					// ResourceUsage returns amount of memory in B and CPU in % that the app occupies
 | 
				
			||||||
func (c *Container) ResourceUsage() (float64, int, error) {
 | 
					func (c *Container) ResourceUsage() (float64, int, error) {
 | 
				
			||||||
	driver := c.getDriver()
 | 
						driver := c.getDriver()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										31
									
								
								main.go
									
									
									
									
									
								
							
							
						
						
									
										31
									
								
								main.go
									
									
									
									
									
								
							| 
						 | 
					@ -255,6 +255,37 @@ func main() {
 | 
				
			||||||
		return c.JSON(http.StatusOK, Message{Message: "ok"})
 | 
							return c.JSON(http.StatusOK, Message{Message: "ok"})
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Adds new label
 | 
				
			||||||
 | 
						e.POST("/v1/apps/:name/labels", func(c echo.Context) error {
 | 
				
			||||||
 | 
							name := c.Param("name")
 | 
				
			||||||
 | 
							label := apps.Label{}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							err := c.Bind(&label)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return c.JSONPretty(http.StatusBadRequest, Message{Message: err.Error()}, JSONIndent)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							err = apps.AddLabel(name, label.Value)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return c.JSONPretty(http.StatusInternalServerError, Message{Message: err.Error()}, JSONIndent)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return c.JSON(http.StatusOK, Message{Message: "ok"})
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Removes existing label
 | 
				
			||||||
 | 
						e.DELETE("/v1/apps/:name/labels/:label", func(c echo.Context) error {
 | 
				
			||||||
 | 
							name := c.Param("name")
 | 
				
			||||||
 | 
							label := c.Param("name")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							err := apps.RemoveLabel(name, label)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return c.JSONPretty(http.StatusInternalServerError, Message{Message: err.Error()}, JSONIndent)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return c.JSON(http.StatusOK, Message{Message: "ok"})
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Delete one app
 | 
						// Delete one app
 | 
				
			||||||
	e.DELETE("/v1/apps/:name", func(c echo.Context) error {
 | 
						e.DELETE("/v1/apps/:name", func(c echo.Context) error {
 | 
				
			||||||
		name := c.Param("name")
 | 
							name := c.Param("name")
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -69,11 +69,13 @@
 | 
				
			||||||
                    <td><strong>{( app.name )}</strong></td>
 | 
					                    <td><strong>{( app.name )}</strong></td>
 | 
				
			||||||
                    <td>{( app.state.state )}</td>
 | 
					                    <td>{( app.state.state )}</td>
 | 
				
			||||||
                    <td>{( app.image.replace("docker.io/", "") )}</td>
 | 
					                    <td>{( app.image.replace("docker.io/", "") )}</td>
 | 
				
			||||||
                    <td>- / {( app.cpu )} %</td>
 | 
					                    <td>{( app.cpu_usage )} % / {( app.cpu )} %</td>
 | 
				
			||||||
                    <td>- / {( app.memory )} MB</td>
 | 
					                    <td>{( app.memory_usage )} MB / {( app.memory )} MB</td>
 | 
				
			||||||
                    <td>- GB</td>
 | 
					                    <td>{( (app.disk_usage_bytes / 1000 / 1000 / 1000).toFixed(2) )} GB</td>
 | 
				
			||||||
                    <td>-</td>
 | 
					                    <td>{( app.disk_usage_inodes )}</td>
 | 
				
			||||||
                    <td>-</td>
 | 
					                    <td>
 | 
				
			||||||
 | 
					                      <span v-for="label in app.labels" class="label label-info">{( label.value )}</span>
 | 
				
			||||||
 | 
					                    </td>
 | 
				
			||||||
                    <td>
 | 
					                    <td>
 | 
				
			||||||
                        <button class="btn btn-success btn-sm" v-on:click="start(app.name)" v-if="['stopped'].includes(app.state.state)">Start</button>
 | 
					                        <button class="btn btn-success btn-sm" v-on:click="start(app.name)" v-if="['stopped'].includes(app.state.state)">Start</button>
 | 
				
			||||||
                        <button class="btn btn-warning btn-sm" v-on:click="stop(app.name)" v-if="['running'].includes(app.state.state)">Stop</button>  
 | 
					                        <button class="btn btn-warning btn-sm" v-on:click="stop(app.name)" v-if="['running'].includes(app.state.state)">Stop</button>  
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue