portainer/api/http/handler/templates/template_file.go

94 lines
2.7 KiB
Go

package templates
import (
"net/http"
"slices"
portainer "github.com/portainer/portainer/api"
httperror "github.com/portainer/portainer/pkg/libhttp/error"
"github.com/portainer/portainer/pkg/libhttp/request"
"github.com/portainer/portainer/pkg/libhttp/response"
"github.com/rs/zerolog/log"
)
type fileResponse struct {
// The requested file content
FileContent string `example:"version:2"`
}
// @id TemplateFile
// @summary Get a template's file
// @description Get a template's file
// @description **Access policy**: authenticated
// @tags templates
// @security ApiKeyAuth
// @security jwt
// @accept json
// @produce json
// @param id path int true "Template identifier"
// @success 200 {object} fileResponse "Success"
// @failure 400 "Invalid request"
// @failure 500 "Server error"
// @router /templates/{id}/file [post]
func (handler *Handler) templateFile(w http.ResponseWriter, r *http.Request) *httperror.HandlerError {
id, err := request.RetrieveNumericRouteVariableValue(r, "id")
if err != nil {
return httperror.BadRequest("Invalid template identifier", err)
}
templatesResponse, httpErr := handler.fetchTemplates()
if httpErr != nil {
return httpErr
}
templateIdx := slices.IndexFunc(templatesResponse.Templates, func(template portainer.Template) bool {
return template.ID == portainer.TemplateID(id)
})
if templateIdx == -1 {
return httperror.NotFound("Unable to find a template with the specified identifier", nil)
}
template := templatesResponse.Templates[templateIdx]
if template.Type == portainer.ContainerTemplate {
return httperror.BadRequest("Invalid template type", nil)
}
if template.StackFile != "" {
return response.JSON(w, fileResponse{FileContent: template.StackFile})
}
if template.Repository.StackFile == "" || template.Repository.URL == "" {
return httperror.BadRequest("Invalid template configuration", nil)
}
projectPath, err := handler.FileService.GetTemporaryPath()
if err != nil {
return httperror.InternalServerError("Unable to create temporary folder", err)
}
defer handler.cleanUp(projectPath)
err = handler.GitService.CloneRepository(projectPath, template.Repository.URL, "", "", "", false)
if err != nil {
return httperror.InternalServerError("Unable to clone git repository", err)
}
fileContent, err := handler.FileService.GetFileContent(projectPath, template.Repository.StackFile)
if err != nil {
return httperror.InternalServerError("Failed loading file content", err)
}
return response.JSON(w, fileResponse{FileContent: string(fileContent)})
}
func (handler *Handler) cleanUp(projectPath string) {
err := handler.FileService.RemoveDirectory(projectPath)
if err != nil {
log.Debug().Err(err).Msg("HTTP error: unable to cleanup stack creation")
}
}