mirror of
https://github.com/portainer/portainer.git
synced 2025-08-02 20:35:25 +02:00
feat(global): introduce user teams and new UAC system (#868)
This commit is contained in:
parent
a380fd9adc
commit
5523fc9023
160 changed files with 7112 additions and 3166 deletions
|
@ -17,6 +17,8 @@ type Store struct {
|
|||
|
||||
// Services
|
||||
UserService *UserService
|
||||
TeamService *TeamService
|
||||
TeamMembershipService *TeamMembershipService
|
||||
EndpointService *EndpointService
|
||||
ResourceControlService *ResourceControlService
|
||||
VersionService *VersionService
|
||||
|
@ -26,13 +28,13 @@ type Store struct {
|
|||
}
|
||||
|
||||
const (
|
||||
databaseFileName = "portainer.db"
|
||||
versionBucketName = "version"
|
||||
userBucketName = "users"
|
||||
endpointBucketName = "endpoints"
|
||||
containerResourceControlBucketName = "containerResourceControl"
|
||||
serviceResourceControlBucketName = "serviceResourceControl"
|
||||
volumeResourceControlBucketName = "volumeResourceControl"
|
||||
databaseFileName = "portainer.db"
|
||||
versionBucketName = "version"
|
||||
userBucketName = "users"
|
||||
teamBucketName = "teams"
|
||||
teamMembershipBucketName = "team_membership"
|
||||
endpointBucketName = "endpoints"
|
||||
resourceControlBucketName = "resource_control"
|
||||
)
|
||||
|
||||
// NewStore initializes a new Store and the associated services
|
||||
|
@ -40,11 +42,15 @@ func NewStore(storePath string) (*Store, error) {
|
|||
store := &Store{
|
||||
Path: storePath,
|
||||
UserService: &UserService{},
|
||||
TeamService: &TeamService{},
|
||||
TeamMembershipService: &TeamMembershipService{},
|
||||
EndpointService: &EndpointService{},
|
||||
ResourceControlService: &ResourceControlService{},
|
||||
VersionService: &VersionService{},
|
||||
}
|
||||
store.UserService.store = store
|
||||
store.TeamService.store = store
|
||||
store.TeamMembershipService.store = store
|
||||
store.EndpointService.store = store
|
||||
store.ResourceControlService.store = store
|
||||
store.VersionService.store = store
|
||||
|
@ -78,19 +84,19 @@ func (store *Store) Open() error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = tx.CreateBucketIfNotExists([]byte(teamBucketName))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = tx.CreateBucketIfNotExists([]byte(endpointBucketName))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = tx.CreateBucketIfNotExists([]byte(containerResourceControlBucketName))
|
||||
_, err = tx.CreateBucketIfNotExists([]byte(resourceControlBucketName))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = tx.CreateBucketIfNotExists([]byte(serviceResourceControlBucketName))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = tx.CreateBucketIfNotExists([]byte(volumeResourceControlBucketName))
|
||||
_, err = tx.CreateBucketIfNotExists([]byte(teamMembershipBucketName))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -17,6 +17,26 @@ func UnmarshalUser(data []byte, user *portainer.User) error {
|
|||
return json.Unmarshal(data, user)
|
||||
}
|
||||
|
||||
// MarshalTeam encodes a team to binary format.
|
||||
func MarshalTeam(team *portainer.Team) ([]byte, error) {
|
||||
return json.Marshal(team)
|
||||
}
|
||||
|
||||
// UnmarshalTeam decodes a team from a binary data.
|
||||
func UnmarshalTeam(data []byte, team *portainer.Team) error {
|
||||
return json.Unmarshal(data, team)
|
||||
}
|
||||
|
||||
// MarshalTeamMembership encodes a team membership to binary format.
|
||||
func MarshalTeamMembership(membership *portainer.TeamMembership) ([]byte, error) {
|
||||
return json.Marshal(membership)
|
||||
}
|
||||
|
||||
// UnmarshalTeamMembership decodes a team membership from a binary data.
|
||||
func UnmarshalTeamMembership(data []byte, membership *portainer.TeamMembership) error {
|
||||
return json.Unmarshal(data, membership)
|
||||
}
|
||||
|
||||
// MarshalEndpoint encodes an endpoint to binary format.
|
||||
func MarshalEndpoint(endpoint *portainer.Endpoint) ([]byte, error) {
|
||||
return json.Marshal(endpoint)
|
||||
|
|
39
api/bolt/migrate_dbversion0.go
Normal file
39
api/bolt/migrate_dbversion0.go
Normal file
|
@ -0,0 +1,39 @@
|
|||
package bolt
|
||||
|
||||
import (
|
||||
"github.com/boltdb/bolt"
|
||||
"github.com/portainer/portainer"
|
||||
)
|
||||
|
||||
func (m *Migrator) updateAdminUserToDBVersion1() error {
|
||||
u, err := m.UserService.UserByUsername("admin")
|
||||
if err == nil {
|
||||
admin := &portainer.User{
|
||||
Username: "admin",
|
||||
Password: u.Password,
|
||||
Role: portainer.AdministratorRole,
|
||||
}
|
||||
err = m.UserService.CreateUser(admin)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = m.removeLegacyAdminUser()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else if err != nil && err != portainer.ErrUserNotFound {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Migrator) removeLegacyAdminUser() error {
|
||||
return m.store.db.Update(func(tx *bolt.Tx) error {
|
||||
bucket := tx.Bucket([]byte(userBucketName))
|
||||
err := bucket.Delete([]byte("admin"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
103
api/bolt/migrate_dbversion1.go
Normal file
103
api/bolt/migrate_dbversion1.go
Normal file
|
@ -0,0 +1,103 @@
|
|||
package bolt
|
||||
|
||||
import (
|
||||
"github.com/boltdb/bolt"
|
||||
"github.com/portainer/portainer"
|
||||
"github.com/portainer/portainer/bolt/internal"
|
||||
)
|
||||
|
||||
func (m *Migrator) updateResourceControlsToDBVersion2() error {
|
||||
legacyResourceControls, err := m.retrieveLegacyResourceControls()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, resourceControl := range legacyResourceControls {
|
||||
resourceControl.SubResourceIDs = []string{}
|
||||
resourceControl.TeamAccesses = []portainer.TeamResourceAccess{}
|
||||
|
||||
owner, err := m.UserService.User(resourceControl.OwnerID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if owner.Role == portainer.AdministratorRole {
|
||||
resourceControl.AdministratorsOnly = true
|
||||
resourceControl.UserAccesses = []portainer.UserResourceAccess{}
|
||||
} else {
|
||||
resourceControl.AdministratorsOnly = false
|
||||
userAccess := portainer.UserResourceAccess{
|
||||
UserID: resourceControl.OwnerID,
|
||||
AccessLevel: portainer.ReadWriteAccessLevel,
|
||||
}
|
||||
resourceControl.UserAccesses = []portainer.UserResourceAccess{userAccess}
|
||||
}
|
||||
|
||||
err = m.ResourceControlService.CreateResourceControl(&resourceControl)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Migrator) updateEndpointsToDBVersion2() error {
|
||||
legacyEndpoints, err := m.EndpointService.Endpoints()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, endpoint := range legacyEndpoints {
|
||||
endpoint.AuthorizedTeams = []portainer.TeamID{}
|
||||
err = m.EndpointService.UpdateEndpoint(endpoint.ID, &endpoint)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Migrator) retrieveLegacyResourceControls() ([]portainer.ResourceControl, error) {
|
||||
legacyResourceControls := make([]portainer.ResourceControl, 0)
|
||||
err := m.store.db.View(func(tx *bolt.Tx) error {
|
||||
bucket := tx.Bucket([]byte("containerResourceControl"))
|
||||
cursor := bucket.Cursor()
|
||||
for k, v := cursor.First(); k != nil; k, v = cursor.Next() {
|
||||
var resourceControl portainer.ResourceControl
|
||||
err := internal.UnmarshalResourceControl(v, &resourceControl)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
resourceControl.Type = portainer.ContainerResourceControl
|
||||
legacyResourceControls = append(legacyResourceControls, resourceControl)
|
||||
}
|
||||
|
||||
bucket = tx.Bucket([]byte("serviceResourceControl"))
|
||||
cursor = bucket.Cursor()
|
||||
for k, v := cursor.First(); k != nil; k, v = cursor.Next() {
|
||||
var resourceControl portainer.ResourceControl
|
||||
err := internal.UnmarshalResourceControl(v, &resourceControl)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
resourceControl.Type = portainer.ServiceResourceControl
|
||||
legacyResourceControls = append(legacyResourceControls, resourceControl)
|
||||
}
|
||||
|
||||
bucket = tx.Bucket([]byte("volumeResourceControl"))
|
||||
cursor = bucket.Cursor()
|
||||
for k, v := cursor.First(); k != nil; k, v = cursor.Next() {
|
||||
var resourceControl portainer.ResourceControl
|
||||
err := internal.UnmarshalResourceControl(v, &resourceControl)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
resourceControl.Type = portainer.VolumeResourceControl
|
||||
legacyResourceControls = append(legacyResourceControls, resourceControl)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
return legacyResourceControls, err
|
||||
}
|
|
@ -1,10 +1,8 @@
|
|||
package bolt
|
||||
|
||||
import (
|
||||
"github.com/boltdb/bolt"
|
||||
"github.com/portainer/portainer"
|
||||
)
|
||||
import "github.com/portainer/portainer"
|
||||
|
||||
// Migrator defines a service to migrate data after a Portainer version update.
|
||||
type Migrator struct {
|
||||
UserService *UserService
|
||||
EndpointService *EndpointService
|
||||
|
@ -14,6 +12,7 @@ type Migrator struct {
|
|||
store *Store
|
||||
}
|
||||
|
||||
// NewMigrator creates a new Migrator.
|
||||
func NewMigrator(store *Store, version int) *Migrator {
|
||||
return &Migrator{
|
||||
UserService: store.UserService,
|
||||
|
@ -25,11 +24,24 @@ func NewMigrator(store *Store, version int) *Migrator {
|
|||
}
|
||||
}
|
||||
|
||||
// Migrate checks the database version and migrate the existing data to the most recent data model.
|
||||
func (m *Migrator) Migrate() error {
|
||||
|
||||
// Portainer < 1.12
|
||||
if m.CurrentDBVersion == 0 {
|
||||
err := m.updateAdminUser()
|
||||
err := m.updateAdminUserToDBVersion1()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Portainer 1.12.x
|
||||
if m.CurrentDBVersion == 1 {
|
||||
err := m.updateResourceControlsToDBVersion2()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = m.updateEndpointsToDBVersion2()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -41,36 +53,3 @@ func (m *Migrator) Migrate() error {
|
|||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Migrator) updateAdminUser() error {
|
||||
u, err := m.UserService.UserByUsername("admin")
|
||||
if err == nil {
|
||||
admin := &portainer.User{
|
||||
Username: "admin",
|
||||
Password: u.Password,
|
||||
Role: portainer.AdministratorRole,
|
||||
}
|
||||
err = m.UserService.CreateUser(admin)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = m.removeLegacyAdminUser()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else if err != nil && err != portainer.ErrUserNotFound {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Migrator) removeLegacyAdminUser() error {
|
||||
return m.store.db.Update(func(tx *bolt.Tx) error {
|
||||
bucket := tx.Bucket([]byte(userBucketName))
|
||||
err := bucket.Delete([]byte("admin"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
148
api/bolt/resource_control_service.go
Normal file
148
api/bolt/resource_control_service.go
Normal file
|
@ -0,0 +1,148 @@
|
|||
package bolt
|
||||
|
||||
import (
|
||||
"github.com/portainer/portainer"
|
||||
"github.com/portainer/portainer/bolt/internal"
|
||||
|
||||
"github.com/boltdb/bolt"
|
||||
)
|
||||
|
||||
// ResourceControlService represents a service for managing resource controls.
|
||||
type ResourceControlService struct {
|
||||
store *Store
|
||||
}
|
||||
|
||||
// ResourceControl returns a ResourceControl object by ID
|
||||
func (service *ResourceControlService) ResourceControl(ID portainer.ResourceControlID) (*portainer.ResourceControl, error) {
|
||||
var data []byte
|
||||
err := service.store.db.View(func(tx *bolt.Tx) error {
|
||||
bucket := tx.Bucket([]byte(resourceControlBucketName))
|
||||
value := bucket.Get(internal.Itob(int(ID)))
|
||||
if value == nil {
|
||||
return portainer.ErrResourceControlNotFound
|
||||
}
|
||||
|
||||
data = make([]byte, len(value))
|
||||
copy(data, value)
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var resourceControl portainer.ResourceControl
|
||||
err = internal.UnmarshalResourceControl(data, &resourceControl)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &resourceControl, nil
|
||||
}
|
||||
|
||||
// ResourceControlByResourceID returns a ResourceControl object by checking if the resourceID is equal
|
||||
// to the main ResourceID or in SubResourceIDs
|
||||
func (service *ResourceControlService) ResourceControlByResourceID(resourceID string) (*portainer.ResourceControl, error) {
|
||||
var resourceControl *portainer.ResourceControl
|
||||
|
||||
err := service.store.db.View(func(tx *bolt.Tx) error {
|
||||
bucket := tx.Bucket([]byte(resourceControlBucketName))
|
||||
cursor := bucket.Cursor()
|
||||
for k, v := cursor.First(); k != nil; k, v = cursor.Next() {
|
||||
var rc portainer.ResourceControl
|
||||
err := internal.UnmarshalResourceControl(v, &rc)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if rc.ResourceID == resourceID {
|
||||
resourceControl = &rc
|
||||
}
|
||||
for _, subResourceID := range rc.SubResourceIDs {
|
||||
if subResourceID == resourceID {
|
||||
resourceControl = &rc
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if resourceControl == nil {
|
||||
return portainer.ErrResourceControlNotFound
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return resourceControl, nil
|
||||
}
|
||||
|
||||
// ResourceControls returns all the ResourceControl objects
|
||||
func (service *ResourceControlService) ResourceControls() ([]portainer.ResourceControl, error) {
|
||||
var rcs = make([]portainer.ResourceControl, 0)
|
||||
err := service.store.db.View(func(tx *bolt.Tx) error {
|
||||
bucket := tx.Bucket([]byte(resourceControlBucketName))
|
||||
|
||||
cursor := bucket.Cursor()
|
||||
for k, v := cursor.First(); k != nil; k, v = cursor.Next() {
|
||||
var resourceControl portainer.ResourceControl
|
||||
err := internal.UnmarshalResourceControl(v, &resourceControl)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
rcs = append(rcs, resourceControl)
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return rcs, nil
|
||||
}
|
||||
|
||||
// CreateResourceControl creates a new ResourceControl object
|
||||
func (service *ResourceControlService) CreateResourceControl(resourceControl *portainer.ResourceControl) error {
|
||||
return service.store.db.Update(func(tx *bolt.Tx) error {
|
||||
bucket := tx.Bucket([]byte(resourceControlBucketName))
|
||||
id, _ := bucket.NextSequence()
|
||||
resourceControl.ID = portainer.ResourceControlID(id)
|
||||
data, err := internal.MarshalResourceControl(resourceControl)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = bucket.Put(internal.Itob(int(resourceControl.ID)), data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// UpdateResourceControl saves a ResourceControl object.
|
||||
func (service *ResourceControlService) UpdateResourceControl(ID portainer.ResourceControlID, resourceControl *portainer.ResourceControl) error {
|
||||
data, err := internal.MarshalResourceControl(resourceControl)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return service.store.db.Update(func(tx *bolt.Tx) error {
|
||||
bucket := tx.Bucket([]byte(resourceControlBucketName))
|
||||
err = bucket.Put(internal.Itob(int(ID)), data)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// DeleteResourceControl deletes a ResourceControl object by ID
|
||||
func (service *ResourceControlService) DeleteResourceControl(ID portainer.ResourceControlID) error {
|
||||
return service.store.db.Update(func(tx *bolt.Tx) error {
|
||||
bucket := tx.Bucket([]byte(resourceControlBucketName))
|
||||
err := bucket.Delete(internal.Itob(int(ID)))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
|
@ -1,110 +0,0 @@
|
|||
package bolt
|
||||
|
||||
import (
|
||||
"github.com/portainer/portainer"
|
||||
"github.com/portainer/portainer/bolt/internal"
|
||||
|
||||
"github.com/boltdb/bolt"
|
||||
)
|
||||
|
||||
// ResourceControlService represents a service for managing resource controls.
|
||||
type ResourceControlService struct {
|
||||
store *Store
|
||||
}
|
||||
|
||||
func getBucketNameByResourceControlType(rcType portainer.ResourceControlType) string {
|
||||
bucketName := containerResourceControlBucketName
|
||||
if rcType == portainer.ServiceResourceControl {
|
||||
bucketName = serviceResourceControlBucketName
|
||||
} else if rcType == portainer.VolumeResourceControl {
|
||||
bucketName = volumeResourceControlBucketName
|
||||
}
|
||||
return bucketName
|
||||
}
|
||||
|
||||
// ResourceControl returns a resource control object by resource ID
|
||||
func (service *ResourceControlService) ResourceControl(resourceID string, rcType portainer.ResourceControlType) (*portainer.ResourceControl, error) {
|
||||
var data []byte
|
||||
bucketName := getBucketNameByResourceControlType(rcType)
|
||||
err := service.store.db.View(func(tx *bolt.Tx) error {
|
||||
bucket := tx.Bucket([]byte(bucketName))
|
||||
value := bucket.Get([]byte(resourceID))
|
||||
if value == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
data = make([]byte, len(value))
|
||||
copy(data, value)
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if data == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
var rc portainer.ResourceControl
|
||||
err = internal.UnmarshalResourceControl(data, &rc)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &rc, nil
|
||||
}
|
||||
|
||||
// ResourceControls returns all resource control objects
|
||||
func (service *ResourceControlService) ResourceControls(rcType portainer.ResourceControlType) ([]portainer.ResourceControl, error) {
|
||||
var rcs = make([]portainer.ResourceControl, 0)
|
||||
bucketName := getBucketNameByResourceControlType(rcType)
|
||||
err := service.store.db.View(func(tx *bolt.Tx) error {
|
||||
bucket := tx.Bucket([]byte(bucketName))
|
||||
|
||||
cursor := bucket.Cursor()
|
||||
for k, v := cursor.First(); k != nil; k, v = cursor.Next() {
|
||||
var rc portainer.ResourceControl
|
||||
err := internal.UnmarshalResourceControl(v, &rc)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
rcs = append(rcs, rc)
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return rcs, nil
|
||||
}
|
||||
|
||||
// CreateResourceControl creates a new resource control
|
||||
func (service *ResourceControlService) CreateResourceControl(resourceID string, rc *portainer.ResourceControl, rcType portainer.ResourceControlType) error {
|
||||
bucketName := getBucketNameByResourceControlType(rcType)
|
||||
return service.store.db.Update(func(tx *bolt.Tx) error {
|
||||
bucket := tx.Bucket([]byte(bucketName))
|
||||
data, err := internal.MarshalResourceControl(rc)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = bucket.Put([]byte(resourceID), data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// DeleteResourceControl deletes a resource control object by resource ID
|
||||
func (service *ResourceControlService) DeleteResourceControl(resourceID string, rcType portainer.ResourceControlType) error {
|
||||
bucketName := getBucketNameByResourceControlType(rcType)
|
||||
return service.store.db.Update(func(tx *bolt.Tx) error {
|
||||
bucket := tx.Bucket([]byte(bucketName))
|
||||
err := bucket.Delete([]byte(resourceID))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
217
api/bolt/team_membership_service.go
Normal file
217
api/bolt/team_membership_service.go
Normal file
|
@ -0,0 +1,217 @@
|
|||
package bolt
|
||||
|
||||
import (
|
||||
"github.com/portainer/portainer"
|
||||
"github.com/portainer/portainer/bolt/internal"
|
||||
|
||||
"github.com/boltdb/bolt"
|
||||
)
|
||||
|
||||
// TeamMembershipService represents a service for managing TeamMembership objects.
|
||||
type TeamMembershipService struct {
|
||||
store *Store
|
||||
}
|
||||
|
||||
// TeamMembership returns a TeamMembership object by ID
|
||||
func (service *TeamMembershipService) TeamMembership(ID portainer.TeamMembershipID) (*portainer.TeamMembership, error) {
|
||||
var data []byte
|
||||
err := service.store.db.View(func(tx *bolt.Tx) error {
|
||||
bucket := tx.Bucket([]byte(teamMembershipBucketName))
|
||||
value := bucket.Get(internal.Itob(int(ID)))
|
||||
if value == nil {
|
||||
return portainer.ErrTeamMembershipNotFound
|
||||
}
|
||||
|
||||
data = make([]byte, len(value))
|
||||
copy(data, value)
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var membership portainer.TeamMembership
|
||||
err = internal.UnmarshalTeamMembership(data, &membership)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &membership, nil
|
||||
}
|
||||
|
||||
// TeamMemberships return an array containing all the TeamMembership objects.
|
||||
func (service *TeamMembershipService) TeamMemberships() ([]portainer.TeamMembership, error) {
|
||||
var memberships = make([]portainer.TeamMembership, 0)
|
||||
err := service.store.db.View(func(tx *bolt.Tx) error {
|
||||
bucket := tx.Bucket([]byte(teamMembershipBucketName))
|
||||
|
||||
cursor := bucket.Cursor()
|
||||
for k, v := cursor.First(); k != nil; k, v = cursor.Next() {
|
||||
var membership portainer.TeamMembership
|
||||
err := internal.UnmarshalTeamMembership(v, &membership)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
memberships = append(memberships, membership)
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return memberships, nil
|
||||
}
|
||||
|
||||
// TeamMembershipsByUserID return an array containing all the TeamMembership objects where the specified userID is present.
|
||||
func (service *TeamMembershipService) TeamMembershipsByUserID(userID portainer.UserID) ([]portainer.TeamMembership, error) {
|
||||
var memberships = make([]portainer.TeamMembership, 0)
|
||||
err := service.store.db.View(func(tx *bolt.Tx) error {
|
||||
bucket := tx.Bucket([]byte(teamMembershipBucketName))
|
||||
|
||||
cursor := bucket.Cursor()
|
||||
for k, v := cursor.First(); k != nil; k, v = cursor.Next() {
|
||||
var membership portainer.TeamMembership
|
||||
err := internal.UnmarshalTeamMembership(v, &membership)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if membership.UserID == userID {
|
||||
memberships = append(memberships, membership)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return memberships, nil
|
||||
}
|
||||
|
||||
// TeamMembershipsByTeamID return an array containing all the TeamMembership objects where the specified teamID is present.
|
||||
func (service *TeamMembershipService) TeamMembershipsByTeamID(teamID portainer.TeamID) ([]portainer.TeamMembership, error) {
|
||||
var memberships = make([]portainer.TeamMembership, 0)
|
||||
err := service.store.db.View(func(tx *bolt.Tx) error {
|
||||
bucket := tx.Bucket([]byte(teamMembershipBucketName))
|
||||
|
||||
cursor := bucket.Cursor()
|
||||
for k, v := cursor.First(); k != nil; k, v = cursor.Next() {
|
||||
var membership portainer.TeamMembership
|
||||
err := internal.UnmarshalTeamMembership(v, &membership)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if membership.TeamID == teamID {
|
||||
memberships = append(memberships, membership)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return memberships, nil
|
||||
}
|
||||
|
||||
// UpdateTeamMembership saves a TeamMembership object.
|
||||
func (service *TeamMembershipService) UpdateTeamMembership(ID portainer.TeamMembershipID, membership *portainer.TeamMembership) error {
|
||||
data, err := internal.MarshalTeamMembership(membership)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return service.store.db.Update(func(tx *bolt.Tx) error {
|
||||
bucket := tx.Bucket([]byte(teamMembershipBucketName))
|
||||
err = bucket.Put(internal.Itob(int(ID)), data)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// CreateTeamMembership creates a new TeamMembership object.
|
||||
func (service *TeamMembershipService) CreateTeamMembership(membership *portainer.TeamMembership) error {
|
||||
return service.store.db.Update(func(tx *bolt.Tx) error {
|
||||
bucket := tx.Bucket([]byte(teamMembershipBucketName))
|
||||
|
||||
id, _ := bucket.NextSequence()
|
||||
membership.ID = portainer.TeamMembershipID(id)
|
||||
|
||||
data, err := internal.MarshalTeamMembership(membership)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = bucket.Put(internal.Itob(int(membership.ID)), data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// DeleteTeamMembership deletes a TeamMembership object.
|
||||
func (service *TeamMembershipService) DeleteTeamMembership(ID portainer.TeamMembershipID) error {
|
||||
return service.store.db.Update(func(tx *bolt.Tx) error {
|
||||
bucket := tx.Bucket([]byte(teamMembershipBucketName))
|
||||
err := bucket.Delete(internal.Itob(int(ID)))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// DeleteTeamMembershipByUserID deletes all the TeamMembership object associated to a UserID.
|
||||
func (service *TeamMembershipService) DeleteTeamMembershipByUserID(userID portainer.UserID) error {
|
||||
return service.store.db.Update(func(tx *bolt.Tx) error {
|
||||
bucket := tx.Bucket([]byte(teamMembershipBucketName))
|
||||
|
||||
cursor := bucket.Cursor()
|
||||
for k, v := cursor.First(); k != nil; k, v = cursor.Next() {
|
||||
var membership portainer.TeamMembership
|
||||
err := internal.UnmarshalTeamMembership(v, &membership)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if membership.UserID == userID {
|
||||
err := bucket.Delete(internal.Itob(int(membership.ID)))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// DeleteTeamMembershipByTeamID deletes all the TeamMembership object associated to a TeamID.
|
||||
func (service *TeamMembershipService) DeleteTeamMembershipByTeamID(teamID portainer.TeamID) error {
|
||||
return service.store.db.Update(func(tx *bolt.Tx) error {
|
||||
bucket := tx.Bucket([]byte(teamMembershipBucketName))
|
||||
|
||||
cursor := bucket.Cursor()
|
||||
for k, v := cursor.First(); k != nil; k, v = cursor.Next() {
|
||||
var membership portainer.TeamMembership
|
||||
err := internal.UnmarshalTeamMembership(v, &membership)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if membership.TeamID == teamID {
|
||||
err := bucket.Delete(internal.Itob(int(membership.ID)))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
144
api/bolt/team_service.go
Normal file
144
api/bolt/team_service.go
Normal file
|
@ -0,0 +1,144 @@
|
|||
package bolt
|
||||
|
||||
import (
|
||||
"github.com/portainer/portainer"
|
||||
"github.com/portainer/portainer/bolt/internal"
|
||||
|
||||
"github.com/boltdb/bolt"
|
||||
)
|
||||
|
||||
// TeamService represents a service for managing teams.
|
||||
type TeamService struct {
|
||||
store *Store
|
||||
}
|
||||
|
||||
// Team returns a Team by ID
|
||||
func (service *TeamService) Team(ID portainer.TeamID) (*portainer.Team, error) {
|
||||
var data []byte
|
||||
err := service.store.db.View(func(tx *bolt.Tx) error {
|
||||
bucket := tx.Bucket([]byte(teamBucketName))
|
||||
value := bucket.Get(internal.Itob(int(ID)))
|
||||
if value == nil {
|
||||
return portainer.ErrTeamNotFound
|
||||
}
|
||||
|
||||
data = make([]byte, len(value))
|
||||
copy(data, value)
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var team portainer.Team
|
||||
err = internal.UnmarshalTeam(data, &team)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &team, nil
|
||||
}
|
||||
|
||||
// TeamByName returns a team by name.
|
||||
func (service *TeamService) TeamByName(name string) (*portainer.Team, error) {
|
||||
var team *portainer.Team
|
||||
|
||||
err := service.store.db.View(func(tx *bolt.Tx) error {
|
||||
bucket := tx.Bucket([]byte(teamBucketName))
|
||||
cursor := bucket.Cursor()
|
||||
for k, v := cursor.First(); k != nil; k, v = cursor.Next() {
|
||||
var t portainer.Team
|
||||
err := internal.UnmarshalTeam(v, &t)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if t.Name == name {
|
||||
team = &t
|
||||
}
|
||||
}
|
||||
|
||||
if team == nil {
|
||||
return portainer.ErrTeamNotFound
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return team, nil
|
||||
}
|
||||
|
||||
// Teams return an array containing all the teams.
|
||||
func (service *TeamService) Teams() ([]portainer.Team, error) {
|
||||
var teams = make([]portainer.Team, 0)
|
||||
err := service.store.db.View(func(tx *bolt.Tx) error {
|
||||
bucket := tx.Bucket([]byte(teamBucketName))
|
||||
|
||||
cursor := bucket.Cursor()
|
||||
for k, v := cursor.First(); k != nil; k, v = cursor.Next() {
|
||||
var team portainer.Team
|
||||
err := internal.UnmarshalTeam(v, &team)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
teams = append(teams, team)
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return teams, nil
|
||||
}
|
||||
|
||||
// UpdateTeam saves a Team.
|
||||
func (service *TeamService) UpdateTeam(ID portainer.TeamID, team *portainer.Team) error {
|
||||
data, err := internal.MarshalTeam(team)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return service.store.db.Update(func(tx *bolt.Tx) error {
|
||||
bucket := tx.Bucket([]byte(teamBucketName))
|
||||
err = bucket.Put(internal.Itob(int(ID)), data)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// CreateTeam creates a new Team.
|
||||
func (service *TeamService) CreateTeam(team *portainer.Team) error {
|
||||
return service.store.db.Update(func(tx *bolt.Tx) error {
|
||||
bucket := tx.Bucket([]byte(teamBucketName))
|
||||
|
||||
id, _ := bucket.NextSequence()
|
||||
team.ID = portainer.TeamID(id)
|
||||
|
||||
data, err := internal.MarshalTeam(team)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = bucket.Put(internal.Itob(int(team.ID)), data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// DeleteTeam deletes a Team.
|
||||
func (service *TeamService) DeleteTeam(ID portainer.TeamID) error {
|
||||
return service.store.db.Update(func(tx *bolt.Tx) error {
|
||||
bucket := tx.Bucket([]byte(teamBucketName))
|
||||
err := bucket.Delete(internal.Itob(int(ID)))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue