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:
parent
a62e0496de
commit
86ad1c6af1
25 changed files with 245 additions and 99 deletions
|
@ -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
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue