1
0
Fork 0
mirror of https://github.com/portainer/portainer.git synced 2025-07-23 07:19:41 +02:00

feat(stacks): scope stack names to endpoint (#4520)

* refactor(stack): create unique name function

* refactor(stack): change stack resource control id

* feat(stacks): validate stack unique name in endpoint

* feat(stacks): prevent name collision with external stacks

* refactor(stacks): move resource id util

* refactor(stacks): supply resource id util with name and endpoint

* fix(docker): calculate swarm resource id

* feat(stack): prevent migration if stack name already exist

* feat(authorization): use stackutils
This commit is contained in:
Chaim Lev-Ari 2021-02-23 22:18:05 +02:00 committed by GitHub
parent a62e0496de
commit 86ad1c6af1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
25 changed files with 245 additions and 99 deletions

View file

@ -1,13 +1,17 @@
package stacks
import (
"context"
"errors"
"net/http"
"strings"
"sync"
"github.com/docker/docker/api/types"
"github.com/gorilla/mux"
httperror "github.com/portainer/libhttp/error"
portainer "github.com/portainer/portainer/api"
"github.com/portainer/portainer/api/docker"
"github.com/portainer/portainer/api/http/security"
"github.com/portainer/portainer/api/internal/authorization"
)
@ -24,6 +28,7 @@ type Handler struct {
requestBouncer *security.RequestBouncer
*mux.Router
DataStore portainer.DataStore
DockerClientFactory *docker.ClientFactory
FileService portainer.FileService
GitService portainer.GitService
SwarmStackManager portainer.SwarmStackManager
@ -103,3 +108,50 @@ func (handler *Handler) userCanCreateStack(securityContext *security.RestrictedR
return handler.userIsAdminOrEndpointAdmin(user, endpointID)
}
func (handler *Handler) checkUniqueName(endpoint *portainer.Endpoint, name string, stackID portainer.StackID, swarmMode bool) (bool, error) {
stacks, err := handler.DataStore.Stack().Stacks()
if err != nil {
return false, err
}
for _, stack := range stacks {
if strings.EqualFold(stack.Name, name) && (stackID == 0 || stackID != stack.ID) && stack.EndpointID == endpoint.ID {
return false, nil
}
}
dockerClient, err := handler.DockerClientFactory.CreateClient(endpoint, "")
if err != nil {
return false, err
}
defer dockerClient.Close()
if swarmMode {
services, err := dockerClient.ServiceList(context.Background(), types.ServiceListOptions{})
if err != nil {
return false, err
}
for _, service := range services {
serviceNS, ok := service.Spec.Labels["com.docker.stack.namespace"]
if ok && serviceNS == name {
return false, nil
}
}
}
containers, err := dockerClient.ContainerList(context.Background(), types.ContainerListOptions{All: true})
if err != nil {
return false, err
}
for _, container := range containers {
containerNS, ok := container.Labels["com.docker.compose.project"]
if ok && containerNS == name {
return false, nil
}
}
return true, nil
}