1
0
Fork 0
mirror of https://github.com/portainer/portainer.git synced 2025-07-23 15:29:42 +02:00

refactor(stacks): extract auto update logic [EE-4945] (#8545)

This commit is contained in:
Chaim Lev-Ari 2023-03-02 17:07:50 +02:00 committed by GitHub
parent 085381e6fc
commit 6918da2414
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
42 changed files with 410 additions and 166 deletions

View file

@ -0,0 +1,13 @@
package errors
type InvalidPayloadError struct {
msg string
}
func (e *InvalidPayloadError) Error() string {
return e.msg
}
func NewInvalidPayloadError(msg string) *InvalidPayloadError {
return &InvalidPayloadError{msg: msg}
}

View file

@ -8,6 +8,7 @@ import (
"github.com/portainer/libhttp/request"
portainer "github.com/portainer/portainer/api"
"github.com/portainer/portainer/api/filesystem"
"github.com/portainer/portainer/api/git/update"
"github.com/portainer/portainer/api/http/security"
"github.com/portainer/portainer/api/stacks/deployments"
"github.com/portainer/portainer/api/stacks/stackbuilders"
@ -156,14 +157,14 @@ type composeStackFromGitRepositoryPayload struct {
// Applicable when deploying with multiple stack files
AdditionalFiles []string `example:"[nz.compose.yml, uat.compose.yml]"`
// Optional auto update configuration
AutoUpdate *portainer.StackAutoUpdate
AutoUpdate *portainer.AutoUpdateSettings
// A list of environment(endpoint) variables used during stack deployment
Env []portainer.Pair
// Whether the stack is from a app template
FromAppTemplate bool `example:"false"`
}
func createStackPayloadFromComposeGitPayload(name, repoUrl, repoReference, repoUsername, repoPassword string, repoAuthentication bool, composeFile string, additionalFiles []string, autoUpdate *portainer.StackAutoUpdate, env []portainer.Pair, fromAppTemplate bool) stackbuilders.StackPayload {
func createStackPayloadFromComposeGitPayload(name, repoUrl, repoReference, repoUsername, repoPassword string, repoAuthentication bool, composeFile string, additionalFiles []string, autoUpdate *portainer.AutoUpdateSettings, env []portainer.Pair, fromAppTemplate bool) stackbuilders.StackPayload {
return stackbuilders.StackPayload{
Name: name,
RepositoryConfigPayload: stackbuilders.RepositoryConfigPayload{
@ -191,7 +192,7 @@ func (payload *composeStackFromGitRepositoryPayload) Validate(r *http.Request) e
if payload.RepositoryAuthentication && govalidator.IsNull(payload.RepositoryPassword) {
return errors.New("Invalid repository credentials. Password must be specified when authentication is enabled")
}
if err := stackutils.ValidateStackAutoUpdate(payload.AutoUpdate); err != nil {
if err := update.ValidateAutoUpdateSettings(payload.AutoUpdate); err != nil {
return err
}
return nil

View file

@ -11,6 +11,7 @@ import (
"github.com/portainer/libhttp/request"
"github.com/portainer/libhttp/response"
portainer "github.com/portainer/portainer/api"
"github.com/portainer/portainer/api/git/update"
k "github.com/portainer/portainer/api/kubernetes"
"github.com/portainer/portainer/api/stacks/deployments"
"github.com/portainer/portainer/api/stacks/stackbuilders"
@ -44,10 +45,10 @@ type kubernetesGitDeploymentPayload struct {
RepositoryPassword string
ManifestFile string
AdditionalFiles []string
AutoUpdate *portainer.StackAutoUpdate
AutoUpdate *portainer.AutoUpdateSettings
}
func createStackPayloadFromK8sGitPayload(name, repoUrl, repoReference, repoUsername, repoPassword string, repoAuthentication, composeFormat bool, namespace, manifest string, additionalFiles []string, autoUpdate *portainer.StackAutoUpdate) stackbuilders.StackPayload {
func createStackPayloadFromK8sGitPayload(name, repoUrl, repoReference, repoUsername, repoPassword string, repoAuthentication, composeFormat bool, namespace, manifest string, additionalFiles []string, autoUpdate *portainer.AutoUpdateSettings) stackbuilders.StackPayload {
return stackbuilders.StackPayload{
StackName: name,
RepositoryConfigPayload: stackbuilders.RepositoryConfigPayload{
@ -101,7 +102,7 @@ func (payload *kubernetesGitDeploymentPayload) Validate(r *http.Request) error {
if govalidator.IsNull(payload.ManifestFile) {
return errors.New("Invalid manifest file in repository")
}
if err := stackutils.ValidateStackAutoUpdate(payload.AutoUpdate); err != nil {
if err := update.ValidateAutoUpdateSettings(payload.AutoUpdate); err != nil {
return err
}
if govalidator.IsNull(payload.StackName) {

View file

@ -10,6 +10,7 @@ import (
httperror "github.com/portainer/libhttp/error"
"github.com/portainer/libhttp/request"
portainer "github.com/portainer/portainer/api"
"github.com/portainer/portainer/api/git/update"
"github.com/portainer/portainer/api/http/security"
"github.com/portainer/portainer/api/stacks/stackbuilders"
"github.com/portainer/portainer/api/stacks/stackutils"
@ -115,7 +116,7 @@ type swarmStackFromGitRepositoryPayload struct {
// Applicable when deploying with multiple stack files
AdditionalFiles []string `example:"[nz.compose.yml, uat.compose.yml]"`
// Optional auto update configuration
AutoUpdate *portainer.StackAutoUpdate
AutoUpdate *portainer.AutoUpdateSettings
}
func (payload *swarmStackFromGitRepositoryPayload) Validate(r *http.Request) error {
@ -131,13 +132,13 @@ func (payload *swarmStackFromGitRepositoryPayload) Validate(r *http.Request) err
if payload.RepositoryAuthentication && govalidator.IsNull(payload.RepositoryPassword) {
return errors.New("Invalid repository credentials. Password must be specified when authentication is enabled")
}
if err := stackutils.ValidateStackAutoUpdate(payload.AutoUpdate); err != nil {
if err := update.ValidateAutoUpdateSettings(payload.AutoUpdate); err != nil {
return err
}
return nil
}
func createStackPayloadFromSwarmGitPayload(name, swarmID, repoUrl, repoReference, repoUsername, repoPassword string, repoAuthentication bool, composeFile string, additionalFiles []string, autoUpdate *portainer.StackAutoUpdate, env []portainer.Pair, fromAppTemplate bool) stackbuilders.StackPayload {
func createStackPayloadFromSwarmGitPayload(name, swarmID, repoUrl, repoReference, repoUsername, repoPassword string, repoAuthentication bool, composeFile string, additionalFiles []string, autoUpdate *portainer.AutoUpdateSettings, env []portainer.Pair, fromAppTemplate bool) stackbuilders.StackPayload {
return stackbuilders.StackPayload{
Name: name,
SwarmID: swarmID,

View file

@ -10,6 +10,7 @@ import (
"github.com/portainer/libhttp/response"
portainer "github.com/portainer/portainer/api"
gittypes "github.com/portainer/portainer/api/git/types"
"github.com/portainer/portainer/api/git/update"
httperrors "github.com/portainer/portainer/api/http/errors"
"github.com/portainer/portainer/api/http/security"
"github.com/portainer/portainer/api/stacks/deployments"
@ -17,7 +18,7 @@ import (
)
type stackGitUpdatePayload struct {
AutoUpdate *portainer.StackAutoUpdate
AutoUpdate *portainer.AutoUpdateSettings
Env []portainer.Pair
Prune bool
RepositoryReferenceName string
@ -27,7 +28,7 @@ type stackGitUpdatePayload struct {
}
func (payload *stackGitUpdatePayload) Validate(r *http.Request) error {
if err := stackutils.ValidateStackAutoUpdate(payload.AutoUpdate); err != nil {
if err := update.ValidateAutoUpdateSettings(payload.AutoUpdate); err != nil {
return err
}
return nil

View file

@ -11,13 +11,12 @@ import (
"github.com/portainer/libhttp/response"
portainer "github.com/portainer/portainer/api"
"github.com/portainer/portainer/api/filesystem"
"github.com/portainer/portainer/api/git"
httperrors "github.com/portainer/portainer/api/http/errors"
"github.com/portainer/portainer/api/http/security"
k "github.com/portainer/portainer/api/kubernetes"
"github.com/portainer/portainer/api/stacks/deployments"
"github.com/portainer/portainer/api/stacks/stackutils"
"github.com/rs/zerolog/log"
)
type stackGitRedployPayload struct {
@ -154,22 +153,12 @@ func (handler *Handler) stackGitRedeploy(w http.ResponseWriter, r *http.Request)
repositoryUsername = payload.RepositoryUsername
}
err = handler.GitService.CloneRepository(stack.ProjectPath, stack.GitConfig.URL, payload.RepositoryReferenceName, repositoryUsername, repositoryPassword)
clean, err := git.CloneWithBackup(handler.GitService, handler.FileService, git.CloneOptions{ProjectPath: stack.ProjectPath, URL: stack.GitConfig.URL, ReferenceName: stack.GitConfig.ReferenceName, Username: repositoryUsername, Password: repositoryPassword})
if err != nil {
restoreError := filesystem.MoveDirectory(backupProjectPath, stack.ProjectPath)
if restoreError != nil {
log.Warn().Err(restoreError).Msg("failed restoring backup folder")
}
return httperror.InternalServerError("Unable to clone git repository", err)
return httperror.InternalServerError("Unable to clone git repository directory", err)
}
defer func() {
err = handler.FileService.RemoveDirectory(backupProjectPath)
if err != nil {
log.Warn().Err(err).Msg("unable to remove git repository directory")
}
}()
defer clean()
httpErr := handler.deployStack(r, stack, payload.PullImage, endpoint)
if httpErr != nil {

View file

@ -11,10 +11,10 @@ import (
portainer "github.com/portainer/portainer/api"
"github.com/portainer/portainer/api/filesystem"
gittypes "github.com/portainer/portainer/api/git/types"
"github.com/portainer/portainer/api/git/update"
"github.com/portainer/portainer/api/http/security"
k "github.com/portainer/portainer/api/kubernetes"
"github.com/portainer/portainer/api/stacks/deployments"
"github.com/portainer/portainer/api/stacks/stackutils"
"github.com/asaskevich/govalidator"
"github.com/pkg/errors"
@ -30,7 +30,7 @@ type kubernetesGitStackUpdatePayload struct {
RepositoryAuthentication bool
RepositoryUsername string
RepositoryPassword string
AutoUpdate *portainer.StackAutoUpdate
AutoUpdate *portainer.AutoUpdateSettings
}
func (payload *kubernetesFileStackUpdatePayload) Validate(r *http.Request) error {
@ -41,7 +41,7 @@ func (payload *kubernetesFileStackUpdatePayload) Validate(r *http.Request) error
}
func (payload *kubernetesGitStackUpdatePayload) Validate(r *http.Request) error {
if err := stackutils.ValidateStackAutoUpdate(payload.AutoUpdate); err != nil {
if err := update.ValidateAutoUpdateSettings(payload.AutoUpdate); err != nil {
return err
}
return nil

View file

@ -9,7 +9,6 @@ import (
"github.com/portainer/portainer/api/stacks/deployments"
"github.com/gofrs/uuid"
"github.com/rs/zerolog/log"
)
// @id WebhookInvoke
@ -43,8 +42,6 @@ func (handler *Handler) webhookInvoke(w http.ResponseWriter, r *http.Request) *h
return &httperror.HandlerError{StatusCode: http.StatusConflict, Message: "Autoupdate for the stack isn't available", Err: err}
}
log.Error().Err(err).Msg("failed to update the stack")
return httperror.InternalServerError("Failed to update the stack", err)
}

View file

@ -18,7 +18,8 @@ func TestHandler_webhookInvoke(t *testing.T) {
webhookID := newGuidString(t)
store.StackService.Create(&portainer.Stack{
AutoUpdate: &portainer.StackAutoUpdate{
ID: 1,
AutoUpdate: &portainer.AutoUpdateSettings{
Webhook: webhookID,
},
})