1
0
Fork 0
mirror of https://github.com/portainer/portainer.git synced 2025-07-24 15:59:41 +02:00

feat(endpointgroups): implement support for transactions EE-5328 (#8944)

This commit is contained in:
andres-portainer 2023-05-16 14:47:31 -03:00 committed by GitHub
parent 077046030d
commit d29b688eb9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 287 additions and 88 deletions

View file

@ -1,6 +1,7 @@
package endpointgroups
import (
"errors"
"net/http"
"reflect"
@ -8,7 +9,9 @@ import (
"github.com/portainer/libhttp/request"
"github.com/portainer/libhttp/response"
portainer "github.com/portainer/portainer/api"
"github.com/portainer/portainer/api/dataservices"
"github.com/portainer/portainer/api/internal/tag"
"github.com/portainer/portainer/pkg/featureflags"
)
type endpointGroupUpdatePayload struct {
@ -54,11 +57,34 @@ func (handler *Handler) endpointGroupUpdate(w http.ResponseWriter, r *http.Reque
return httperror.BadRequest("Invalid request payload", err)
}
endpointGroup, err := handler.DataStore.EndpointGroup().EndpointGroup(portainer.EndpointGroupID(endpointGroupID))
if handler.DataStore.IsErrObjectNotFound(err) {
return httperror.NotFound("Unable to find an environment group with the specified identifier inside the database", err)
var endpointGroup *portainer.EndpointGroup
if featureflags.IsEnabled(portainer.FeatureNoTx) {
endpointGroup, err = handler.updateEndpointGroup(handler.DataStore, portainer.EndpointGroupID(endpointGroupID), payload)
} else {
err = handler.DataStore.UpdateTx(func(tx dataservices.DataStoreTx) error {
endpointGroup, err = handler.updateEndpointGroup(tx, portainer.EndpointGroupID(endpointGroupID), payload)
return err
})
}
if err != nil {
var httpErr *httperror.HandlerError
if errors.As(err, &httpErr) {
return httpErr
}
return httperror.InternalServerError("Unexpected error", err)
}
return response.JSON(w, endpointGroup)
}
func (handler *Handler) updateEndpointGroup(tx dataservices.DataStoreTx, endpointGroupID portainer.EndpointGroupID, payload endpointGroupUpdatePayload) (*portainer.EndpointGroup, error) {
endpointGroup, err := tx.EndpointGroup().EndpointGroup(portainer.EndpointGroupID(endpointGroupID))
if tx.IsErrObjectNotFound(err) {
return nil, httperror.NotFound("Unable to find an environment group with the specified identifier inside the database", err)
} else if err != nil {
return httperror.InternalServerError("Unable to find an environment group with the specified identifier inside the database", err)
return nil, httperror.InternalServerError("Unable to find an environment group with the specified identifier inside the database", err)
}
if payload.Name != "" {
@ -81,27 +107,59 @@ func (handler *Handler) endpointGroupUpdate(w http.ResponseWriter, r *http.Reque
removeTags := tag.Difference(endpointGroupTagSet, payloadTagSet)
for tagID := range removeTags {
err = handler.DataStore.Tag().UpdateTagFunc(tagID, func(tag *portainer.Tag) {
delete(tag.EndpointGroups, endpointGroup.ID)
})
if featureflags.IsEnabled(portainer.FeatureNoTx) {
err = tx.Tag().UpdateTagFunc(tagID, func(tag *portainer.Tag) {
delete(tag.EndpointGroups, endpointGroup.ID)
})
if handler.DataStore.IsErrObjectNotFound(err) {
return httperror.InternalServerError("Unable to find a tag inside the database", err)
} else if err != nil {
return httperror.InternalServerError("Unable to persist tag changes inside the database", err)
if tx.IsErrObjectNotFound(err) {
return nil, httperror.InternalServerError("Unable to find a tag inside the database", err)
} else if err != nil {
return nil, httperror.InternalServerError("Unable to persist tag changes inside the database", err)
}
continue
}
tag, err := tx.Tag().Tag(tagID)
if err != nil {
return nil, httperror.InternalServerError("Unable to find a tag inside the database", err)
}
delete(tag.EndpointGroups, endpointGroup.ID)
err = tx.Tag().UpdateTag(tagID, tag)
if err != nil {
return nil, httperror.InternalServerError("Unable to persist tag changes inside the database", err)
}
}
endpointGroup.TagIDs = payload.TagIDs
for _, tagID := range payload.TagIDs {
err = handler.DataStore.Tag().UpdateTagFunc(tagID, func(tag *portainer.Tag) {
tag.EndpointGroups[endpointGroup.ID] = true
})
if featureflags.IsEnabled(portainer.FeatureNoTx) {
err = tx.Tag().UpdateTagFunc(tagID, func(tag *portainer.Tag) {
tag.EndpointGroups[endpointGroup.ID] = true
})
if handler.DataStore.IsErrObjectNotFound(err) {
return httperror.InternalServerError("Unable to find a tag inside the database", err)
} else if err != nil {
return httperror.InternalServerError("Unable to persist tag changes inside the database", err)
if tx.IsErrObjectNotFound(err) {
return nil, httperror.InternalServerError("Unable to find a tag inside the database", err)
} else if err != nil {
return nil, httperror.InternalServerError("Unable to persist tag changes inside the database", err)
}
continue
}
tag, err := tx.Tag().Tag(tagID)
if err != nil {
return nil, httperror.InternalServerError("Unable to find a tag inside the database", err)
}
tag.EndpointGroups[endpointGroup.ID] = true
err = tx.Tag().UpdateTag(tagID, tag)
if err != nil {
return nil, httperror.InternalServerError("Unable to persist tag changes inside the database", err)
}
}
}
@ -119,44 +177,44 @@ func (handler *Handler) endpointGroupUpdate(w http.ResponseWriter, r *http.Reque
}
if updateAuthorizations {
endpoints, err := handler.DataStore.Endpoint().Endpoints()
endpoints, err := tx.Endpoint().Endpoints()
if err != nil {
return httperror.InternalServerError("Unable to retrieve environments from the database", err)
return nil, httperror.InternalServerError("Unable to retrieve environments from the database", err)
}
for _, endpoint := range endpoints {
if endpoint.GroupID == endpointGroup.ID {
if endpoint.Type == portainer.KubernetesLocalEnvironment || endpoint.Type == portainer.AgentOnKubernetesEnvironment || endpoint.Type == portainer.EdgeAgentOnKubernetesEnvironment {
err = handler.AuthorizationService.CleanNAPWithOverridePolicies(&endpoint, endpointGroup)
err = handler.AuthorizationService.CleanNAPWithOverridePolicies(tx, &endpoint, endpointGroup)
if err != nil {
return httperror.InternalServerError("Unable to update user authorizations", err)
return nil, httperror.InternalServerError("Unable to update user authorizations", err)
}
}
}
}
}
err = handler.DataStore.EndpointGroup().UpdateEndpointGroup(endpointGroup.ID, endpointGroup)
err = tx.EndpointGroup().UpdateEndpointGroup(endpointGroup.ID, endpointGroup)
if err != nil {
return httperror.InternalServerError("Unable to persist environment group changes inside the database", err)
return nil, httperror.InternalServerError("Unable to persist environment group changes inside the database", err)
}
if tagsChanged {
endpoints, err := handler.DataStore.Endpoint().Endpoints()
endpoints, err := tx.Endpoint().Endpoints()
if err != nil {
return httperror.InternalServerError("Unable to retrieve environments from the database", err)
return nil, httperror.InternalServerError("Unable to retrieve environments from the database", err)
}
for _, endpoint := range endpoints {
if endpoint.GroupID == endpointGroup.ID {
err = handler.updateEndpointRelations(&endpoint, endpointGroup)
err = handler.updateEndpointRelations(tx, &endpoint, endpointGroup)
if err != nil {
return httperror.InternalServerError("Unable to persist environment relations changes inside the database", err)
return nil, httperror.InternalServerError("Unable to persist environment relations changes inside the database", err)
}
}
}
}
return response.JSON(w, endpointGroup)
return endpointGroup, nil
}