mirror of
https://github.com/portainer/portainer.git
synced 2025-07-25 08:19:40 +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
|
@ -5,10 +5,12 @@ import (
|
|||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/portainer/portainer/api/internal/stackutils"
|
||||
|
||||
"github.com/portainer/portainer/api/http/proxy/factory/responseutils"
|
||||
"github.com/portainer/portainer/api/internal/authorization"
|
||||
|
||||
"github.com/portainer/portainer/api"
|
||||
portainer "github.com/portainer/portainer/api"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -117,17 +119,17 @@ func (transport *Transport) getInheritedResourceControlFromServiceOrStack(resour
|
|||
|
||||
switch resourceType {
|
||||
case portainer.ContainerResourceControl:
|
||||
return getInheritedResourceControlFromContainerLabels(client, resourceIdentifier, resourceControls)
|
||||
return getInheritedResourceControlFromContainerLabels(client, transport.endpoint.ID, resourceIdentifier, resourceControls)
|
||||
case portainer.NetworkResourceControl:
|
||||
return getInheritedResourceControlFromNetworkLabels(client, resourceIdentifier, resourceControls)
|
||||
return getInheritedResourceControlFromNetworkLabels(client, transport.endpoint.ID, resourceIdentifier, resourceControls)
|
||||
case portainer.VolumeResourceControl:
|
||||
return getInheritedResourceControlFromVolumeLabels(client, resourceIdentifier, resourceControls)
|
||||
return getInheritedResourceControlFromVolumeLabels(client, transport.endpoint.ID, resourceIdentifier, resourceControls)
|
||||
case portainer.ServiceResourceControl:
|
||||
return getInheritedResourceControlFromServiceLabels(client, resourceIdentifier, resourceControls)
|
||||
return getInheritedResourceControlFromServiceLabels(client, transport.endpoint.ID, resourceIdentifier, resourceControls)
|
||||
case portainer.ConfigResourceControl:
|
||||
return getInheritedResourceControlFromConfigLabels(client, resourceIdentifier, resourceControls)
|
||||
return getInheritedResourceControlFromConfigLabels(client, transport.endpoint.ID, resourceIdentifier, resourceControls)
|
||||
case portainer.SecretResourceControl:
|
||||
return getInheritedResourceControlFromSecretLabels(client, resourceIdentifier, resourceControls)
|
||||
return getInheritedResourceControlFromSecretLabels(client, transport.endpoint.ID, resourceIdentifier, resourceControls)
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
|
@ -273,8 +275,9 @@ func (transport *Transport) findResourceControl(resourceIdentifier string, resou
|
|||
}
|
||||
|
||||
if resourceLabelsObject[resourceLabelForDockerSwarmStackName] != nil {
|
||||
inheritedSwarmStackIdentifier := resourceLabelsObject[resourceLabelForDockerSwarmStackName].(string)
|
||||
resourceControl = authorization.GetResourceControlByResourceIDAndType(inheritedSwarmStackIdentifier, portainer.StackResourceControl, resourceControls)
|
||||
stackName := resourceLabelsObject[resourceLabelForDockerSwarmStackName].(string)
|
||||
stackResourceID := stackutils.ResourceControlID(transport.endpoint.ID, stackName)
|
||||
resourceControl = authorization.GetResourceControlByResourceIDAndType(stackResourceID, portainer.StackResourceControl, resourceControls)
|
||||
|
||||
if resourceControl != nil {
|
||||
return resourceControl, nil
|
||||
|
@ -282,8 +285,9 @@ func (transport *Transport) findResourceControl(resourceIdentifier string, resou
|
|||
}
|
||||
|
||||
if resourceLabelsObject[resourceLabelForDockerComposeStackName] != nil {
|
||||
inheritedComposeStackIdentifier := resourceLabelsObject[resourceLabelForDockerComposeStackName].(string)
|
||||
resourceControl = authorization.GetResourceControlByResourceIDAndType(inheritedComposeStackIdentifier, portainer.StackResourceControl, resourceControls)
|
||||
stackName := resourceLabelsObject[resourceLabelForDockerComposeStackName].(string)
|
||||
stackResourceID := stackutils.ResourceControlID(transport.endpoint.ID, stackName)
|
||||
resourceControl = authorization.GetResourceControlByResourceIDAndType(stackResourceID, portainer.StackResourceControl, resourceControls)
|
||||
|
||||
if resourceControl != nil {
|
||||
return resourceControl, nil
|
||||
|
@ -296,6 +300,20 @@ func (transport *Transport) findResourceControl(resourceIdentifier string, resou
|
|||
return nil, nil
|
||||
}
|
||||
|
||||
func getStackResourceIDFromLabels(resourceLabelsObject map[string]string, endpointID portainer.EndpointID) string {
|
||||
if resourceLabelsObject[resourceLabelForDockerSwarmStackName] != "" {
|
||||
stackName := resourceLabelsObject[resourceLabelForDockerSwarmStackName]
|
||||
return stackutils.ResourceControlID(endpointID, stackName)
|
||||
}
|
||||
|
||||
if resourceLabelsObject[resourceLabelForDockerComposeStackName] != "" {
|
||||
stackName := resourceLabelsObject[resourceLabelForDockerComposeStackName]
|
||||
return stackutils.ResourceControlID(endpointID, stackName)
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
func decorateObject(object map[string]interface{}, resourceControl *portainer.ResourceControl) map[string]interface{} {
|
||||
if object["Portainer"] == nil {
|
||||
object["Portainer"] = make(map[string]interface{})
|
||||
|
|
|
@ -15,15 +15,15 @@ const (
|
|||
configObjectIdentifier = "ID"
|
||||
)
|
||||
|
||||
func getInheritedResourceControlFromConfigLabels(dockerClient *client.Client, configID string, resourceControls []portainer.ResourceControl) (*portainer.ResourceControl, error) {
|
||||
func getInheritedResourceControlFromConfigLabels(dockerClient *client.Client, endpointID portainer.EndpointID, configID string, resourceControls []portainer.ResourceControl) (*portainer.ResourceControl, error) {
|
||||
config, _, err := dockerClient.ConfigInspectWithRaw(context.Background(), configID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
swarmStackName := config.Spec.Labels[resourceLabelForDockerSwarmStackName]
|
||||
if swarmStackName != "" {
|
||||
return authorization.GetResourceControlByResourceIDAndType(swarmStackName, portainer.StackResourceControl, resourceControls), nil
|
||||
stackResourceID := getStackResourceIDFromLabels(config.Spec.Labels, endpointID)
|
||||
if stackResourceID != "" {
|
||||
return authorization.GetResourceControlByResourceIDAndType(stackResourceID, portainer.StackResourceControl, resourceControls), nil
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
|
|
|
@ -19,7 +19,7 @@ const (
|
|||
containerObjectIdentifier = "Id"
|
||||
)
|
||||
|
||||
func getInheritedResourceControlFromContainerLabels(dockerClient *client.Client, containerID string, resourceControls []portainer.ResourceControl) (*portainer.ResourceControl, error) {
|
||||
func getInheritedResourceControlFromContainerLabels(dockerClient *client.Client, endpointID portainer.EndpointID, containerID string, resourceControls []portainer.ResourceControl) (*portainer.ResourceControl, error) {
|
||||
container, err := dockerClient.ContainerInspect(context.Background(), containerID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -33,14 +33,9 @@ func getInheritedResourceControlFromContainerLabels(dockerClient *client.Client,
|
|||
}
|
||||
}
|
||||
|
||||
swarmStackName := container.Config.Labels[resourceLabelForDockerSwarmStackName]
|
||||
if swarmStackName != "" {
|
||||
return authorization.GetResourceControlByResourceIDAndType(swarmStackName, portainer.StackResourceControl, resourceControls), nil
|
||||
}
|
||||
|
||||
composeStackName := container.Config.Labels[resourceLabelForDockerComposeStackName]
|
||||
if composeStackName != "" {
|
||||
return authorization.GetResourceControlByResourceIDAndType(composeStackName, portainer.StackResourceControl, resourceControls), nil
|
||||
stackResourceID := getStackResourceIDFromLabels(container.Config.Labels, endpointID)
|
||||
if stackResourceID != "" {
|
||||
return authorization.GetResourceControlByResourceIDAndType(stackResourceID, portainer.StackResourceControl, resourceControls), nil
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
|
|
|
@ -4,11 +4,12 @@ import (
|
|||
"context"
|
||||
"net/http"
|
||||
|
||||
portainer "github.com/portainer/portainer/api"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
|
||||
"github.com/docker/docker/client"
|
||||
|
||||
"github.com/portainer/portainer/api"
|
||||
"github.com/portainer/portainer/api/http/proxy/factory/responseutils"
|
||||
"github.com/portainer/portainer/api/internal/authorization"
|
||||
)
|
||||
|
@ -18,15 +19,15 @@ const (
|
|||
networkObjectName = "Name"
|
||||
)
|
||||
|
||||
func getInheritedResourceControlFromNetworkLabels(dockerClient *client.Client, networkID string, resourceControls []portainer.ResourceControl) (*portainer.ResourceControl, error) {
|
||||
func getInheritedResourceControlFromNetworkLabels(dockerClient *client.Client, endpointID portainer.EndpointID, networkID string, resourceControls []portainer.ResourceControl) (*portainer.ResourceControl, error) {
|
||||
network, err := dockerClient.NetworkInspect(context.Background(), networkID, types.NetworkInspectOptions{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
swarmStackName := network.Labels[resourceLabelForDockerSwarmStackName]
|
||||
if swarmStackName != "" {
|
||||
return authorization.GetResourceControlByResourceIDAndType(swarmStackName, portainer.StackResourceControl, resourceControls), nil
|
||||
stackResourceID := getStackResourceIDFromLabels(network.Labels, endpointID)
|
||||
if stackResourceID != "" {
|
||||
return authorization.GetResourceControlByResourceIDAndType(stackResourceID, portainer.StackResourceControl, resourceControls), nil
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
|
|
|
@ -15,15 +15,15 @@ const (
|
|||
secretObjectIdentifier = "ID"
|
||||
)
|
||||
|
||||
func getInheritedResourceControlFromSecretLabels(dockerClient *client.Client, secretID string, resourceControls []portainer.ResourceControl) (*portainer.ResourceControl, error) {
|
||||
func getInheritedResourceControlFromSecretLabels(dockerClient *client.Client, endpointID portainer.EndpointID, secretID string, resourceControls []portainer.ResourceControl) (*portainer.ResourceControl, error) {
|
||||
secret, _, err := dockerClient.SecretInspectWithRaw(context.Background(), secretID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
swarmStackName := secret.Spec.Labels[resourceLabelForDockerSwarmStackName]
|
||||
if swarmStackName != "" {
|
||||
return authorization.GetResourceControlByResourceIDAndType(swarmStackName, portainer.StackResourceControl, resourceControls), nil
|
||||
stackResourceID := getStackResourceIDFromLabels(secret.Spec.Labels, endpointID)
|
||||
if stackResourceID != "" {
|
||||
return authorization.GetResourceControlByResourceIDAndType(stackResourceID, portainer.StackResourceControl, resourceControls), nil
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
|
|
|
@ -20,15 +20,15 @@ const (
|
|||
serviceObjectIdentifier = "ID"
|
||||
)
|
||||
|
||||
func getInheritedResourceControlFromServiceLabels(dockerClient *client.Client, serviceID string, resourceControls []portainer.ResourceControl) (*portainer.ResourceControl, error) {
|
||||
func getInheritedResourceControlFromServiceLabels(dockerClient *client.Client, endpointID portainer.EndpointID, serviceID string, resourceControls []portainer.ResourceControl) (*portainer.ResourceControl, error) {
|
||||
service, _, err := dockerClient.ServiceInspectWithRaw(context.Background(), serviceID, types.ServiceInspectOptions{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
swarmStackName := service.Spec.Labels[resourceLabelForDockerSwarmStackName]
|
||||
if swarmStackName != "" {
|
||||
return authorization.GetResourceControlByResourceIDAndType(swarmStackName, portainer.StackResourceControl, resourceControls), nil
|
||||
stackResourceID := getStackResourceIDFromLabels(service.Spec.Labels, endpointID)
|
||||
if stackResourceID != "" {
|
||||
return authorization.GetResourceControlByResourceIDAndType(stackResourceID, portainer.StackResourceControl, resourceControls), nil
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
|
|
|
@ -8,7 +8,7 @@ import (
|
|||
|
||||
"github.com/docker/docker/client"
|
||||
|
||||
"github.com/portainer/portainer/api"
|
||||
portainer "github.com/portainer/portainer/api"
|
||||
"github.com/portainer/portainer/api/http/proxy/factory/responseutils"
|
||||
"github.com/portainer/portainer/api/http/security"
|
||||
"github.com/portainer/portainer/api/internal/authorization"
|
||||
|
@ -18,15 +18,15 @@ const (
|
|||
volumeObjectIdentifier = "ID"
|
||||
)
|
||||
|
||||
func getInheritedResourceControlFromVolumeLabels(dockerClient *client.Client, volumeID string, resourceControls []portainer.ResourceControl) (*portainer.ResourceControl, error) {
|
||||
func getInheritedResourceControlFromVolumeLabels(dockerClient *client.Client, endpointID portainer.EndpointID, volumeID string, resourceControls []portainer.ResourceControl) (*portainer.ResourceControl, error) {
|
||||
volume, err := dockerClient.VolumeInspect(context.Background(), volumeID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
swarmStackName := volume.Labels[resourceLabelForDockerSwarmStackName]
|
||||
if swarmStackName != "" {
|
||||
return authorization.GetResourceControlByResourceIDAndType(swarmStackName, portainer.StackResourceControl, resourceControls), nil
|
||||
stackResourceID := getStackResourceIDFromLabels(volume.Labels, endpointID)
|
||||
if stackResourceID != "" {
|
||||
return authorization.GetResourceControlByResourceIDAndType(stackResourceID, portainer.StackResourceControl, resourceControls), nil
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue