mirror of
https://github.com/portainer/portainer.git
synced 2025-08-02 20:35:25 +02:00
feat(tags): add the ability to manage tags (#1971)
* feat(tags): add the ability to manage tags * feat(tags): update tag selector UX * refactor(app): remove unused ui-select library
This commit is contained in:
parent
b349f16090
commit
5e73a49473
50 changed files with 942 additions and 118 deletions
|
@ -27,6 +27,7 @@ type Store struct {
|
|||
RegistryService *RegistryService
|
||||
DockerHubService *DockerHubService
|
||||
StackService *StackService
|
||||
TagService *TagService
|
||||
|
||||
db *bolt.DB
|
||||
checkForDataMigration bool
|
||||
|
@ -45,6 +46,7 @@ const (
|
|||
registryBucketName = "registries"
|
||||
dockerhubBucketName = "dockerhub"
|
||||
stackBucketName = "stacks"
|
||||
tagBucketName = "tags"
|
||||
)
|
||||
|
||||
// NewStore initializes a new Store and the associated services
|
||||
|
@ -62,6 +64,7 @@ func NewStore(storePath string) (*Store, error) {
|
|||
RegistryService: &RegistryService{},
|
||||
DockerHubService: &DockerHubService{},
|
||||
StackService: &StackService{},
|
||||
TagService: &TagService{},
|
||||
}
|
||||
store.UserService.store = store
|
||||
store.TeamService.store = store
|
||||
|
@ -74,6 +77,7 @@ func NewStore(storePath string) (*Store, error) {
|
|||
store.RegistryService.store = store
|
||||
store.DockerHubService.store = store
|
||||
store.StackService.store = store
|
||||
store.TagService.store = store
|
||||
|
||||
_, err := os.Stat(storePath + "/" + databaseFileName)
|
||||
if err != nil && os.IsNotExist(err) {
|
||||
|
@ -99,7 +103,7 @@ func (store *Store) Open() error {
|
|||
|
||||
bucketsToCreate := []string{versionBucketName, userBucketName, teamBucketName, endpointBucketName,
|
||||
endpointGroupBucketName, resourceControlBucketName, teamMembershipBucketName, settingsBucketName,
|
||||
registryBucketName, dockerhubBucketName, stackBucketName}
|
||||
registryBucketName, dockerhubBucketName, stackBucketName, tagBucketName}
|
||||
|
||||
return db.Update(func(tx *bolt.Tx) error {
|
||||
|
||||
|
@ -128,6 +132,7 @@ func (store *Store) Init() error {
|
|||
Labels: []portainer.Pair{},
|
||||
AuthorizedUsers: []portainer.UserID{},
|
||||
AuthorizedTeams: []portainer.TeamID{},
|
||||
Tags: []string{},
|
||||
}
|
||||
|
||||
return store.EndpointGroupService.CreateEndpointGroup(unassignedGroup)
|
||||
|
|
|
@ -107,6 +107,16 @@ func UnmarshalDockerHub(data []byte, settings *portainer.DockerHub) error {
|
|||
return json.Unmarshal(data, settings)
|
||||
}
|
||||
|
||||
// MarshalTag encodes a Tag object to binary format.
|
||||
func MarshalTag(tag *portainer.Tag) ([]byte, error) {
|
||||
return json.Marshal(tag)
|
||||
}
|
||||
|
||||
// UnmarshalTag decodes a Tag object from a binary data.
|
||||
func UnmarshalTag(data []byte, tag *portainer.Tag) error {
|
||||
return json.Unmarshal(data, tag)
|
||||
}
|
||||
|
||||
// Itob returns an 8-byte big endian representation of v.
|
||||
// This function is typically used for encoding integer IDs to byte slices
|
||||
// so that they can be used as BoltDB keys.
|
||||
|
|
37
api/bolt/migrate_dbversion11.go
Normal file
37
api/bolt/migrate_dbversion11.go
Normal file
|
@ -0,0 +1,37 @@
|
|||
package bolt
|
||||
|
||||
func (m *Migrator) updateEndpointsToVersion12() error {
|
||||
legacyEndpoints, err := m.EndpointService.Endpoints()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, endpoint := range legacyEndpoints {
|
||||
endpoint.Tags = []string{}
|
||||
|
||||
err = m.EndpointService.UpdateEndpoint(endpoint.ID, &endpoint)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Migrator) updateEndpointGroupsToVersion12() error {
|
||||
legacyEndpointGroups, err := m.EndpointGroupService.EndpointGroups()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, group := range legacyEndpointGroups {
|
||||
group.Tags = []string{}
|
||||
|
||||
err = m.EndpointGroupService.UpdateEndpointGroup(group.ID, &group)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
|
@ -6,6 +6,7 @@ import "github.com/portainer/portainer"
|
|||
type Migrator struct {
|
||||
UserService *UserService
|
||||
EndpointService *EndpointService
|
||||
EndpointGroupService *EndpointGroupService
|
||||
ResourceControlService *ResourceControlService
|
||||
SettingsService *SettingsService
|
||||
VersionService *VersionService
|
||||
|
@ -18,6 +19,7 @@ func NewMigrator(store *Store, version int) *Migrator {
|
|||
return &Migrator{
|
||||
UserService: store.UserService,
|
||||
EndpointService: store.EndpointService,
|
||||
EndpointGroupService: store.EndpointGroupService,
|
||||
ResourceControlService: store.ResourceControlService,
|
||||
SettingsService: store.SettingsService,
|
||||
VersionService: store.VersionService,
|
||||
|
@ -120,6 +122,18 @@ func (m *Migrator) Migrate() error {
|
|||
}
|
||||
}
|
||||
|
||||
if m.CurrentDBVersion < 12 {
|
||||
err := m.updateEndpointsToVersion12()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = m.updateEndpointGroupsToVersion12()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
err := m.VersionService.StoreDBVersion(portainer.DBVersion)
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
71
api/bolt/tag_service.go
Normal file
71
api/bolt/tag_service.go
Normal file
|
@ -0,0 +1,71 @@
|
|||
package bolt
|
||||
|
||||
import (
|
||||
"github.com/portainer/portainer"
|
||||
"github.com/portainer/portainer/bolt/internal"
|
||||
|
||||
"github.com/boltdb/bolt"
|
||||
)
|
||||
|
||||
// TagService represents a service for managing tags.
|
||||
type TagService struct {
|
||||
store *Store
|
||||
}
|
||||
|
||||
// Tags return an array containing all the tags.
|
||||
func (service *TagService) Tags() ([]portainer.Tag, error) {
|
||||
var tags = make([]portainer.Tag, 0)
|
||||
err := service.store.db.View(func(tx *bolt.Tx) error {
|
||||
bucket := tx.Bucket([]byte(tagBucketName))
|
||||
|
||||
cursor := bucket.Cursor()
|
||||
for k, v := cursor.First(); k != nil; k, v = cursor.Next() {
|
||||
var tag portainer.Tag
|
||||
err := internal.UnmarshalTag(v, &tag)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
tags = append(tags, tag)
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return tags, nil
|
||||
}
|
||||
|
||||
// CreateTag creates a new tag.
|
||||
func (service *TagService) CreateTag(tag *portainer.Tag) error {
|
||||
return service.store.db.Update(func(tx *bolt.Tx) error {
|
||||
bucket := tx.Bucket([]byte(tagBucketName))
|
||||
|
||||
id, _ := bucket.NextSequence()
|
||||
tag.ID = portainer.TagID(id)
|
||||
|
||||
data, err := internal.MarshalTag(tag)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = bucket.Put(internal.Itob(int(tag.ID)), data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// DeleteTag deletes a tag.
|
||||
func (service *TagService) DeleteTag(ID portainer.TagID) error {
|
||||
return service.store.db.Update(func(tx *bolt.Tx) error {
|
||||
bucket := tx.Bucket([]byte(tagBucketName))
|
||||
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