mirror of
https://github.com/portainer/portainer.git
synced 2025-07-24 15:59:41 +02:00
feat(stacks): add support for stack deploy (#1280)
This commit is contained in:
parent
80827935da
commit
587e2fa673
77 changed files with 3219 additions and 702 deletions
|
@ -10,6 +10,7 @@ const (
|
|||
// ErrDockerNetworkIdentifierNotFound defines an error raised when Portainer is unable to find a network identifier
|
||||
ErrDockerNetworkIdentifierNotFound = portainer.Error("Docker network identifier not found")
|
||||
networkIdentifier = "Id"
|
||||
networkLabelForStackIdentifier = "com.docker.stack.namespace"
|
||||
)
|
||||
|
||||
// networkListOperation extracts the response as a JSON object, loop through the networks array
|
||||
|
@ -26,8 +27,7 @@ func networkListOperation(request *http.Request, response *http.Response, execut
|
|||
if executor.operationContext.isAdmin {
|
||||
responseArray, err = decorateNetworkList(responseArray, executor.operationContext.resourceControls)
|
||||
} else {
|
||||
responseArray, err = filterNetworkList(responseArray, executor.operationContext.resourceControls,
|
||||
executor.operationContext.userID, executor.operationContext.userTeamIDs)
|
||||
responseArray, err = filterNetworkList(responseArray, executor.operationContext)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -50,17 +50,85 @@ func networkInspectOperation(request *http.Request, response *http.Response, exe
|
|||
if responseObject[networkIdentifier] == nil {
|
||||
return ErrDockerNetworkIdentifierNotFound
|
||||
}
|
||||
networkID := responseObject[networkIdentifier].(string)
|
||||
|
||||
resourceControl := getResourceControlByResourceID(networkID, executor.operationContext.resourceControls)
|
||||
if resourceControl != nil {
|
||||
if executor.operationContext.isAdmin || canUserAccessResource(executor.operationContext.userID,
|
||||
executor.operationContext.userTeamIDs, resourceControl) {
|
||||
responseObject = decorateObject(responseObject, resourceControl)
|
||||
} else {
|
||||
return rewriteAccessDeniedResponse(response)
|
||||
}
|
||||
networkID := responseObject[networkIdentifier].(string)
|
||||
responseObject, access := applyResourceAccessControl(responseObject, networkID, executor.operationContext)
|
||||
if !access {
|
||||
return rewriteAccessDeniedResponse(response)
|
||||
}
|
||||
|
||||
networkLabels := extractNetworkLabelsFromNetworkInspectObject(responseObject)
|
||||
responseObject, access = applyResourceAccessControlFromLabel(networkLabels, responseObject, networkLabelForStackIdentifier, executor.operationContext)
|
||||
if !access {
|
||||
return rewriteAccessDeniedResponse(response)
|
||||
}
|
||||
|
||||
return rewriteResponse(response, responseObject, http.StatusOK)
|
||||
}
|
||||
|
||||
// extractNetworkLabelsFromNetworkInspectObject retrieve the Labels of the network if present.
|
||||
// Container schema reference: https://docs.docker.com/engine/api/v1.28/#operation/NetworkInspect
|
||||
func extractNetworkLabelsFromNetworkInspectObject(responseObject map[string]interface{}) map[string]interface{} {
|
||||
// Labels are stored under Labels
|
||||
return extractJSONField(responseObject, "Labels")
|
||||
}
|
||||
|
||||
// extractNetworkLabelsFromNetworkListObject retrieve the Labels of the network if present.
|
||||
// Network schema reference: https://docs.docker.com/engine/api/v1.28/#operation/NetworkList
|
||||
func extractNetworkLabelsFromNetworkListObject(responseObject map[string]interface{}) map[string]interface{} {
|
||||
// Labels are stored under Labels
|
||||
return extractJSONField(responseObject, "Labels")
|
||||
}
|
||||
|
||||
// decorateNetworkList loops through all networks and decorates any network with an existing resource control.
|
||||
// Resource controls checks are based on: resource identifier, stack identifier (from label).
|
||||
// Network object schema reference: https://docs.docker.com/engine/api/v1.28/#operation/NetworkList
|
||||
func decorateNetworkList(networkData []interface{}, resourceControls []portainer.ResourceControl) ([]interface{}, error) {
|
||||
decoratedNetworkData := make([]interface{}, 0)
|
||||
|
||||
for _, network := range networkData {
|
||||
|
||||
networkObject := network.(map[string]interface{})
|
||||
if networkObject[networkIdentifier] == nil {
|
||||
return nil, ErrDockerNetworkIdentifierNotFound
|
||||
}
|
||||
|
||||
networkID := networkObject[networkIdentifier].(string)
|
||||
networkObject = decorateResourceWithAccessControl(networkObject, networkID, resourceControls)
|
||||
|
||||
networkLabels := extractNetworkLabelsFromNetworkListObject(networkObject)
|
||||
networkObject = decorateResourceWithAccessControlFromLabel(networkLabels, networkObject, networkLabelForStackIdentifier, resourceControls)
|
||||
|
||||
decoratedNetworkData = append(decoratedNetworkData, networkObject)
|
||||
}
|
||||
|
||||
return decoratedNetworkData, nil
|
||||
}
|
||||
|
||||
// filterNetworkList loops through all networks and filters public networks (no associated resource control)
|
||||
// as well as authorized networks (access granted to the user based on existing resource control).
|
||||
// Authorized networks are decorated during the process.
|
||||
// Resource controls checks are based on: resource identifier, stack identifier (from label).
|
||||
// Network object schema reference: https://docs.docker.com/engine/api/v1.28/#operation/NetworkList
|
||||
func filterNetworkList(networkData []interface{}, context *restrictedOperationContext) ([]interface{}, error) {
|
||||
filteredNetworkData := make([]interface{}, 0)
|
||||
|
||||
for _, network := range networkData {
|
||||
networkObject := network.(map[string]interface{})
|
||||
if networkObject[networkIdentifier] == nil {
|
||||
return nil, ErrDockerNetworkIdentifierNotFound
|
||||
}
|
||||
|
||||
networkID := networkObject[networkIdentifier].(string)
|
||||
networkObject, access := applyResourceAccessControl(networkObject, networkID, context)
|
||||
if access {
|
||||
networkLabels := extractNetworkLabelsFromNetworkListObject(networkObject)
|
||||
networkObject, access = applyResourceAccessControlFromLabel(networkLabels, networkObject, networkLabelForStackIdentifier, context)
|
||||
if access {
|
||||
filteredNetworkData = append(filteredNetworkData, networkObject)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return filteredNetworkData, nil
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue