psu/common/accessControl.go

133 lines
5.2 KiB
Go

package common
import (
"fmt"
"net/http"
"github.com/greenled/portainer-stack-utils/client"
portainer "github.com/portainer/portainer/api"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
// NewAccessCmd creates a new Cobra command for Docker resource access control management
func NewAccessCmd(resourceType client.ResourceType, argumentName string) *cobra.Command {
return &cobra.Command{
Use: fmt.Sprintf("access <%s>", argumentName),
Short: fmt.Sprintf("Set access control for %s", resourceType),
Args: cobra.ExactArgs(1),
Run: func(cmd *cobra.Command, args []string) {
portainerClient, clientRetrievalErr := GetClient()
CheckError(clientRetrievalErr)
resourceID := args[0]
setAdmins := viper.GetBool(fmt.Sprintf("%s.access.admins", resourceType))
setPrivate := viper.GetBool(fmt.Sprintf("%s.access.private", resourceType))
setPublic := viper.GetBool(fmt.Sprintf("%s.access.public", resourceType))
if (setAdmins && setPrivate) || (setPrivate && setPublic) || (setPublic && setAdmins) {
logrus.Fatal("only one of --admins, --private or --public flags can be used")
}
var endpoint portainer.Endpoint
if endpointName := viper.GetString(fmt.Sprintf("%s.access.endpoint", resourceType)); endpointName == "" {
// Guess endpoint if not set
logrus.WithFields(logrus.Fields{
"implications": "Command will fail if there is not exactly one endpoint available",
}).Warning("Endpoint not set")
var endpointRetrievalErr error
endpoint, endpointRetrievalErr = GetDefaultEndpoint()
CheckError(endpointRetrievalErr)
endpointName = endpoint.Name
logrus.WithFields(logrus.Fields{
"endpoint": endpointName,
}).Debug("Using the only available endpoint")
} else {
// Get endpoint by name
var endpointRetrievalErr error
endpoint, endpointRetrievalErr = GetEndpointByName(endpointName)
CheckError(endpointRetrievalErr)
}
logrus.WithFields(logrus.Fields{
"endpoint": endpoint.Name,
}).Debug(fmt.Sprintf("Getting %s access control info", resourceType))
if setAdmins {
// We are removing an access control
resourceControl, err := GetDockerResourcePortainerAccessControl(endpoint.ID, resourceID, resourceType)
if err == nil {
err = portainerClient.ResourceControlDelete(resourceControl.ID)
} else if err != ErrAccessControlNotFound {
CheckError(err)
}
} else {
// We may be creating a new access control
resourceControlCreateOptions := client.ResourceControlCreateOptions{
ResourceID: resourceID,
Type: resourceType,
}
if setPrivate {
currentUser, err := GetUserByName(portainerClient.GetUsername())
CheckError(err)
resourceControlCreateOptions.Users = []portainer.UserID{currentUser.ID}
}
if setPublic {
resourceControlCreateOptions.Public = true
}
_, err := portainerClient.ResourceControlCreate(resourceControlCreateOptions)
if err != nil {
genericError, isGenericError := err.(*client.GenericError)
if isGenericError && genericError.Code == http.StatusConflict {
// We are updating an existing access control
resourceControl, err := GetDockerResourcePortainerAccessControl(endpoint.ID, resourceID, resourceType)
if err == nil {
resourceControlUpdateOptions := client.ResourceControlUpdateOptions{
ID: resourceControl.ID,
}
if setPrivate {
currentUser, err := GetUserByName(portainerClient.GetUsername())
CheckError(err)
resourceControlUpdateOptions.Users = []portainer.UserID{currentUser.ID}
}
if setPublic {
resourceControlUpdateOptions.Public = true
}
_, err := portainerClient.ResourceControlUpdate(resourceControlUpdateOptions)
CheckError(err)
} else {
// Something else happened
CheckError(err)
}
} else {
// Something else happened
CheckError(err)
}
}
}
logrus.WithFields(logrus.Fields{
string(resourceType): resourceID,
}).Info("Access control set")
},
}
}
// AccessCmdInitFunc creates an access command for a given Docker resource type
func AccessCmdInitFunc(parentCmd *cobra.Command, resourceControlType client.ResourceType) {
accessCmd := NewAccessCmd(resourceControlType, fmt.Sprintf("|%sId", resourceControlType))
parentCmd.AddCommand(accessCmd)
accessCmd.Flags().String("endpoint", "", "Endpoint name.")
accessCmd.Flags().Bool("admins", false, fmt.Sprintf("Permit access to this %s to administrators only.", resourceControlType))
accessCmd.Flags().Bool("private", false, fmt.Sprintf("Permit access to this %s to the current user only.", resourceControlType))
accessCmd.Flags().Bool("public", false, fmt.Sprintf("Permit access to this %s to any user.", resourceControlType))
viper.BindPFlag(fmt.Sprintf("%s.access.endpoint", resourceControlType), accessCmd.Flags().Lookup("endpoint"))
viper.BindPFlag(fmt.Sprintf("%s.access.admins", resourceControlType), accessCmd.Flags().Lookup("admins"))
viper.BindPFlag(fmt.Sprintf("%s.access.private", resourceControlType), accessCmd.Flags().Lookup("private"))
viper.BindPFlag(fmt.Sprintf("%s.access.public", resourceControlType), accessCmd.Flags().Lookup("public"))
}