1
0
Fork 0
mirror of https://github.com/portainer/portainer.git synced 2025-08-02 20:35:25 +02:00

feat(waiting-room): choose relations when associated endpoint [EE-5187] (#8720)

This commit is contained in:
Chaim Lev-Ari 2023-05-14 09:26:11 +07:00 committed by GitHub
parent 511adabce2
commit 365316971b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
53 changed files with 1712 additions and 303 deletions

View file

@ -39,7 +39,7 @@ func Test_EndpointList_AgentVersion(t *testing.T) {
noVersionEndpoint := portainer.Endpoint{ID: 3, Type: portainer.AgentOnDockerEnvironment, GroupID: 1}
notAgentEnvironments := portainer.Endpoint{ID: 4, Type: portainer.DockerEnvironment, GroupID: 1}
handler, teardown := setup(t, []portainer.Endpoint{
handler, teardown := setupEndpointListHandler(t, []portainer.Endpoint{
notAgentEnvironments,
version1Endpoint,
version2Endpoint,
@ -111,7 +111,7 @@ func Test_endpointList_edgeFilter(t *testing.T) {
regularTrustedEdgeStandard := portainer.Endpoint{ID: 4, UserTrusted: true, Edge: portainer.EnvironmentEdgeSettings{AsyncMode: false}, GroupID: 1, Type: portainer.EdgeAgentOnDockerEnvironment}
regularEndpoint := portainer.Endpoint{ID: 5, GroupID: 1, Type: portainer.DockerEnvironment}
handler, teardown := setup(t, []portainer.Endpoint{
handler, teardown := setupEndpointListHandler(t, []portainer.Endpoint{
trustedEdgeAsync,
untrustedEdgeAsync,
regularUntrustedEdgeStandard,
@ -184,7 +184,7 @@ func Test_endpointList_edgeFilter(t *testing.T) {
}
}
func setup(t *testing.T, endpoints []portainer.Endpoint) (handler *Handler, teardown func()) {
func setupEndpointListHandler(t *testing.T, endpoints []portainer.Endpoint) (handler *Handler, teardown func()) {
is := assert.New(t)
_, store, teardown := datastore.MustNewTestStore(t, true, true)

View file

@ -9,9 +9,8 @@ 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/http/client"
"github.com/portainer/portainer/api/internal/edge"
"github.com/portainer/portainer/api/internal/tag"
)
type endpointUpdatePayload struct {
@ -120,48 +119,31 @@ func (handler *Handler) endpointUpdate(w http.ResponseWriter, r *http.Request) *
endpoint.EdgeCheckinInterval = *payload.EdgeCheckinInterval
}
groupIDChanged := false
updateRelations := false
if payload.GroupID != nil {
groupID := portainer.EndpointGroupID(*payload.GroupID)
groupIDChanged = groupID != endpoint.GroupID
endpoint.GroupID = groupID
updateRelations = updateRelations || groupID != endpoint.GroupID
}
tagsChanged := false
if payload.TagIDs != nil {
payloadTagSet := tag.Set(payload.TagIDs)
endpointTagSet := tag.Set((endpoint.TagIDs))
union := tag.Union(payloadTagSet, endpointTagSet)
intersection := tag.Intersection(payloadTagSet, endpointTagSet)
tagsChanged = len(union) > len(intersection)
err := handler.DataStore.UpdateTx(func(tx dataservices.DataStoreTx) error {
if tagsChanged {
removeTags := tag.Difference(endpointTagSet, payloadTagSet)
for tagID := range removeTags {
err = handler.DataStore.Tag().UpdateTagFunc(tagID, func(tag *portainer.Tag) {
delete(tag.Endpoints, endpoint.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)
}
tagsChanged, err := updateEnvironmentTags(tx, payload.TagIDs, endpoint.TagIDs, endpoint.ID)
if err != nil {
return err
}
endpoint.TagIDs = payload.TagIDs
for _, tagID := range payload.TagIDs {
err = handler.DataStore.Tag().UpdateTagFunc(tagID, func(tag *portainer.Tag) {
tag.Endpoints[endpoint.ID] = true
})
updateRelations = updateRelations || tagsChanged
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)
}
}
return nil
})
if err != nil {
httperror.InternalServerError("Unable to update environment tags", err)
}
}
@ -286,39 +268,13 @@ func (handler *Handler) endpointUpdate(w http.ResponseWriter, r *http.Request) *
return httperror.InternalServerError("Unable to persist environment changes inside the database", err)
}
if (endpoint.Type == portainer.EdgeAgentOnDockerEnvironment || endpoint.Type == portainer.EdgeAgentOnKubernetesEnvironment) && (groupIDChanged || tagsChanged) {
relation, err := handler.DataStore.EndpointRelation().EndpointRelation(endpoint.ID)
if updateRelations {
err := handler.DataStore.UpdateTx(func(tx dataservices.DataStoreTx) error {
return handler.updateEdgeRelations(tx, endpoint)
})
if err != nil {
return httperror.InternalServerError("Unable to find environment relation inside the database", err)
}
endpointGroup, err := handler.DataStore.EndpointGroup().EndpointGroup(endpoint.GroupID)
if err != nil {
return httperror.InternalServerError("Unable to find environment group inside the database", err)
}
edgeGroups, err := handler.DataStore.EdgeGroup().EdgeGroups()
if err != nil {
return httperror.InternalServerError("Unable to retrieve edge groups from the database", err)
}
edgeStacks, err := handler.DataStore.EdgeStack().EdgeStacks()
if err != nil {
return httperror.InternalServerError("Unable to retrieve edge stacks from the database", err)
}
currentEdgeStackSet := map[portainer.EdgeStackID]bool{}
endpointEdgeStacks := edge.EndpointRelatedEdgeStacks(endpoint, endpointGroup, edgeGroups, edgeStacks)
for _, edgeStackID := range endpointEdgeStacks {
currentEdgeStackSet[edgeStackID] = true
}
relation.EdgeStacks = currentEdgeStackSet
err = handler.DataStore.EndpointRelation().UpdateEndpointRelation(endpoint.ID, relation)
if err != nil {
return httperror.InternalServerError("Unable to persist environment relation changes inside the database", err)
return httperror.InternalServerError("Unable to update environment relations", err)
}
}

View file

@ -0,0 +1,110 @@
package endpoints
import (
"net/http"
"github.com/pkg/errors"
httperror "github.com/portainer/libhttp/error"
"github.com/portainer/libhttp/request"
"github.com/portainer/libhttp/response"
portainer "github.com/portainer/portainer/api"
"github.com/portainer/portainer/api/dataservices"
)
type endpointUpdateRelationsPayload struct {
Relations map[portainer.EndpointID]struct {
EdgeGroups []portainer.EdgeGroupID
Tags []portainer.TagID
Group portainer.EndpointGroupID
}
}
func (payload *endpointUpdateRelationsPayload) Validate(r *http.Request) error {
for eID := range payload.Relations {
if eID == 0 {
return errors.New("Missing environment identifier")
}
}
return nil
}
// @id EndpointUpdateRelations
// @summary Update relations for a list of environments
// @description Update relations for a list of environments
// @description Edge groups, tags and environment group can be updated.
// @description
// @description **Access policy**: administrator
// @tags endpoints
// @security jwt
// @accept json
// @param body body endpointUpdateRelationsPayload true "Environment relations data"
// @success 204 "Success"
// @failure 400 "Invalid request"
// @failure 401 "Unauthorized"
// @failure 404 "Not found"
// @failure 500 "Server error"
// @router /endpoints/relations [put]
func (handler *Handler) updateRelations(w http.ResponseWriter, r *http.Request) *httperror.HandlerError {
payload, err := request.GetPayload[endpointUpdateRelationsPayload](r)
if err != nil {
return httperror.BadRequest("Invalid request payload", err)
}
err = handler.DataStore.UpdateTx(func(tx dataservices.DataStoreTx) error {
for environmentID, relationPayload := range payload.Relations {
endpoint, err := tx.Endpoint().Endpoint(environmentID)
if err != nil {
return errors.WithMessage(err, "Unable to find an environment with the specified identifier inside the database")
}
updateRelations := false
if relationPayload.Group != 0 {
groupIDChanged := endpoint.GroupID != relationPayload.Group
endpoint.GroupID = relationPayload.Group
updateRelations = updateRelations || groupIDChanged
}
if relationPayload.Tags != nil {
tagsChanged, err := updateEnvironmentTags(tx, relationPayload.Tags, endpoint.TagIDs, endpoint.ID)
if err != nil {
return errors.WithMessage(err, "Unable to update environment tags")
}
endpoint.TagIDs = relationPayload.Tags
updateRelations = updateRelations || tagsChanged
}
if relationPayload.EdgeGroups != nil {
edgeGroupsChanged, err := updateEnvironmentEdgeGroups(tx, relationPayload.EdgeGroups, endpoint.ID)
if err != nil {
return errors.WithMessage(err, "Unable to update environment edge groups")
}
updateRelations = updateRelations || edgeGroupsChanged
}
if updateRelations {
err := tx.Endpoint().UpdateEndpoint(endpoint.ID, endpoint)
if err != nil {
return errors.WithMessage(err, "Unable to update environment")
}
err = handler.updateEdgeRelations(tx, endpoint)
if err != nil {
return errors.WithMessage(err, "Unable to update environment relations")
}
}
}
return nil
})
if err != nil {
return httperror.InternalServerError("Unable to update environment relations", err)
}
return response.Empty(w)
}

View file

@ -69,6 +69,7 @@ func NewHandler(bouncer requestBouncer, demoService *demo.Service) *Handler {
bouncer.RestrictedAccess(httperror.LoggerHandler(h.endpointList))).Methods(http.MethodGet)
h.Handle("/endpoints/agent_versions",
bouncer.RestrictedAccess(httperror.LoggerHandler(h.agentVersions))).Methods(http.MethodGet)
h.Handle("/endpoints/relations", bouncer.RestrictedAccess(httperror.LoggerHandler(h.updateRelations))).Methods(http.MethodPut)
h.Handle("/endpoints/{id}",
bouncer.RestrictedAccess(httperror.LoggerHandler(h.endpointInspect))).Methods(http.MethodGet)

View file

@ -0,0 +1,48 @@
package endpoints
import (
"github.com/pkg/errors"
portainer "github.com/portainer/portainer/api"
"github.com/portainer/portainer/api/dataservices"
"github.com/portainer/portainer/api/internal/edge"
"github.com/portainer/portainer/api/internal/endpointutils"
"github.com/portainer/portainer/api/internal/set"
)
// updateEdgeRelations updates the edge stacks associated to an edge endpoint
func (handler *Handler) updateEdgeRelations(tx dataservices.DataStoreTx, endpoint *portainer.Endpoint) error {
if !endpointutils.IsEdgeEndpoint(endpoint) {
return nil
}
relation, err := tx.EndpointRelation().EndpointRelation(endpoint.ID)
if err != nil {
return errors.WithMessage(err, "Unable to find environment relation inside the database")
}
endpointGroup, err := tx.EndpointGroup().EndpointGroup(endpoint.GroupID)
if err != nil {
return errors.WithMessage(err, "Unable to find environment group inside the database")
}
edgeGroups, err := tx.EdgeGroup().EdgeGroups()
if err != nil {
return errors.WithMessage(err, "Unable to retrieve edge groups from the database")
}
edgeStacks, err := tx.EdgeStack().EdgeStacks()
if err != nil {
return errors.WithMessage(err, "Unable to retrieve edge stacks from the database")
}
currentEdgeStackSet := set.ToSet(edge.EndpointRelatedEdgeStacks(endpoint, endpointGroup, edgeGroups, edgeStacks))
relation.EdgeStacks = currentEdgeStackSet
err = tx.EndpointRelation().UpdateEndpointRelation(endpoint.ID, relation)
if err != nil {
return errors.WithMessage(err, "Unable to persist environment relation changes inside the database")
}
return nil
}

View file

@ -0,0 +1,72 @@
package endpoints
import (
"github.com/pkg/errors"
portainer "github.com/portainer/portainer/api"
"github.com/portainer/portainer/api/dataservices"
"github.com/portainer/portainer/api/internal/set"
"github.com/portainer/portainer/api/internal/slices"
)
func updateEnvironmentEdgeGroups(tx dataservices.DataStoreTx, newEdgeGroups []portainer.EdgeGroupID, environmentID portainer.EndpointID) (bool, error) {
edgeGroups, err := tx.EdgeGroup().EdgeGroups()
if err != nil {
return false, errors.WithMessage(err, "Unable to retrieve edge groups from the database")
}
newEdgeGroupsSet := set.ToSet(newEdgeGroups)
environmentEdgeGroupsSet := set.Set[portainer.EdgeGroupID]{}
for _, edgeGroup := range edgeGroups {
for _, eID := range edgeGroup.Endpoints {
if eID == environmentID {
environmentEdgeGroupsSet[edgeGroup.ID] = true
}
}
}
union := set.Union(newEdgeGroupsSet, environmentEdgeGroupsSet)
intersection := set.Intersection(newEdgeGroupsSet, environmentEdgeGroupsSet)
if len(union) <= len(intersection) {
return false, nil
}
updateSet := func(groupIDs set.Set[portainer.EdgeGroupID], updateItem func(*portainer.EdgeGroup)) error {
for groupID := range groupIDs {
group, err := tx.EdgeGroup().EdgeGroup(groupID)
if err != nil {
return errors.WithMessage(err, "Unable to find a Edge group inside the database")
}
updateItem(group)
err = tx.EdgeGroup().UpdateEdgeGroup(groupID, group)
if err != nil {
return errors.WithMessage(err, "Unable to persist Edge group changes inside the database")
}
}
return nil
}
removeEdgeGroups := environmentEdgeGroupsSet.Difference(newEdgeGroupsSet)
err = updateSet(removeEdgeGroups, func(edgeGroup *portainer.EdgeGroup) {
edgeGroup.Endpoints = slices.RemoveItem(edgeGroup.Endpoints, func(eID portainer.EndpointID) bool {
return eID == environmentID
})
})
if err != nil {
return false, err
}
addToEdgeGroups := newEdgeGroupsSet.Difference(environmentEdgeGroupsSet)
err = updateSet(addToEdgeGroups, func(edgeGroup *portainer.EdgeGroup) {
edgeGroup.Endpoints = append(edgeGroup.Endpoints, environmentID)
})
if err != nil {
return false, err
}
return true, nil
}

View file

@ -0,0 +1,156 @@
package endpoints
import (
"testing"
portainer "github.com/portainer/portainer/api"
"github.com/portainer/portainer/api/dataservices"
"github.com/portainer/portainer/api/datastore"
"github.com/stretchr/testify/assert"
)
func Test_updateEdgeGroups(t *testing.T) {
createGroups := func(store *datastore.Store, names []string) ([]portainer.EdgeGroup, error) {
groups := make([]portainer.EdgeGroup, len(names))
for index, name := range names {
group := &portainer.EdgeGroup{
Name: name,
Dynamic: false,
TagIDs: make([]portainer.TagID, 0),
Endpoints: make([]portainer.EndpointID, 0),
}
err := store.EdgeGroup().Create(group)
if err != nil {
return nil, err
}
groups[index] = *group
}
return groups, nil
}
checkGroups := func(store *datastore.Store, is *assert.Assertions, groupIDs []portainer.EdgeGroupID, endpointID portainer.EndpointID) {
for _, groupID := range groupIDs {
group, err := store.EdgeGroup().EdgeGroup(groupID)
is.NoError(err)
for _, endpoint := range group.Endpoints {
if endpoint == endpointID {
return
}
}
is.Fail("expected endpoint to be in group")
}
}
groupsByName := func(groups []portainer.EdgeGroup, groupNames []string) []portainer.EdgeGroup {
result := make([]portainer.EdgeGroup, len(groupNames))
for i, tagName := range groupNames {
for j, tag := range groups {
if tag.Name == tagName {
result[i] = groups[j]
break
}
}
}
return result
}
type testCase struct {
title string
endpoint *portainer.Endpoint
groupNames []string
endpointGroupNames []string
groupsToApply []string
shouldNotBeUpdated bool
}
testFn := func(t *testing.T, testCase testCase) {
is := assert.New(t)
_, store, teardown := datastore.MustNewTestStore(t, true, true)
defer teardown()
err := store.Endpoint().Create(testCase.endpoint)
is.NoError(err)
groups, err := createGroups(store, testCase.groupNames)
is.NoError(err)
endpointGroups := groupsByName(groups, testCase.endpointGroupNames)
for _, group := range endpointGroups {
group.Endpoints = append(group.Endpoints, testCase.endpoint.ID)
err = store.EdgeGroup().UpdateEdgeGroup(group.ID, &group)
is.NoError(err)
}
expectedGroups := groupsByName(groups, testCase.groupsToApply)
expectedIDs := make([]portainer.EdgeGroupID, len(expectedGroups))
for i, tag := range expectedGroups {
expectedIDs[i] = tag.ID
}
err = store.UpdateTx(func(tx dataservices.DataStoreTx) error {
updated, err := updateEnvironmentEdgeGroups(tx, expectedIDs, testCase.endpoint.ID)
is.NoError(err)
is.Equal(testCase.shouldNotBeUpdated, !updated)
return nil
})
is.NoError(err)
checkGroups(store, is, expectedIDs, testCase.endpoint.ID)
}
testCases := []testCase{
{
title: "applying edge groups to an endpoint without edge groups",
endpoint: &portainer.Endpoint{},
groupNames: []string{"edge group1", "edge group2", "edge group3"},
endpointGroupNames: []string{},
groupsToApply: []string{"edge group1", "edge group2", "edge group3"},
},
{
title: "applying edge groups to an endpoint with edge groups",
endpoint: &portainer.Endpoint{},
groupNames: []string{"edge group1", "edge group2", "edge group3", "edge group4", "edge group5", "edge group6"},
endpointGroupNames: []string{"edge group1", "edge group2", "edge group3"},
groupsToApply: []string{"edge group4", "edge group5", "edge group6"},
},
{
title: "applying edge groups to an endpoint with edge groups that are already applied",
endpoint: &portainer.Endpoint{},
groupNames: []string{"edge group1", "edge group2", "edge group3"},
endpointGroupNames: []string{"edge group1", "edge group2", "edge group3"},
groupsToApply: []string{"edge group1", "edge group2", "edge group3"},
shouldNotBeUpdated: true,
},
{
title: "adding new edge groups to an endpoint with edge groups ",
endpoint: &portainer.Endpoint{},
groupNames: []string{"edge group1", "edge group2", "edge group3", "edge group4", "edge group5", "edge group6"},
endpointGroupNames: []string{"edge group1", "edge group2", "edge group3"},
groupsToApply: []string{"edge group1", "edge group2", "edge group3", "edge group4", "edge group5", "edge group6"},
},
{
title: "mixing edge groups that are already applied and new edge groups",
endpoint: &portainer.Endpoint{},
groupNames: []string{"edge group1", "edge group2", "edge group3", "edge group4", "edge group5", "edge group6"},
endpointGroupNames: []string{"edge group1", "edge group2", "edge group3"},
groupsToApply: []string{"edge group2", "edge group4", "edge group5"},
},
}
for _, testCase := range testCases {
t.Run(testCase.title, func(t *testing.T) {
testFn(t, testCase)
})
}
}

View file

@ -0,0 +1,56 @@
package endpoints
import (
"github.com/pkg/errors"
portainer "github.com/portainer/portainer/api"
"github.com/portainer/portainer/api/dataservices"
"github.com/portainer/portainer/api/internal/set"
)
// updateEnvironmentTags updates the tags associated to an environment
func updateEnvironmentTags(tx dataservices.DataStoreTx, newTags []portainer.TagID, oldTags []portainer.TagID, environmentID portainer.EndpointID) (bool, error) {
payloadTagSet := set.ToSet(newTags)
environmentTagSet := set.ToSet(oldTags)
union := set.Union(payloadTagSet, environmentTagSet)
intersection := set.Intersection(payloadTagSet, environmentTagSet)
if len(union) <= len(intersection) {
return false, nil
}
updateSet := func(tagIDs set.Set[portainer.TagID], updateItem func(*portainer.Tag)) error {
for tagID := range tagIDs {
tag, err := tx.Tag().Tag(tagID)
if err != nil {
return errors.WithMessage(err, "Unable to find a tag inside the database")
}
updateItem(tag)
err = tx.Tag().UpdateTag(tagID, tag)
if err != nil {
return errors.WithMessage(err, "Unable to persist tag changes inside the database")
}
}
return nil
}
removeTags := environmentTagSet.Difference(payloadTagSet)
err := updateSet(removeTags, func(tag *portainer.Tag) {
delete(tag.Endpoints, environmentID)
})
if err != nil {
return false, err
}
addTags := payloadTagSet.Difference(environmentTagSet)
err = updateSet(addTags, func(tag *portainer.Tag) {
tag.Endpoints[environmentID] = true
})
if err != nil {
return false, err
}
return true, nil
}

View file

@ -0,0 +1,165 @@
package endpoints
import (
"testing"
portainer "github.com/portainer/portainer/api"
"github.com/portainer/portainer/api/dataservices"
"github.com/portainer/portainer/api/datastore"
"github.com/stretchr/testify/assert"
)
func Test_updateTags(t *testing.T) {
createTags := func(store *datastore.Store, tagNames []string) ([]portainer.Tag, error) {
tags := make([]portainer.Tag, len(tagNames))
for index, tagName := range tagNames {
tag := &portainer.Tag{
Name: tagName,
Endpoints: make(map[portainer.EndpointID]bool),
EndpointGroups: make(map[portainer.EndpointGroupID]bool),
}
err := store.Tag().Create(tag)
if err != nil {
return nil, err
}
tags[index] = *tag
}
return tags, nil
}
checkTags := func(store *datastore.Store, is *assert.Assertions, tagIDs []portainer.TagID, endpointID portainer.EndpointID) {
for _, tagID := range tagIDs {
tag, err := store.Tag().Tag(tagID)
is.NoError(err)
_, ok := tag.Endpoints[endpointID]
is.True(ok, "expected endpoint to be tagged")
}
}
tagsByName := func(tags []portainer.Tag, tagNames []string) []portainer.Tag {
result := make([]portainer.Tag, len(tagNames))
for i, tagName := range tagNames {
for j, tag := range tags {
if tag.Name == tagName {
result[i] = tags[j]
break
}
}
}
return result
}
getIDs := func(tags []portainer.Tag) []portainer.TagID {
ids := make([]portainer.TagID, len(tags))
for i, tag := range tags {
ids[i] = tag.ID
}
return ids
}
type testCase struct {
title string
endpoint *portainer.Endpoint
tagNames []string
endpointTagNames []string
tagsToApply []string
shouldNotBeUpdated bool
}
testFn := func(t *testing.T, testCase testCase) {
is := assert.New(t)
_, store, teardown := datastore.MustNewTestStore(t, true, true)
defer teardown()
err := store.Endpoint().Create(testCase.endpoint)
is.NoError(err)
tags, err := createTags(store, testCase.tagNames)
is.NoError(err)
endpointTags := tagsByName(tags, testCase.endpointTagNames)
for _, tag := range endpointTags {
tag.Endpoints[testCase.endpoint.ID] = true
err = store.Tag().UpdateTag(tag.ID, &tag)
is.NoError(err)
}
endpointTagIDs := getIDs(endpointTags)
testCase.endpoint.TagIDs = endpointTagIDs
err = store.Endpoint().UpdateEndpoint(testCase.endpoint.ID, testCase.endpoint)
is.NoError(err)
expectedTags := tagsByName(tags, testCase.tagsToApply)
expectedTagIDs := make([]portainer.TagID, len(expectedTags))
for i, tag := range expectedTags {
expectedTagIDs[i] = tag.ID
}
err = store.UpdateTx(func(tx dataservices.DataStoreTx) error {
updated, err := updateEnvironmentTags(tx, expectedTagIDs, testCase.endpoint.TagIDs, testCase.endpoint.ID)
is.NoError(err)
is.Equal(testCase.shouldNotBeUpdated, !updated)
return nil
})
is.NoError(err)
checkTags(store, is, expectedTagIDs, testCase.endpoint.ID)
}
testCases := []testCase{
{
title: "applying tags to an endpoint without tags",
endpoint: &portainer.Endpoint{},
tagNames: []string{"tag1", "tag2", "tag3"},
endpointTagNames: []string{},
tagsToApply: []string{"tag1", "tag2", "tag3"},
},
{
title: "applying tags to an endpoint with tags",
endpoint: &portainer.Endpoint{},
tagNames: []string{"tag1", "tag2", "tag3", "tag4", "tag5", "tag6"},
endpointTagNames: []string{"tag1", "tag2", "tag3"},
tagsToApply: []string{"tag4", "tag5", "tag6"},
},
{
title: "applying tags to an endpoint with tags that are already applied",
endpoint: &portainer.Endpoint{},
tagNames: []string{"tag1", "tag2", "tag3"},
endpointTagNames: []string{"tag1", "tag2", "tag3"},
tagsToApply: []string{"tag1", "tag2", "tag3"},
shouldNotBeUpdated: true,
},
{
title: "adding new tags to an endpoint with tags ",
endpoint: &portainer.Endpoint{},
tagNames: []string{"tag1", "tag2", "tag3", "tag4", "tag5", "tag6"},
endpointTagNames: []string{"tag1", "tag2", "tag3"},
tagsToApply: []string{"tag1", "tag2", "tag3", "tag4", "tag5", "tag6"},
},
{
title: "mixing tags that are already applied and new tags",
endpoint: &portainer.Endpoint{},
tagNames: []string{"tag1", "tag2", "tag3", "tag4", "tag5", "tag6"},
endpointTagNames: []string{"tag1", "tag2", "tag3"},
tagsToApply: []string{"tag2", "tag4", "tag5"},
},
}
for _, testCase := range testCases {
t.Run(testCase.title, func(t *testing.T) {
testFn(t, testCase)
})
}
}