2018-04-11 20:05:38 +02:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/json"
|
2020-12-04 23:41:26 +01:00
|
|
|
"github.com/ansible-semaphore/semaphore/db"
|
2018-04-11 20:05:38 +02:00
|
|
|
trans "github.com/snikch/goodman/transaction"
|
2020-12-04 23:22:05 +01:00
|
|
|
"regexp"
|
2018-04-11 20:05:38 +02:00
|
|
|
"strconv"
|
|
|
|
"strings"
|
|
|
|
)
|
|
|
|
|
|
|
|
// STATE
|
|
|
|
// Runtime created objects we needs to reference in test setups
|
2020-12-04 23:41:26 +01:00
|
|
|
var testRunnerUser *db.User
|
|
|
|
var userPathTestUser *db.User
|
|
|
|
var userProject *db.Project
|
|
|
|
var userKey *db.AccessKey
|
|
|
|
var task *db.Task
|
2018-04-11 20:05:38 +02:00
|
|
|
|
|
|
|
// Runtime created simple ID values for some items we need to reference in other objects
|
|
|
|
var repoID int64
|
|
|
|
var inventoryID int64
|
|
|
|
var environmentID int64
|
|
|
|
var templateID int64
|
|
|
|
|
|
|
|
var capabilities = map[string][]string{
|
|
|
|
"user": {},
|
|
|
|
"project": {"user"},
|
2021-03-12 21:20:18 +01:00
|
|
|
//"access_key": {"project"},
|
2018-04-11 20:05:38 +02:00
|
|
|
"repository": {"access_key"},
|
|
|
|
"inventory": {"repository"},
|
|
|
|
"environment": {"repository"},
|
|
|
|
"template": {"repository", "inventory", "environment"},
|
|
|
|
"task": {"template"},
|
|
|
|
}
|
|
|
|
|
|
|
|
func capabilityWrapper(cap string) func(t *trans.Transaction) {
|
|
|
|
return func(t *trans.Transaction) {
|
|
|
|
addCapabilities([]string{cap})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func addCapabilities(caps []string) {
|
|
|
|
dbConnect()
|
2020-12-04 23:22:05 +01:00
|
|
|
defer store.Sql().Db.Close()
|
2018-04-11 20:05:38 +02:00
|
|
|
resolved := make([]string, 0)
|
|
|
|
uid := getUUID()
|
|
|
|
resolveCapability(caps, resolved, uid)
|
|
|
|
}
|
|
|
|
|
|
|
|
func resolveCapability(caps []string, resolved []string, uid string) {
|
|
|
|
for _, v := range caps {
|
|
|
|
|
|
|
|
//if cap has deps resolve them
|
|
|
|
if val, ok := capabilities[v]; ok {
|
|
|
|
resolveCapability(val, resolved, uid)
|
|
|
|
}
|
|
|
|
|
|
|
|
//skip if already resolved
|
|
|
|
if _, exists := stringInSlice(v, resolved); exists {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
//Add dep specific stuff
|
|
|
|
switch v {
|
|
|
|
case "user":
|
|
|
|
userPathTestUser = addUser()
|
|
|
|
case "project":
|
|
|
|
userProject = addProject()
|
|
|
|
//allow the admin user (test executor) to manipulate the project
|
|
|
|
addUserProjectRelation(userProject.ID, testRunnerUser.ID)
|
|
|
|
addUserProjectRelation(userProject.ID, userPathTestUser.ID)
|
|
|
|
case "access_key":
|
|
|
|
userKey = addAccessKey(&userProject.ID)
|
|
|
|
case "repository":
|
2021-08-30 16:24:20 +02:00
|
|
|
pRepo, err := store.Sql().Exec(
|
|
|
|
"insert into project__repository (project_id, git_url, ssh_key_id, name) values (?, ?, ?, ?)",
|
|
|
|
userProject.ID, "git@github.com/ansible,semaphore/semaphore", userKey.ID, "ITR-"+uid)
|
2018-04-11 20:05:38 +02:00
|
|
|
printError(err)
|
|
|
|
repoID, _ = pRepo.LastInsertId()
|
|
|
|
case "inventory":
|
2021-08-30 16:24:20 +02:00
|
|
|
res, err := store.Sql().Exec(
|
|
|
|
"insert into project__inventory (project_id, name, type, key_id, ssh_key_id, inventory) values (?, ?, ?, ?, ?, ?)",
|
|
|
|
userProject.ID, "ITI-"+uid, "static", userKey.ID, userKey.ID, "Test Inventory")
|
2018-04-11 20:05:38 +02:00
|
|
|
printError(err)
|
|
|
|
inventoryID, _ = res.LastInsertId()
|
|
|
|
case "environment":
|
2021-08-30 16:24:20 +02:00
|
|
|
res, err := store.Sql().Exec(
|
|
|
|
"insert into project__environment (project_id, name, json, password) values (?, ?, ?, ?)",
|
|
|
|
userProject.ID, "ITI-"+uid, "{}", "test-pass")
|
2018-04-11 20:05:38 +02:00
|
|
|
printError(err)
|
|
|
|
environmentID, _ = res.LastInsertId()
|
|
|
|
case "template":
|
2021-08-30 16:24:20 +02:00
|
|
|
res, err := store.Sql().Exec(
|
|
|
|
"insert into project__template " +
|
|
|
|
"(ssh_key_id, project_id, inventory_id, repository_id, environment_id, alias, playbook, arguments, override_args) " +
|
|
|
|
"value (?, ?, ?, ?, ?, ?, ?, ?, ?)",
|
|
|
|
userKey.ID, userProject.ID, inventoryID, repoID, environmentID, "Test-"+uid, "test-playbook.yml", "", false)
|
2018-04-11 20:05:38 +02:00
|
|
|
printError(err)
|
|
|
|
templateID, _ = res.LastInsertId()
|
|
|
|
case "task":
|
|
|
|
task = addTask()
|
|
|
|
}
|
|
|
|
resolved = append(resolved, v)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// HOOKS
|
|
|
|
var skipTest = func(t *trans.Transaction) {
|
|
|
|
t.Skip = true
|
|
|
|
}
|
|
|
|
|
|
|
|
// Contains all the substitutions for paths under test
|
|
|
|
// The parameter example value in the api-doc should respond to the index+1 of the function in this slice
|
|
|
|
// ie the project id, with example value 1, will be replaced by the return value of pathSubPatterns[0]
|
|
|
|
var pathSubPatterns = []func() string{
|
|
|
|
func() string { return strconv.Itoa(userProject.ID) },
|
|
|
|
func() string { return strconv.Itoa(userPathTestUser.ID) },
|
|
|
|
func() string { return strconv.Itoa(userKey.ID) },
|
|
|
|
func() string { return strconv.Itoa(int(repoID)) },
|
|
|
|
func() string { return strconv.Itoa(int(inventoryID)) },
|
|
|
|
func() string { return strconv.Itoa(int(environmentID)) },
|
|
|
|
func() string { return strconv.Itoa(int(templateID)) },
|
|
|
|
func() string { return strconv.Itoa(task.ID) },
|
|
|
|
}
|
|
|
|
|
|
|
|
// alterRequestPath with the above slice of functions
|
|
|
|
func alterRequestPath(t *trans.Transaction) {
|
|
|
|
pathArgs := strings.Split(t.FullPath, "/")
|
|
|
|
exploded := make([]string, len(pathArgs))
|
|
|
|
copy(exploded, pathArgs)
|
|
|
|
for k, v := range pathSubPatterns {
|
|
|
|
pos, exists := stringInSlice(strconv.Itoa(k+1), exploded)
|
|
|
|
if exists {
|
|
|
|
pathArgs[pos] = v()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
t.FullPath = strings.Join(pathArgs, "/")
|
|
|
|
t.Request.URI = t.FullPath
|
|
|
|
}
|
|
|
|
|
|
|
|
func alterRequestBody(t *trans.Transaction) {
|
|
|
|
var request map[string]interface{}
|
|
|
|
json.Unmarshal([]byte(t.Request.Body), &request)
|
|
|
|
|
|
|
|
if userProject != nil {
|
|
|
|
bodyFieldProcessor("project_id", userProject.ID, &request)
|
|
|
|
}
|
|
|
|
bodyFieldProcessor("json", "{}", &request)
|
|
|
|
if userKey != nil {
|
|
|
|
bodyFieldProcessor("ssh_key_id", userKey.ID, &request)
|
|
|
|
bodyFieldProcessor("key_id", userKey.ID, &request)
|
|
|
|
}
|
|
|
|
bodyFieldProcessor("environment_id", environmentID, &request)
|
|
|
|
bodyFieldProcessor("inventory_id", inventoryID, &request)
|
|
|
|
bodyFieldProcessor("repository_id", repoID, &request)
|
|
|
|
bodyFieldProcessor("template_id", templateID, &request)
|
|
|
|
if task != nil {
|
|
|
|
bodyFieldProcessor("task_id", task.ID, &request)
|
|
|
|
}
|
|
|
|
|
2020-12-04 23:22:05 +01:00
|
|
|
// Inject object ID to body for PUT requests
|
|
|
|
if strings.ToLower(t.Request.Method) == "put" {
|
|
|
|
putRequestPathRE := regexp.MustCompile(`/api/(?:project/\d+/)?\w+/(\d+)/?$`)
|
|
|
|
m := putRequestPathRE.FindStringSubmatch(t.FullPath)
|
|
|
|
if len(m) > 0 {
|
|
|
|
objectID, err := strconv.Atoi(m[1])
|
|
|
|
if err != nil {
|
|
|
|
panic("Invalid object ID in PUT request " + t.FullPath)
|
|
|
|
}
|
|
|
|
request["id"] = objectID
|
|
|
|
|
|
|
|
} else {
|
|
|
|
panic("Unexpected PUT request " + t.FullPath)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-11 20:05:38 +02:00
|
|
|
out, _ := json.Marshal(request)
|
|
|
|
t.Request.Body = string(out)
|
|
|
|
}
|
|
|
|
|
|
|
|
func bodyFieldProcessor(id string, sub interface{}, request *map[string]interface{}) {
|
|
|
|
if _, ok := (*request)[id]; ok {
|
|
|
|
(*request)[id] = sub
|
|
|
|
}
|
|
|
|
}
|