173 lines
5.4 KiB
Go
173 lines
5.4 KiB
Go
package controller
|
|
|
|
import (
|
|
"errors"
|
|
"net/http"
|
|
"time"
|
|
|
|
storepkg "github.com/cirruslabs/orchard/internal/controller/store"
|
|
"github.com/cirruslabs/orchard/internal/responder"
|
|
"github.com/cirruslabs/orchard/internal/simplename"
|
|
v1 "github.com/cirruslabs/orchard/pkg/resource/v1"
|
|
"github.com/gin-gonic/gin"
|
|
"github.com/google/uuid"
|
|
)
|
|
|
|
func (controller *Controller) createServiceAccount(ctx *gin.Context) responder.Responder {
|
|
if responder := controller.authorize(ctx, v1.ServiceAccountRoleAdminWrite); responder != nil {
|
|
return responder
|
|
}
|
|
|
|
var serviceAccount v1.ServiceAccount
|
|
|
|
if err := ctx.ShouldBindJSON(&serviceAccount); err != nil {
|
|
return responder.JSON(http.StatusBadRequest, NewErrorResponse("invalid JSON was provided"))
|
|
}
|
|
|
|
// Validate service account name
|
|
if serviceAccount.Name == "" {
|
|
return responder.JSON(http.StatusPreconditionFailed,
|
|
NewErrorResponse("service account name is empty"))
|
|
} else if err := simplename.Validate(serviceAccount.Name); err != nil {
|
|
return responder.JSON(http.StatusPreconditionFailed,
|
|
NewErrorResponse("service account %v", err))
|
|
}
|
|
|
|
// Validate roles
|
|
for _, role := range serviceAccount.Roles {
|
|
_, err := v1.NewServiceAccountRole(string(role))
|
|
if err != nil {
|
|
return responder.JSON(http.StatusPreconditionFailed,
|
|
NewErrorResponse("unsupported role \"%s\"", role))
|
|
}
|
|
}
|
|
|
|
if serviceAccount.Token == "" {
|
|
serviceAccount.Token = uuid.New().String()
|
|
}
|
|
|
|
serviceAccount.CreatedAt = time.Now()
|
|
|
|
return controller.storeUpdate(func(txn storepkg.Transaction) responder.Responder {
|
|
// Does the Service Account resource with this name already exists?
|
|
_, err := txn.GetServiceAccount(serviceAccount.Name)
|
|
if err != nil && !errors.Is(err, storepkg.ErrNotFound) {
|
|
controller.logger.Errorf("failed to check if the service account exists in the DB: %v", err)
|
|
|
|
return responder.Code(http.StatusInternalServerError)
|
|
}
|
|
if err == nil {
|
|
return responder.JSON(http.StatusConflict,
|
|
NewErrorResponse("service account with this name already exists"))
|
|
}
|
|
|
|
if err := txn.SetServiceAccount(&serviceAccount); err != nil {
|
|
controller.logger.Errorf("failed to create the service account in the DB: %v", err)
|
|
|
|
return responder.Code(http.StatusInternalServerError)
|
|
}
|
|
|
|
return responder.JSON(http.StatusOK, &serviceAccount)
|
|
})
|
|
}
|
|
|
|
func (controller *Controller) updateServiceAccount(ctx *gin.Context) responder.Responder {
|
|
if responder := controller.authorize(ctx, v1.ServiceAccountRoleAdminWrite); responder != nil {
|
|
return responder
|
|
}
|
|
|
|
var userServiceAccount v1.ServiceAccount
|
|
|
|
if err := ctx.ShouldBindJSON(&userServiceAccount); err != nil {
|
|
return responder.JSON(http.StatusBadRequest, NewErrorResponse("invalid JSON was provided"))
|
|
}
|
|
|
|
// Validate service account name
|
|
if userServiceAccount.Name == "" {
|
|
return responder.JSON(http.StatusPreconditionFailed,
|
|
NewErrorResponse("service account name is empty"))
|
|
} else if err := simplename.Validate(userServiceAccount.Name); err != nil {
|
|
return responder.JSON(http.StatusPreconditionFailed,
|
|
NewErrorResponse("service account %v", err))
|
|
}
|
|
|
|
// Validate roles
|
|
for _, role := range userServiceAccount.Roles {
|
|
_, err := v1.NewServiceAccountRole(string(role))
|
|
if err != nil {
|
|
return responder.JSON(http.StatusPreconditionFailed,
|
|
NewErrorResponse("unsupported role \"%s\"", role))
|
|
}
|
|
}
|
|
|
|
if userServiceAccount.Token == "" {
|
|
return responder.JSON(http.StatusPreconditionFailed, NewErrorResponse("service account token is empty"))
|
|
}
|
|
|
|
return controller.storeUpdate(func(txn storepkg.Transaction) responder.Responder {
|
|
dbServiceAccount, err := txn.GetServiceAccount(userServiceAccount.Name)
|
|
if err != nil {
|
|
return responder.Error(err)
|
|
}
|
|
|
|
dbServiceAccount.Token = userServiceAccount.Token
|
|
dbServiceAccount.Roles = userServiceAccount.Roles
|
|
|
|
if err := txn.SetServiceAccount(dbServiceAccount); err != nil {
|
|
controller.logger.Errorf("failed to update service account in the DB: %v", err)
|
|
|
|
return responder.Code(http.StatusInternalServerError)
|
|
}
|
|
|
|
return responder.JSON(http.StatusOK, &dbServiceAccount)
|
|
})
|
|
}
|
|
|
|
func (controller *Controller) getServiceAccount(ctx *gin.Context) responder.Responder {
|
|
if responder := controller.authorize(ctx, v1.ServiceAccountRoleAdminRead); responder != nil {
|
|
return responder
|
|
}
|
|
|
|
name := ctx.Param("name")
|
|
|
|
return controller.storeView(func(txn storepkg.Transaction) responder.Responder {
|
|
serviceAccount, err := txn.GetServiceAccount(name)
|
|
if err != nil {
|
|
return responder.Error(err)
|
|
}
|
|
|
|
return responder.JSON(http.StatusOK, &serviceAccount)
|
|
})
|
|
}
|
|
|
|
func (controller *Controller) listServiceAccounts(ctx *gin.Context) responder.Responder {
|
|
if responder := controller.authorize(ctx, v1.ServiceAccountRoleAdminRead); responder != nil {
|
|
return responder
|
|
}
|
|
|
|
return controller.storeView(func(txn storepkg.Transaction) responder.Responder {
|
|
serviceAccounts, err := txn.ListServiceAccounts()
|
|
if err != nil {
|
|
return responder.Error(err)
|
|
}
|
|
|
|
return responder.JSON(http.StatusOK, &serviceAccounts)
|
|
})
|
|
}
|
|
|
|
func (controller *Controller) deleteServiceAccount(ctx *gin.Context) responder.Responder {
|
|
if responder := controller.authorize(ctx, v1.ServiceAccountRoleAdminWrite); responder != nil {
|
|
return responder
|
|
}
|
|
|
|
name := ctx.Param("name")
|
|
|
|
return controller.storeUpdate(func(txn storepkg.Transaction) responder.Responder {
|
|
if err := txn.DeleteServiceAccount(name); err != nil {
|
|
return responder.Error(err)
|
|
}
|
|
|
|
return responder.Code(http.StatusOK)
|
|
})
|
|
}
|