diff --git a/controllers/task_definitions_controller.go b/controllers/task_definitions_controller.go index 4bd6542..25513c3 100644 --- a/controllers/task_definitions_controller.go +++ b/controllers/task_definitions_controller.go @@ -263,3 +263,40 @@ func DeleteTaskDefinition(c *gin.Context) { "message": "deleted", }) } + +// GetTaskHistory godoc +// @Summary Returns a history of the executions for the given task definition. +// @Description Returns a history of the executions for the given task definition. +// @Tags definition +// @Produce application/json +// @Param definitionId path string true "The task definition id" +// @Param offset query int false "Offset of the history" +// @Param limit query int false "Limit the number of the results" +// @Success 200 +// @Router /api/v1/task/{definitionId}/history [get] +func GetTaskHistory(c *gin.Context) { + // var err error + apiKey, authErr := AuthRequest(c) + + if authErr != nil { + c.AbortWithStatus(http.StatusUnauthorized) + return + } + + uuidParam := c.Param("definitionId") + definitionId, err := uuid.Parse(uuidParam) + if err != nil { + c.JSON(http.StatusBadRequest, c.Error(err)) + return + } + + offset := ParseIntQueryParameter(c, "offset", 0) + limit := ParseIntQueryParameter(c, "limit", 10) + + executions, err := dao.GetExecutionsHistory(definitionId, apiKey.OrganizationId, offset, limit) + if err != nil { + c.AbortWithStatus(http.StatusInternalServerError) + } + + c.IndentedJSON(http.StatusOK, executions) +} diff --git a/controllers/utils.go b/controllers/utils.go index f797676..060b18d 100644 --- a/controllers/utils.go +++ b/controllers/utils.go @@ -2,6 +2,7 @@ package controllers import ( "errors" + "strconv" "github.com/drorivry/rego/dao" "github.com/drorivry/rego/models" @@ -9,16 +10,27 @@ import ( "github.com/rs/zerolog/log" ) -func AuthRequest(c *gin.Context) (*models.ApiKeys, error){ +func AuthRequest(c *gin.Context) (*models.ApiKeys, error) { token := c.GetHeader("X-Rego-Api-Key") apiKey, authErr := dao.AuthApiKey(token) if authErr != nil { log.Error().Err(authErr).Msg("Invalid token") - return nil, errors.New("Invalid token"); + return nil, errors.New("Invalid token") } return &apiKey, nil -} \ No newline at end of file +} + +func ParseIntQueryParameter(c *gin.Context, paramName string, defaultValue int) int { + param_str := c.DefaultQuery(paramName, strconv.Itoa(defaultValue)) + param, err := strconv.Atoi(param_str) + + if err != nil { + param = 0 + } + + return param +} diff --git a/dao/api_keys_dao.go b/dao/api_keys_dao.go index 2a59d77..f3b6a3a 100644 --- a/dao/api_keys_dao.go +++ b/dao/api_keys_dao.go @@ -24,7 +24,7 @@ func AuthApiKey(apiKey string) (models.ApiKeys, error) { var api_key models.ApiKeys h := sha256.New() - h.Write([]byte(apiKey)) + h.Write([]byte(apiKey)) hashedKey := hex.EncodeToString(h.Sum(nil)) result := initializers.GetApiKeysTable().Where( @@ -37,3 +37,10 @@ func AuthApiKey(apiKey string) (models.ApiKeys, error) { } return api_key, nil } + +func CountApiKeys() int64 { + var count int64 + initializers.GetApiKeysTable().Count(&count) + + return count +} diff --git a/dao/executions_dao.go b/dao/executions_dao.go index 468dab9..7473359 100644 --- a/dao/executions_dao.go +++ b/dao/executions_dao.go @@ -77,7 +77,6 @@ func UpdateExecutionStatus(executionId uuid.UUID, status models.Status, Organiza return } - InsertExecutionStatusUpdate(executionId, status, OrganizationId) } @@ -104,3 +103,37 @@ func GetLatestExecutionByDefinitionId(definitionId uuid.UUID, OrganizationId str return task, result.Error } + +func GetExecutionsHistory(definitionId uuid.UUID, organizationId string, offset int, limit int) ([]models.TaskExecution, error) { + var executions []models.TaskExecution + + result := initializers.GetTaskExecutionsTable().Where( + "task_definition_id = ?", + definitionId, + ).Where( + "organization_id = ?", + organizationId, + ).Order( + "created_at desc", + ).Offset( + offset, + ).Limit( + limit, + ).Find(&executions) + + if result.Error != nil { + log.Error().Err( + result.Error, + ).Str( + "definition_id", + definitionId.String(), + ).Str( + "organization_id", + organizationId, + ).Msg( + "Error fetching executions history from db", + ) + } + + return executions, result.Error +} diff --git a/main.go b/main.go index e2d3927..c89ccae 100644 --- a/main.go +++ b/main.go @@ -2,6 +2,8 @@ package main import ( "context" + "crypto/sha256" + "encoding/hex" "flag" "net/http" "os" @@ -12,8 +14,10 @@ import ( "github.com/rs/zerolog/log" "github.com/drorivry/rego/config" + "github.com/drorivry/rego/dao" "github.com/drorivry/rego/initializers" k8s_client "github.com/drorivry/rego/k8s" + "github.com/drorivry/rego/models" "github.com/drorivry/rego/poller" "github.com/drorivry/rego/tasker" ) @@ -37,10 +41,30 @@ func handleInterrupt(c chan os.Signal, server *http.Server, p *poller.Poller) { p.Shutdown() } +func initApiKey() { + h := sha256.New() + h.Write([]byte("delete_me")) + hashedKey := hex.EncodeToString(h.Sum(nil)) + + if dao.CountApiKeys() == 0 { + log.Info().Msg("Creating initial api key") + dao.CreateApiKey( + &models.ApiKeys{ + ApiKey: hashedKey, + ApiKeyHint: "Delete Me", + OrganizationId: "delete_me", + }, + ) + } + +} + func init() { initializers.LoadEnvVars() config.InitConfig() initializers.InitDBConnection() + + initApiKey() } // @title Rego diff --git a/tasker/tasker.go b/tasker/tasker.go index 20301b9..4be5be9 100644 --- a/tasker/tasker.go +++ b/tasker/tasker.go @@ -33,6 +33,7 @@ func GetServer(port int) *http.Server { v1.POST("/task", ginZerologger, controllers.CreateTaskDefinition) v1.POST("/task/:definitionId/rerun", ginZerologger, controllers.RerunTask) v1.GET("/task/:definitionId/latest", ginZerologger, controllers.GetLatestExecution) + v1.GET("task/:definitionId/history", ginZerologger, controllers.GetTaskHistory) v1.PUT("/task", ginZerologger, controllers.UpdateTaskDefinition) v1.DELETE("/task/:definitionId", ginZerologger, controllers.DeleteTaskDefinition) v1.GET("/tasks/pending", ginZerologger, controllers.GetAllPendingTaskDefinitions)