mirror of https://github.com/portainer/portainer
chore(edge): add transaction support for common objects EE-5079 (#8522)
parent
9a8e95d017
commit
95ac2cc4c3
|
@ -8,10 +8,8 @@ import (
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
|
||||||
// BucketName represents the name of the bucket where this service stores data.
|
// BucketName represents the name of the bucket where this service stores data.
|
||||||
BucketName = "edgejobs"
|
const BucketName = "edgejobs"
|
||||||
)
|
|
||||||
|
|
||||||
// Service represents a service for managing edge jobs data.
|
// Service represents a service for managing edge jobs data.
|
||||||
type Service struct {
|
type Service struct {
|
||||||
|
@ -34,6 +32,13 @@ func NewService(connection portainer.Connection) (*Service, error) {
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (service *Service) Tx(tx portainer.Transaction) ServiceTx {
|
||||||
|
return ServiceTx{
|
||||||
|
service: service,
|
||||||
|
tx: tx,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// EdgeJobs returns a list of Edge jobs
|
// EdgeJobs returns a list of Edge jobs
|
||||||
func (service *Service) EdgeJobs() ([]portainer.EdgeJob, error) {
|
func (service *Service) EdgeJobs() ([]portainer.EdgeJob, error) {
|
||||||
var edgeJobs = make([]portainer.EdgeJob, 0)
|
var edgeJobs = make([]portainer.EdgeJob, 0)
|
||||||
|
|
|
@ -0,0 +1,84 @@
|
||||||
|
package edgejob
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
portainer "github.com/portainer/portainer/api"
|
||||||
|
|
||||||
|
"github.com/rs/zerolog/log"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ServiceTx struct {
|
||||||
|
service *Service
|
||||||
|
tx portainer.Transaction
|
||||||
|
}
|
||||||
|
|
||||||
|
func (service ServiceTx) BucketName() string {
|
||||||
|
return BucketName
|
||||||
|
}
|
||||||
|
|
||||||
|
// EdgeJobs returns a list of Edge jobs
|
||||||
|
func (service ServiceTx) EdgeJobs() ([]portainer.EdgeJob, error) {
|
||||||
|
var edgeJobs = make([]portainer.EdgeJob, 0)
|
||||||
|
|
||||||
|
err := service.tx.GetAll(
|
||||||
|
BucketName,
|
||||||
|
&portainer.EdgeJob{},
|
||||||
|
func(obj interface{}) (interface{}, error) {
|
||||||
|
job, ok := obj.(*portainer.EdgeJob)
|
||||||
|
if !ok {
|
||||||
|
log.Debug().Str("obj", fmt.Sprintf("%#v", obj)).Msg("failed to convert to EdgeJob object")
|
||||||
|
return nil, fmt.Errorf("failed to convert to EdgeJob object: %s", obj)
|
||||||
|
}
|
||||||
|
|
||||||
|
edgeJobs = append(edgeJobs, *job)
|
||||||
|
|
||||||
|
return &portainer.EdgeJob{}, nil
|
||||||
|
})
|
||||||
|
|
||||||
|
return edgeJobs, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// EdgeJob returns an Edge job by ID
|
||||||
|
func (service ServiceTx) EdgeJob(ID portainer.EdgeJobID) (*portainer.EdgeJob, error) {
|
||||||
|
var edgeJob portainer.EdgeJob
|
||||||
|
identifier := service.service.connection.ConvertToKey(int(ID))
|
||||||
|
|
||||||
|
err := service.tx.GetObject(BucketName, identifier, &edgeJob)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &edgeJob, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create creates a new EdgeJob
|
||||||
|
func (service ServiceTx) Create(ID portainer.EdgeJobID, edgeJob *portainer.EdgeJob) error {
|
||||||
|
edgeJob.ID = ID
|
||||||
|
|
||||||
|
return service.tx.CreateObjectWithId(BucketName, int(edgeJob.ID), edgeJob)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateEdgeJob updates an edge job
|
||||||
|
func (service ServiceTx) UpdateEdgeJob(ID portainer.EdgeJobID, edgeJob *portainer.EdgeJob) error {
|
||||||
|
identifier := service.service.connection.ConvertToKey(int(ID))
|
||||||
|
return service.tx.UpdateObject(BucketName, identifier, edgeJob)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateEdgeJobFunc is a no-op inside a transaction.
|
||||||
|
func (service ServiceTx) UpdateEdgeJobFunc(ID portainer.EdgeJobID, updateFunc func(edgeJob *portainer.EdgeJob)) error {
|
||||||
|
return errors.New("cannot be called inside a transaction")
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteEdgeJob deletes an Edge job
|
||||||
|
func (service ServiceTx) DeleteEdgeJob(ID portainer.EdgeJobID) error {
|
||||||
|
identifier := service.service.connection.ConvertToKey(int(ID))
|
||||||
|
|
||||||
|
return service.tx.DeleteObject(BucketName, identifier)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetNextIdentifier returns the next identifier for an environment(endpoint).
|
||||||
|
func (service ServiceTx) GetNextIdentifier() int {
|
||||||
|
return service.tx.GetNextIdentifier(BucketName)
|
||||||
|
}
|
|
@ -9,10 +9,8 @@ import (
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
|
||||||
// BucketName represents the name of the bucket where this service stores data.
|
// BucketName represents the name of the bucket where this service stores data.
|
||||||
BucketName = "edge_stack"
|
const BucketName = "edge_stack"
|
||||||
)
|
|
||||||
|
|
||||||
// Service represents a service for managing Edge stack data.
|
// Service represents a service for managing Edge stack data.
|
||||||
type Service struct {
|
type Service struct {
|
||||||
|
@ -55,6 +53,13 @@ func NewService(connection portainer.Connection, cacheInvalidationFn func(portai
|
||||||
return s, nil
|
return s, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (service *Service) Tx(tx portainer.Transaction) ServiceTx {
|
||||||
|
return ServiceTx{
|
||||||
|
service: service,
|
||||||
|
tx: tx,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// EdgeStacks returns an array containing all edge stacks
|
// EdgeStacks returns an array containing all edge stacks
|
||||||
func (service *Service) EdgeStacks() ([]portainer.EdgeStack, error) {
|
func (service *Service) EdgeStacks() ([]portainer.EdgeStack, error) {
|
||||||
var stacks = make([]portainer.EdgeStack, 0)
|
var stacks = make([]portainer.EdgeStack, 0)
|
||||||
|
|
|
@ -0,0 +1,131 @@
|
||||||
|
package edgestack
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
portainer "github.com/portainer/portainer/api"
|
||||||
|
|
||||||
|
"github.com/rs/zerolog/log"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ServiceTx struct {
|
||||||
|
service *Service
|
||||||
|
tx portainer.Transaction
|
||||||
|
}
|
||||||
|
|
||||||
|
func (service ServiceTx) BucketName() string {
|
||||||
|
return BucketName
|
||||||
|
}
|
||||||
|
|
||||||
|
// EdgeStacks returns an array containing all edge stacks
|
||||||
|
func (service ServiceTx) EdgeStacks() ([]portainer.EdgeStack, error) {
|
||||||
|
var stacks = make([]portainer.EdgeStack, 0)
|
||||||
|
|
||||||
|
err := service.tx.GetAll(
|
||||||
|
BucketName,
|
||||||
|
&portainer.EdgeStack{},
|
||||||
|
func(obj interface{}) (interface{}, error) {
|
||||||
|
stack, ok := obj.(*portainer.EdgeStack)
|
||||||
|
if !ok {
|
||||||
|
log.Debug().Str("obj", fmt.Sprintf("%#v", obj)).Msg("failed to convert to EdgeStack object")
|
||||||
|
return nil, fmt.Errorf("Failed to convert to EdgeStack object: %s", obj)
|
||||||
|
}
|
||||||
|
|
||||||
|
stacks = append(stacks, *stack)
|
||||||
|
|
||||||
|
return &portainer.EdgeStack{}, nil
|
||||||
|
})
|
||||||
|
|
||||||
|
return stacks, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// EdgeStack returns an Edge stack by ID.
|
||||||
|
func (service ServiceTx) EdgeStack(ID portainer.EdgeStackID) (*portainer.EdgeStack, error) {
|
||||||
|
var stack portainer.EdgeStack
|
||||||
|
identifier := service.service.connection.ConvertToKey(int(ID))
|
||||||
|
|
||||||
|
err := service.tx.GetObject(BucketName, identifier, &stack)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &stack, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// EdgeStackVersion returns the version of the given edge stack ID directly from an in-memory index
|
||||||
|
func (service ServiceTx) EdgeStackVersion(ID portainer.EdgeStackID) (int, bool) {
|
||||||
|
service.service.mu.RLock()
|
||||||
|
v, ok := service.service.idxVersion[ID]
|
||||||
|
service.service.mu.RUnlock()
|
||||||
|
|
||||||
|
return v, ok
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateEdgeStack saves an Edge stack object to db.
|
||||||
|
func (service ServiceTx) Create(id portainer.EdgeStackID, edgeStack *portainer.EdgeStack) error {
|
||||||
|
edgeStack.ID = id
|
||||||
|
|
||||||
|
err := service.tx.CreateObjectWithId(
|
||||||
|
BucketName,
|
||||||
|
int(edgeStack.ID),
|
||||||
|
edgeStack,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
service.service.mu.Lock()
|
||||||
|
service.service.idxVersion[id] = edgeStack.Version
|
||||||
|
service.service.cacheInvalidationFn(id)
|
||||||
|
service.service.mu.Unlock()
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateEdgeStack updates an Edge stack.
|
||||||
|
func (service ServiceTx) UpdateEdgeStack(ID portainer.EdgeStackID, edgeStack *portainer.EdgeStack) error {
|
||||||
|
service.service.mu.Lock()
|
||||||
|
defer service.service.mu.Unlock()
|
||||||
|
|
||||||
|
identifier := service.service.connection.ConvertToKey(int(ID))
|
||||||
|
|
||||||
|
err := service.tx.UpdateObject(BucketName, identifier, edgeStack)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
service.service.idxVersion[ID] = edgeStack.Version
|
||||||
|
service.service.cacheInvalidationFn(ID)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateEdgeStackFunc is a no-op inside a transaction.
|
||||||
|
func (service ServiceTx) UpdateEdgeStackFunc(ID portainer.EdgeStackID, updateFunc func(edgeStack *portainer.EdgeStack)) error {
|
||||||
|
return errors.New("cannot be called inside a transaction")
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteEdgeStack deletes an Edge stack.
|
||||||
|
func (service ServiceTx) DeleteEdgeStack(ID portainer.EdgeStackID) error {
|
||||||
|
service.service.mu.Lock()
|
||||||
|
defer service.service.mu.Unlock()
|
||||||
|
|
||||||
|
identifier := service.service.connection.ConvertToKey(int(ID))
|
||||||
|
|
||||||
|
err := service.tx.DeleteObject(BucketName, identifier)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
delete(service.service.idxVersion, ID)
|
||||||
|
|
||||||
|
service.service.cacheInvalidationFn(ID)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetNextIdentifier returns the next identifier for an environment(endpoint).
|
||||||
|
func (service ServiceTx) GetNextIdentifier() int {
|
||||||
|
return service.tx.GetNextIdentifier(BucketName)
|
||||||
|
}
|
|
@ -34,6 +34,13 @@ func NewService(connection portainer.Connection) (*Service, error) {
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (service *Service) Tx(tx portainer.Transaction) ServiceTx {
|
||||||
|
return ServiceTx{
|
||||||
|
service: service,
|
||||||
|
tx: tx,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// EndpointGroup returns an environment(endpoint) group by ID.
|
// EndpointGroup returns an environment(endpoint) group by ID.
|
||||||
func (service *Service) EndpointGroup(ID portainer.EndpointGroupID) (*portainer.EndpointGroup, error) {
|
func (service *Service) EndpointGroup(ID portainer.EndpointGroupID) (*portainer.EndpointGroup, error) {
|
||||||
var endpointGroup portainer.EndpointGroup
|
var endpointGroup portainer.EndpointGroup
|
||||||
|
|
|
@ -0,0 +1,76 @@
|
||||||
|
package endpointgroup
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
portainer "github.com/portainer/portainer/api"
|
||||||
|
|
||||||
|
"github.com/rs/zerolog/log"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ServiceTx struct {
|
||||||
|
service *Service
|
||||||
|
tx portainer.Transaction
|
||||||
|
}
|
||||||
|
|
||||||
|
func (service ServiceTx) BucketName() string {
|
||||||
|
return BucketName
|
||||||
|
}
|
||||||
|
|
||||||
|
// EndpointGroup returns an environment(endpoint) group by ID.
|
||||||
|
func (service ServiceTx) EndpointGroup(ID portainer.EndpointGroupID) (*portainer.EndpointGroup, error) {
|
||||||
|
var endpointGroup portainer.EndpointGroup
|
||||||
|
identifier := service.service.connection.ConvertToKey(int(ID))
|
||||||
|
|
||||||
|
err := service.tx.GetObject(BucketName, identifier, &endpointGroup)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &endpointGroup, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateEndpointGroup updates an environment(endpoint) group.
|
||||||
|
func (service ServiceTx) UpdateEndpointGroup(ID portainer.EndpointGroupID, endpointGroup *portainer.EndpointGroup) error {
|
||||||
|
identifier := service.service.connection.ConvertToKey(int(ID))
|
||||||
|
return service.tx.UpdateObject(BucketName, identifier, endpointGroup)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteEndpointGroup deletes an environment(endpoint) group.
|
||||||
|
func (service ServiceTx) DeleteEndpointGroup(ID portainer.EndpointGroupID) error {
|
||||||
|
identifier := service.service.connection.ConvertToKey(int(ID))
|
||||||
|
return service.tx.DeleteObject(BucketName, identifier)
|
||||||
|
}
|
||||||
|
|
||||||
|
// EndpointGroups return an array containing all the environment(endpoint) groups.
|
||||||
|
func (service ServiceTx) EndpointGroups() ([]portainer.EndpointGroup, error) {
|
||||||
|
var endpointGroups = make([]portainer.EndpointGroup, 0)
|
||||||
|
|
||||||
|
err := service.tx.GetAll(
|
||||||
|
BucketName,
|
||||||
|
&portainer.EndpointGroup{},
|
||||||
|
func(obj interface{}) (interface{}, error) {
|
||||||
|
endpointGroup, ok := obj.(*portainer.EndpointGroup)
|
||||||
|
if !ok {
|
||||||
|
log.Debug().Str("obj", fmt.Sprintf("%#v", obj)).Msg("failed to convert to EndpointGroup object")
|
||||||
|
return nil, fmt.Errorf("failed to convert to EndpointGroup object: %s", obj)
|
||||||
|
}
|
||||||
|
|
||||||
|
endpointGroups = append(endpointGroups, *endpointGroup)
|
||||||
|
|
||||||
|
return &portainer.EndpointGroup{}, nil
|
||||||
|
})
|
||||||
|
|
||||||
|
return endpointGroups, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateEndpointGroup assign an ID to a new environment(endpoint) group and saves it.
|
||||||
|
func (service ServiceTx) Create(endpointGroup *portainer.EndpointGroup) error {
|
||||||
|
return service.tx.CreateObject(
|
||||||
|
BucketName,
|
||||||
|
func(id uint64) (int, interface{}) {
|
||||||
|
endpointGroup.ID = portainer.EndpointGroupID(id)
|
||||||
|
return int(endpointGroup.ID), endpointGroup
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
|
@ -9,10 +9,8 @@ import (
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
|
||||||
// BucketName represents the name of the bucket where this service stores data.
|
// BucketName represents the name of the bucket where this service stores data.
|
||||||
BucketName = "endpoint_relations"
|
const BucketName = "endpoint_relations"
|
||||||
)
|
|
||||||
|
|
||||||
// Service represents a service for managing environment(endpoint) relation data.
|
// Service represents a service for managing environment(endpoint) relation data.
|
||||||
type Service struct {
|
type Service struct {
|
||||||
|
@ -40,6 +38,13 @@ func NewService(connection portainer.Connection) (*Service, error) {
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (service *Service) Tx(tx portainer.Transaction) ServiceTx {
|
||||||
|
return ServiceTx{
|
||||||
|
service: service,
|
||||||
|
tx: tx,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// EndpointRelations returns an array of all EndpointRelations
|
// EndpointRelations returns an array of all EndpointRelations
|
||||||
func (service *Service) EndpointRelations() ([]portainer.EndpointRelation, error) {
|
func (service *Service) EndpointRelations() ([]portainer.EndpointRelation, error) {
|
||||||
var all = make([]portainer.EndpointRelation, 0)
|
var all = make([]portainer.EndpointRelation, 0)
|
||||||
|
|
|
@ -0,0 +1,159 @@
|
||||||
|
package endpointrelation
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
portainer "github.com/portainer/portainer/api"
|
||||||
|
"github.com/portainer/portainer/api/internal/edge/cache"
|
||||||
|
|
||||||
|
"github.com/rs/zerolog/log"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ServiceTx struct {
|
||||||
|
service *Service
|
||||||
|
tx portainer.Transaction
|
||||||
|
}
|
||||||
|
|
||||||
|
func (service ServiceTx) BucketName() string {
|
||||||
|
return BucketName
|
||||||
|
}
|
||||||
|
|
||||||
|
// EndpointRelations returns an array of all EndpointRelations
|
||||||
|
func (service ServiceTx) EndpointRelations() ([]portainer.EndpointRelation, error) {
|
||||||
|
var all = make([]portainer.EndpointRelation, 0)
|
||||||
|
|
||||||
|
err := service.tx.GetAll(
|
||||||
|
BucketName,
|
||||||
|
&portainer.EndpointRelation{},
|
||||||
|
func(obj interface{}) (interface{}, error) {
|
||||||
|
r, ok := obj.(*portainer.EndpointRelation)
|
||||||
|
if !ok {
|
||||||
|
log.Debug().Str("obj", fmt.Sprintf("%#v", obj)).Msg("failed to convert to EndpointRelation object")
|
||||||
|
return nil, fmt.Errorf("failed to convert to EndpointRelation object: %s", obj)
|
||||||
|
}
|
||||||
|
|
||||||
|
all = append(all, *r)
|
||||||
|
|
||||||
|
return &portainer.EndpointRelation{}, nil
|
||||||
|
})
|
||||||
|
|
||||||
|
return all, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// EndpointRelation returns an Environment(Endpoint) relation object by EndpointID
|
||||||
|
func (service ServiceTx) EndpointRelation(endpointID portainer.EndpointID) (*portainer.EndpointRelation, error) {
|
||||||
|
var endpointRelation portainer.EndpointRelation
|
||||||
|
identifier := service.service.connection.ConvertToKey(int(endpointID))
|
||||||
|
|
||||||
|
err := service.tx.GetObject(BucketName, identifier, &endpointRelation)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &endpointRelation, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateEndpointRelation saves endpointRelation
|
||||||
|
func (service ServiceTx) Create(endpointRelation *portainer.EndpointRelation) error {
|
||||||
|
err := service.tx.CreateObjectWithId(BucketName, int(endpointRelation.EndpointID), endpointRelation)
|
||||||
|
cache.Del(endpointRelation.EndpointID)
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateEndpointRelation updates an Environment(Endpoint) relation object
|
||||||
|
func (service ServiceTx) UpdateEndpointRelation(endpointID portainer.EndpointID, endpointRelation *portainer.EndpointRelation) error {
|
||||||
|
previousRelationState, _ := service.EndpointRelation(endpointID)
|
||||||
|
|
||||||
|
identifier := service.service.connection.ConvertToKey(int(endpointID))
|
||||||
|
err := service.tx.UpdateObject(BucketName, identifier, endpointRelation)
|
||||||
|
cache.Del(endpointID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
updatedRelationState, _ := service.EndpointRelation(endpointID)
|
||||||
|
|
||||||
|
service.updateEdgeStacksAfterRelationChange(previousRelationState, updatedRelationState)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteEndpointRelation deletes an Environment(Endpoint) relation object
|
||||||
|
func (service ServiceTx) DeleteEndpointRelation(endpointID portainer.EndpointID) error {
|
||||||
|
deletedRelation, _ := service.EndpointRelation(endpointID)
|
||||||
|
|
||||||
|
identifier := service.service.connection.ConvertToKey(int(endpointID))
|
||||||
|
err := service.tx.DeleteObject(BucketName, identifier)
|
||||||
|
cache.Del(endpointID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
service.updateEdgeStacksAfterRelationChange(deletedRelation, nil)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (service ServiceTx) InvalidateEdgeCacheForEdgeStack(edgeStackID portainer.EdgeStackID) {
|
||||||
|
rels, err := service.EndpointRelations()
|
||||||
|
if err != nil {
|
||||||
|
log.Error().Err(err).Msg("cannot retrieve endpoint relations")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, rel := range rels {
|
||||||
|
for id := range rel.EdgeStacks {
|
||||||
|
if edgeStackID == id {
|
||||||
|
cache.Del(rel.EndpointID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (service ServiceTx) updateEdgeStacksAfterRelationChange(previousRelationState *portainer.EndpointRelation, updatedRelationState *portainer.EndpointRelation) {
|
||||||
|
relations, _ := service.EndpointRelations()
|
||||||
|
|
||||||
|
stacksToUpdate := map[portainer.EdgeStackID]bool{}
|
||||||
|
|
||||||
|
if previousRelationState != nil {
|
||||||
|
for stackId, enabled := range previousRelationState.EdgeStacks {
|
||||||
|
// flag stack for update if stack is not in the updated relation state
|
||||||
|
// = stack has been removed for this relation
|
||||||
|
// or this relation has been deleted
|
||||||
|
if enabled && (updatedRelationState == nil || !updatedRelationState.EdgeStacks[stackId]) {
|
||||||
|
stacksToUpdate[stackId] = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if updatedRelationState != nil {
|
||||||
|
for stackId, enabled := range updatedRelationState.EdgeStacks {
|
||||||
|
// flag stack for update if stack is not in the previous relation state
|
||||||
|
// = stack has been added for this relation
|
||||||
|
if enabled && (previousRelationState == nil || !previousRelationState.EdgeStacks[stackId]) {
|
||||||
|
stacksToUpdate[stackId] = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// for each stack referenced by the updated relation
|
||||||
|
// list how many time this stack is referenced in all relations
|
||||||
|
// in order to update the stack deployments count
|
||||||
|
for refStackId, refStackEnabled := range stacksToUpdate {
|
||||||
|
if refStackEnabled {
|
||||||
|
numDeployments := 0
|
||||||
|
for _, r := range relations {
|
||||||
|
for sId, enabled := range r.EdgeStacks {
|
||||||
|
if enabled && sId == refStackId {
|
||||||
|
numDeployments += 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
service.service.updateStackFn(refStackId, func(edgeStack *portainer.EdgeStack) {
|
||||||
|
edgeStack.NumDeployments = numDeployments
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -31,6 +31,13 @@ func NewService(connection portainer.Connection) (*Service, error) {
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (service *Service) Tx(tx portainer.Transaction) ServiceTx {
|
||||||
|
return ServiceTx{
|
||||||
|
service: service,
|
||||||
|
tx: tx,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (service *Service) Snapshot(endpointID portainer.EndpointID) (*portainer.Snapshot, error) {
|
func (service *Service) Snapshot(endpointID portainer.EndpointID) (*portainer.Snapshot, error) {
|
||||||
var snapshot portainer.Snapshot
|
var snapshot portainer.Snapshot
|
||||||
identifier := service.connection.ConvertToKey(int(endpointID))
|
identifier := service.connection.ConvertToKey(int(endpointID))
|
||||||
|
|
|
@ -0,0 +1,63 @@
|
||||||
|
package snapshot
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
portainer "github.com/portainer/portainer/api"
|
||||||
|
|
||||||
|
"github.com/rs/zerolog/log"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ServiceTx struct {
|
||||||
|
service *Service
|
||||||
|
tx portainer.Transaction
|
||||||
|
}
|
||||||
|
|
||||||
|
func (service ServiceTx) BucketName() string {
|
||||||
|
return BucketName
|
||||||
|
}
|
||||||
|
|
||||||
|
func (service ServiceTx) Snapshot(endpointID portainer.EndpointID) (*portainer.Snapshot, error) {
|
||||||
|
var snapshot portainer.Snapshot
|
||||||
|
identifier := service.service.connection.ConvertToKey(int(endpointID))
|
||||||
|
|
||||||
|
err := service.tx.GetObject(BucketName, identifier, &snapshot)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &snapshot, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (service ServiceTx) Snapshots() ([]portainer.Snapshot, error) {
|
||||||
|
var snapshots = make([]portainer.Snapshot, 0)
|
||||||
|
|
||||||
|
err := service.tx.GetAllWithJsoniter(
|
||||||
|
BucketName,
|
||||||
|
&portainer.Snapshot{},
|
||||||
|
func(obj interface{}) (interface{}, error) {
|
||||||
|
snapshot, ok := obj.(*portainer.Snapshot)
|
||||||
|
if !ok {
|
||||||
|
log.Debug().Str("obj", fmt.Sprintf("%#v", obj)).Msg("failed to convert to Snapshot object")
|
||||||
|
return nil, fmt.Errorf("failed to convert to Snapshot object: %s", obj)
|
||||||
|
}
|
||||||
|
snapshots = append(snapshots, *snapshot)
|
||||||
|
return &portainer.Snapshot{}, nil
|
||||||
|
})
|
||||||
|
|
||||||
|
return snapshots, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (service ServiceTx) UpdateSnapshot(snapshot *portainer.Snapshot) error {
|
||||||
|
identifier := service.service.connection.ConvertToKey(int(snapshot.EndpointID))
|
||||||
|
return service.tx.UpdateObject(BucketName, identifier, snapshot)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (service ServiceTx) DeleteSnapshot(endpointID portainer.EndpointID) error {
|
||||||
|
identifier := service.service.connection.ConvertToKey(int(endpointID))
|
||||||
|
return service.tx.DeleteObject(BucketName, identifier)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (service ServiceTx) Create(snapshot *portainer.Snapshot) error {
|
||||||
|
return service.tx.CreateObjectWithId(BucketName, int(snapshot.EndpointID), snapshot)
|
||||||
|
}
|
|
@ -34,6 +34,13 @@ func NewService(connection portainer.Connection) (*Service, error) {
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (service *Service) Tx(tx portainer.Transaction) ServiceTx {
|
||||||
|
return ServiceTx{
|
||||||
|
service: service,
|
||||||
|
tx: tx,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Tags return an array containing all the tags.
|
// Tags return an array containing all the tags.
|
||||||
func (service *Service) Tags() ([]portainer.Tag, error) {
|
func (service *Service) Tags() ([]portainer.Tag, error) {
|
||||||
var tags = make([]portainer.Tag, 0)
|
var tags = make([]portainer.Tag, 0)
|
||||||
|
|
|
@ -0,0 +1,82 @@
|
||||||
|
package tag
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
portainer "github.com/portainer/portainer/api"
|
||||||
|
|
||||||
|
"github.com/rs/zerolog/log"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ServiceTx struct {
|
||||||
|
service *Service
|
||||||
|
tx portainer.Transaction
|
||||||
|
}
|
||||||
|
|
||||||
|
func (service ServiceTx) BucketName() string {
|
||||||
|
return BucketName
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tags return an array containing all the tags.
|
||||||
|
func (service ServiceTx) Tags() ([]portainer.Tag, error) {
|
||||||
|
var tags = make([]portainer.Tag, 0)
|
||||||
|
|
||||||
|
err := service.tx.GetAll(
|
||||||
|
BucketName,
|
||||||
|
&portainer.Tag{},
|
||||||
|
func(obj interface{}) (interface{}, error) {
|
||||||
|
tag, ok := obj.(*portainer.Tag)
|
||||||
|
if !ok {
|
||||||
|
log.Debug().Str("obj", fmt.Sprintf("%#v", obj)).Msg("failed to convert to Tag object")
|
||||||
|
return nil, fmt.Errorf("failed to convert to Tag object: %s", obj)
|
||||||
|
}
|
||||||
|
|
||||||
|
tags = append(tags, *tag)
|
||||||
|
|
||||||
|
return &portainer.Tag{}, nil
|
||||||
|
})
|
||||||
|
|
||||||
|
return tags, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tag returns a tag by ID.
|
||||||
|
func (service ServiceTx) Tag(ID portainer.TagID) (*portainer.Tag, error) {
|
||||||
|
var tag portainer.Tag
|
||||||
|
identifier := service.service.connection.ConvertToKey(int(ID))
|
||||||
|
|
||||||
|
err := service.tx.GetObject(BucketName, identifier, &tag)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &tag, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateTag creates a new tag.
|
||||||
|
func (service ServiceTx) Create(tag *portainer.Tag) error {
|
||||||
|
return service.tx.CreateObject(
|
||||||
|
BucketName,
|
||||||
|
func(id uint64) (int, interface{}) {
|
||||||
|
tag.ID = portainer.TagID(id)
|
||||||
|
return int(tag.ID), tag
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateTag updates a tag
|
||||||
|
func (service ServiceTx) UpdateTag(ID portainer.TagID, tag *portainer.Tag) error {
|
||||||
|
identifier := service.service.connection.ConvertToKey(int(ID))
|
||||||
|
return service.tx.UpdateObject(BucketName, identifier, tag)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateTagFunc is a no-op inside a transaction
|
||||||
|
func (service ServiceTx) UpdateTagFunc(ID portainer.TagID, updateFunc func(tag *portainer.Tag)) error {
|
||||||
|
return errors.New("cannot be called inside a transaction")
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteTag deletes a tag.
|
||||||
|
func (service ServiceTx) DeleteTag(ID portainer.TagID) error {
|
||||||
|
identifier := service.service.connection.ConvertToKey(int(ID))
|
||||||
|
return service.tx.DeleteObject(BucketName, identifier)
|
||||||
|
}
|
|
@ -20,15 +20,26 @@ func (tx *StoreTx) EdgeGroup() dataservices.EdgeGroupService {
|
||||||
return tx.store.EdgeGroupService.Tx(tx.tx)
|
return tx.store.EdgeGroupService.Tx(tx.tx)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tx *StoreTx) EdgeJob() dataservices.EdgeJobService { return nil }
|
func (tx *StoreTx) EdgeJob() dataservices.EdgeJobService {
|
||||||
func (tx *StoreTx) EdgeStack() dataservices.EdgeStackService { return nil }
|
return tx.store.EdgeJobService.Tx(tx.tx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tx *StoreTx) EdgeStack() dataservices.EdgeStackService {
|
||||||
|
return tx.store.EdgeStackService.Tx(tx.tx)
|
||||||
|
}
|
||||||
|
|
||||||
func (tx *StoreTx) Endpoint() dataservices.EndpointService {
|
func (tx *StoreTx) Endpoint() dataservices.EndpointService {
|
||||||
return tx.store.EndpointService.Tx(tx.tx)
|
return tx.store.EndpointService.Tx(tx.tx)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tx *StoreTx) EndpointGroup() dataservices.EndpointGroupService { return nil }
|
func (tx *StoreTx) EndpointGroup() dataservices.EndpointGroupService {
|
||||||
func (tx *StoreTx) EndpointRelation() dataservices.EndpointRelationService { return nil }
|
return tx.store.EndpointGroupService.Tx(tx.tx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tx *StoreTx) EndpointRelation() dataservices.EndpointRelationService {
|
||||||
|
return tx.store.EndpointRelationService.Tx(tx.tx)
|
||||||
|
}
|
||||||
|
|
||||||
func (tx *StoreTx) FDOProfile() dataservices.FDOProfileService { return nil }
|
func (tx *StoreTx) FDOProfile() dataservices.FDOProfileService { return nil }
|
||||||
func (tx *StoreTx) HelmUserRepository() dataservices.HelmUserRepositoryService { return nil }
|
func (tx *StoreTx) HelmUserRepository() dataservices.HelmUserRepositoryService { return nil }
|
||||||
func (tx *StoreTx) Registry() dataservices.RegistryService { return nil }
|
func (tx *StoreTx) Registry() dataservices.RegistryService { return nil }
|
||||||
|
@ -36,10 +47,18 @@ func (tx *StoreTx) ResourceControl() dataservices.ResourceControlService {
|
||||||
func (tx *StoreTx) Role() dataservices.RoleService { return nil }
|
func (tx *StoreTx) Role() dataservices.RoleService { return nil }
|
||||||
func (tx *StoreTx) APIKeyRepository() dataservices.APIKeyRepository { return nil }
|
func (tx *StoreTx) APIKeyRepository() dataservices.APIKeyRepository { return nil }
|
||||||
func (tx *StoreTx) Settings() dataservices.SettingsService { return nil }
|
func (tx *StoreTx) Settings() dataservices.SettingsService { return nil }
|
||||||
func (tx *StoreTx) Snapshot() dataservices.SnapshotService { return nil }
|
|
||||||
|
func (tx *StoreTx) Snapshot() dataservices.SnapshotService {
|
||||||
|
return tx.store.SnapshotService.Tx(tx.tx)
|
||||||
|
}
|
||||||
|
|
||||||
func (tx *StoreTx) SSLSettings() dataservices.SSLSettingsService { return nil }
|
func (tx *StoreTx) SSLSettings() dataservices.SSLSettingsService { return nil }
|
||||||
func (tx *StoreTx) Stack() dataservices.StackService { return nil }
|
func (tx *StoreTx) Stack() dataservices.StackService { return nil }
|
||||||
func (tx *StoreTx) Tag() dataservices.TagService { return nil }
|
|
||||||
|
func (tx *StoreTx) Tag() dataservices.TagService {
|
||||||
|
return tx.store.TagService.Tx(tx.tx)
|
||||||
|
}
|
||||||
|
|
||||||
func (tx *StoreTx) TeamMembership() dataservices.TeamMembershipService { return nil }
|
func (tx *StoreTx) TeamMembership() dataservices.TeamMembershipService { return nil }
|
||||||
func (tx *StoreTx) Team() dataservices.TeamService { return nil }
|
func (tx *StoreTx) Team() dataservices.TeamService { return nil }
|
||||||
func (tx *StoreTx) TunnelServer() dataservices.TunnelServerService { return nil }
|
func (tx *StoreTx) TunnelServer() dataservices.TunnelServerService { return nil }
|
||||||
|
|
Loading…
Reference in New Issue