2016-04-02 14:40:07 +02:00
package projects
2016-04-04 15:44:34 +02:00
import (
2016-04-13 18:09:44 +02:00
"database/sql"
2017-02-23 00:21:49 +01:00
"net/http"
2016-04-13 18:09:44 +02:00
2017-02-23 06:12:16 +01:00
"github.com/ansible-semaphore/semaphore/db"
2016-04-13 18:09:44 +02:00
"github.com/ansible-semaphore/semaphore/util"
2017-02-23 00:21:49 +01:00
"github.com/castawaylabs/mulekick"
"github.com/gorilla/context"
2016-04-04 15:44:34 +02:00
"github.com/masterminds/squirrel"
2018-03-08 10:04:34 +01:00
"path/filepath"
"strings"
2018-03-08 15:00:15 +01:00
"os"
2016-04-04 15:44:34 +02:00
)
2016-04-02 14:40:07 +02:00
2018-03-27 22:12:47 +02:00
const (
asc = "asc"
desc = "desc"
)
// InventoryMiddleware ensures an inventory exists and loads it to the context
2017-02-22 23:17:36 +01:00
func InventoryMiddleware ( w http . ResponseWriter , r * http . Request ) {
2017-02-23 06:12:16 +01:00
project := context . Get ( r , "project" ) . ( db . Project )
2017-02-23 00:21:49 +01:00
inventoryID , err := util . GetIntParam ( "inventory_id" , w , r )
2016-04-13 18:09:44 +02:00
if err != nil {
return
}
2018-03-27 22:12:47 +02:00
query , args , err := squirrel . Select ( "*" ) .
2016-04-13 18:09:44 +02:00
From ( "project__inventory" ) .
Where ( "project_id=?" , project . ID ) .
Where ( "id=?" , inventoryID ) .
ToSql ( )
2018-03-27 22:12:47 +02:00
util . LogWarning ( err )
2016-04-13 18:09:44 +02:00
2017-02-23 06:12:16 +01:00
var inventory db . Inventory
if err := db . Mysql . SelectOne ( & inventory , query , args ... ) ; err != nil {
2016-04-13 18:09:44 +02:00
if err == sql . ErrNoRows {
2017-02-22 23:17:36 +01:00
w . WriteHeader ( http . StatusNotFound )
2016-04-13 18:09:44 +02:00
return
}
panic ( err )
}
2017-02-23 00:21:49 +01:00
context . Set ( r , "inventory" , inventory )
2016-04-02 14:40:07 +02:00
}
2018-03-27 22:12:47 +02:00
// GetInventory returns an inventory from the database
2017-02-22 23:17:36 +01:00
func GetInventory ( w http . ResponseWriter , r * http . Request ) {
2017-02-23 06:12:16 +01:00
project := context . Get ( r , "project" ) . ( db . Project )
var inv [ ] db . Inventory
2016-04-04 15:44:34 +02:00
2017-03-16 15:55:50 +01:00
sort := r . URL . Query ( ) . Get ( "sort" )
order := r . URL . Query ( ) . Get ( "order" )
2018-03-27 22:12:47 +02:00
if order != asc && order != desc {
order = asc
2017-03-16 15:55:50 +01:00
}
q := squirrel . Select ( "*" ) .
From ( "project__inventory pi" )
switch sort {
case "name" , "type" :
q = q . Where ( "pi.project_id=?" , project . ID ) .
OrderBy ( "pi." + sort + " " + order )
default :
q = q . Where ( "pi.project_id=?" , project . ID ) .
OrderBy ( "pi.name " + order )
}
2018-03-27 22:12:47 +02:00
query , args , err := q . ToSql ( )
util . LogWarning ( err )
2016-04-04 15:44:34 +02:00
2017-02-23 06:12:16 +01:00
if _ , err := db . Mysql . Select ( & inv , query , args ... ) ; err != nil {
2016-04-04 15:44:34 +02:00
panic ( err )
}
2017-02-23 00:21:49 +01:00
mulekick . WriteJSON ( w , http . StatusOK , inv )
2016-04-04 15:44:34 +02:00
}
2018-03-27 22:12:47 +02:00
// AddInventory creates an inventory in the database
2017-02-22 23:17:36 +01:00
func AddInventory ( w http . ResponseWriter , r * http . Request ) {
2017-02-23 06:12:16 +01:00
project := context . Get ( r , "project" ) . ( db . Project )
2016-04-16 21:42:57 +02:00
var inventory struct {
Name string ` json:"name" binding:"required" `
KeyID * int ` json:"key_id" `
2018-03-27 22:12:47 +02:00
SSHKeyID int ` json:"ssh_key_id" `
2016-04-16 21:42:57 +02:00
Type string ` json:"type" `
Inventory string ` json:"inventory" `
}
2016-04-04 15:44:34 +02:00
2017-02-22 23:21:52 +01:00
if err := mulekick . Bind ( w , r , & inventory ) ; err != nil {
2016-04-04 15:44:34 +02:00
return
}
switch inventory . Type {
2018-03-08 08:39:20 +01:00
case "static" , "file" :
2016-04-04 15:44:34 +02:00
break
default :
2017-02-22 23:17:36 +01:00
w . WriteHeader ( http . StatusBadRequest )
2016-04-04 15:44:34 +02:00
return
}
2018-03-27 22:12:47 +02:00
res , err := db . Mysql . Exec ( "insert into project__inventory set project_id=?, name=?, type=?, key_id=?, ssh_key_id=?, inventory=?" , project . ID , inventory . Name , inventory . Type , inventory . KeyID , inventory . SSHKeyID , inventory . Inventory )
2016-04-17 02:20:23 +02:00
if err != nil {
panic ( err )
}
2018-03-27 22:12:47 +02:00
insertID , err := res . LastInsertId ( )
util . LogWarning ( err )
2016-04-17 02:20:23 +02:00
insertIDInt := int ( insertID )
objType := "inventory"
desc := "Inventory " + inventory . Name + " created"
2017-02-23 06:12:16 +01:00
if err := ( db . Event {
2016-04-17 02:20:23 +02:00
ProjectID : & project . ID ,
ObjectType : & objType ,
ObjectID : & insertIDInt ,
Description : & desc ,
} . Insert ( ) ) ; err != nil {
2016-04-04 15:44:34 +02:00
panic ( err )
}
2017-03-10 15:56:23 +01:00
inv := db . Inventory {
2018-03-27 22:12:47 +02:00
ID : insertIDInt ,
Name : inventory . Name ,
2017-03-11 06:47:26 +01:00
ProjectID : project . ID ,
Inventory : inventory . Inventory ,
2018-03-27 22:12:47 +02:00
KeyID : inventory . KeyID ,
SSHKeyID : & inventory . SSHKeyID ,
Type : inventory . Type ,
2017-03-10 15:56:23 +01:00
}
2017-03-11 06:47:26 +01:00
mulekick . WriteJSON ( w , http . StatusCreated , inv )
2016-04-04 15:44:34 +02:00
}
2018-03-27 22:12:47 +02:00
// IsValidInventoryPath tests a path to ensure it is below the cwd
2018-03-08 12:37:38 +01:00
func IsValidInventoryPath ( path string ) bool {
2018-03-27 22:12:47 +02:00
currentPath , err := os . Getwd ( )
if err != nil {
2018-03-08 10:04:34 +01:00
return false
2018-03-27 22:12:47 +02:00
}
absPath , err := filepath . Abs ( path )
if err != nil {
2018-03-08 10:04:34 +01:00
return false
2018-03-27 22:12:47 +02:00
}
relPath , err := filepath . Rel ( currentPath , absPath )
if err != nil {
2018-03-08 10:04:34 +01:00
return false
}
2018-03-27 22:12:47 +02:00
return ! strings . HasPrefix ( relPath , ".." )
2018-03-08 10:04:34 +01:00
}
2018-03-27 22:12:47 +02:00
// UpdateInventory writes updated values to an existing inventory item in the database
2017-02-22 23:17:36 +01:00
func UpdateInventory ( w http . ResponseWriter , r * http . Request ) {
2017-02-23 06:12:16 +01:00
oldInventory := context . Get ( r , "inventory" ) . ( db . Inventory )
2016-04-16 21:42:57 +02:00
var inventory struct {
Name string ` json:"name" binding:"required" `
KeyID * int ` json:"key_id" `
2018-03-27 22:12:47 +02:00
SSHKeyID int ` json:"ssh_key_id" `
2016-04-16 21:42:57 +02:00
Type string ` json:"type" `
Inventory string ` json:"inventory" `
}
2017-02-22 23:21:52 +01:00
if err := mulekick . Bind ( w , r , & inventory ) ; err != nil {
2016-04-16 21:42:57 +02:00
return
}
switch inventory . Type {
2018-03-08 10:04:34 +01:00
case "static" :
break
case "file" :
2018-03-08 12:37:38 +01:00
if ! IsValidInventoryPath ( inventory . Inventory ) {
2018-03-08 10:04:34 +01:00
panic ( "Invalid inventory path" )
}
2016-04-16 21:42:57 +02:00
default :
2017-02-22 23:17:36 +01:00
w . WriteHeader ( http . StatusBadRequest )
2016-04-16 21:42:57 +02:00
return
}
2018-03-27 22:12:47 +02:00
if _ , err := db . Mysql . Exec ( "update project__inventory set name=?, type=?, key_id=?, ssh_key_id=?, inventory=? where id=?" , inventory . Name , inventory . Type , inventory . KeyID , inventory . SSHKeyID , inventory . Inventory , oldInventory . ID ) ; err != nil {
2016-04-16 21:42:57 +02:00
panic ( err )
}
2016-04-17 02:20:23 +02:00
desc := "Inventory " + inventory . Name + " updated"
objType := "inventory"
2017-02-23 06:12:16 +01:00
if err := ( db . Event {
2016-04-17 02:20:23 +02:00
ProjectID : & oldInventory . ProjectID ,
Description : & desc ,
ObjectID : & oldInventory . ID ,
ObjectType : & objType ,
} . Insert ( ) ) ; err != nil {
panic ( err )
}
2017-02-22 23:17:36 +01:00
w . WriteHeader ( http . StatusNoContent )
2016-04-02 14:40:07 +02:00
}
2018-03-27 22:12:47 +02:00
// RemoveInventory deletes an inventory from the database
2017-02-22 23:17:36 +01:00
func RemoveInventory ( w http . ResponseWriter , r * http . Request ) {
2017-02-23 06:12:16 +01:00
inventory := context . Get ( r , "inventory" ) . ( db . Inventory )
2016-04-13 18:09:44 +02:00
2017-02-23 06:12:16 +01:00
templatesC , err := db . Mysql . SelectInt ( "select count(1) from project__template where project_id=? and inventory_id=?" , inventory . ProjectID , inventory . ID )
2016-06-17 22:16:46 +02:00
if err != nil {
panic ( err )
}
if templatesC > 0 {
2017-02-23 00:21:49 +01:00
if len ( r . URL . Query ( ) . Get ( "setRemoved" ) ) == 0 {
mulekick . WriteJSON ( w , http . StatusBadRequest , map [ string ] interface { } {
2016-06-17 22:16:46 +02:00
"error" : "Inventory is in use by one or more templates" ,
"inUse" : true ,
} )
return
}
2017-02-23 06:12:16 +01:00
if _ , err := db . Mysql . Exec ( "update project__inventory set removed=1 where id=?" , inventory . ID ) ; err != nil {
2016-06-17 22:16:46 +02:00
panic ( err )
}
2017-02-22 23:17:36 +01:00
w . WriteHeader ( http . StatusNoContent )
2016-06-17 22:16:46 +02:00
return
}
2017-02-23 06:12:16 +01:00
if _ , err := db . Mysql . Exec ( "delete from project__inventory where id=?" , inventory . ID ) ; err != nil {
2016-04-13 18:09:44 +02:00
panic ( err )
}
2016-04-17 02:20:23 +02:00
desc := "Inventory " + inventory . Name + " deleted"
2017-02-23 06:12:16 +01:00
if err := ( db . Event {
2016-04-17 02:20:23 +02:00
ProjectID : & inventory . ProjectID ,
Description : & desc ,
} . Insert ( ) ) ; err != nil {
panic ( err )
}
2017-02-22 23:17:36 +01:00
w . WriteHeader ( http . StatusNoContent )
2016-04-02 14:40:07 +02:00
}