package endpoint 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 } // Endpoint returns an environment(endpoint) by ID. func (service ServiceTx) Endpoint(ID portainer.EndpointID) (*portainer.Endpoint, error) { var endpoint portainer.Endpoint identifier := service.service.connection.ConvertToKey(int(ID)) err := service.tx.GetObject(BucketName, identifier, &endpoint) if err != nil { return nil, err } return &endpoint, nil } // UpdateEndpoint updates an environment(endpoint). func (service ServiceTx) UpdateEndpoint(ID portainer.EndpointID, endpoint *portainer.Endpoint) error { identifier := service.service.connection.ConvertToKey(int(ID)) err := service.tx.UpdateObject(BucketName, identifier, endpoint) if err != nil { return err } service.service.mu.Lock() if len(endpoint.EdgeID) > 0 { service.service.idxEdgeID[endpoint.EdgeID] = ID } service.service.heartbeats.Store(ID, endpoint.LastCheckInDate) service.service.mu.Unlock() cache.Del(endpoint.ID) return nil } // DeleteEndpoint deletes an environment(endpoint). func (service ServiceTx) DeleteEndpoint(ID portainer.EndpointID) error { identifier := service.service.connection.ConvertToKey(int(ID)) err := service.tx.DeleteObject(BucketName, identifier) if err != nil { return err } service.service.mu.Lock() for edgeID, endpointID := range service.service.idxEdgeID { if endpointID == ID { delete(service.service.idxEdgeID, edgeID) break } } service.service.heartbeats.Delete(ID) service.service.mu.Unlock() cache.Del(ID) return nil } // Endpoints return an array containing all the environments(endpoints). func (service ServiceTx) Endpoints() ([]portainer.Endpoint, error) { var endpoints = make([]portainer.Endpoint, 0) err := service.tx.GetAllWithJsoniter( BucketName, &portainer.Endpoint{}, func(obj interface{}) (interface{}, error) { endpoint, ok := obj.(*portainer.Endpoint) if !ok { log.Debug().Str("obj", fmt.Sprintf("%#v", obj)).Msg("failed to convert to Endpoint object") return nil, fmt.Errorf("failed to convert to Endpoint object: %s", obj) } endpoints = append(endpoints, *endpoint) return &portainer.Endpoint{}, nil }) return endpoints, err } func (service ServiceTx) EndpointIDByEdgeID(edgeID string) (portainer.EndpointID, bool) { log.Error().Str("func", "EndpointIDByEdgeID").Msg("cannot be called inside a transaction") return 0, false } func (service ServiceTx) Heartbeat(endpointID portainer.EndpointID) (int64, bool) { log.Error().Str("func", "Heartbeat").Msg("cannot be called inside a transaction") return 0, false } func (service ServiceTx) UpdateHeartbeat(endpointID portainer.EndpointID) { log.Error().Str("func", "UpdateHeartbeat").Msg("cannot be called inside a transaction") } // CreateEndpoint assign an ID to a new environment(endpoint) and saves it. func (service ServiceTx) Create(endpoint *portainer.Endpoint) error { err := service.tx.CreateObjectWithId(BucketName, int(endpoint.ID), endpoint) if err != nil { return err } service.service.mu.Lock() if len(endpoint.EdgeID) > 0 { service.service.idxEdgeID[endpoint.EdgeID] = endpoint.ID } service.service.heartbeats.Store(endpoint.ID, endpoint.LastCheckInDate) service.service.mu.Unlock() return nil } // GetNextIdentifier returns the next identifier for an environment(endpoint). func (service ServiceTx) GetNextIdentifier() int { return service.tx.GetNextIdentifier(BucketName) }