1
0
Fork 0
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:
Anthony Lapenna 2017-10-15 19:24:40 +02:00 committed by GitHub
parent 80827935da
commit 587e2fa673
77 changed files with 3219 additions and 702 deletions

View file

@ -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
}