feat(exec): relocate config.json to data folder and re-use existing content (#1898)

pull/1892/merge
Anthony Lapenna 2018-05-15 14:12:49 +02:00 committed by GitHub
parent a09af01e17
commit 2c0595f5ed
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 45 additions and 25 deletions

View File

@ -62,8 +62,8 @@ func initStore(dataStorePath string) *bolt.Store {
return store
}
func initStackManager(assetsPath string, signatureService portainer.DigitalSignatureService, fileService portainer.FileService) (portainer.StackManager, error) {
return exec.NewStackManager(assetsPath, signatureService, fileService)
func initStackManager(assetsPath string, dataStorePath string, signatureService portainer.DigitalSignatureService, fileService portainer.FileService) (portainer.StackManager, error) {
return exec.NewStackManager(assetsPath, dataStorePath, signatureService, fileService)
}
func initJWTService(authenticationEnabled bool) portainer.JWTService {
@ -232,7 +232,7 @@ func main() {
log.Fatal(err)
}
stackManager, err := initStackManager(*flags.Assets, digitalSignatureService, fileService)
stackManager, err := initStackManager(*flags.Assets, *flags.Data, digitalSignatureService, fileService)
if err != nil {
log.Fatal(err)
}

View File

@ -2,6 +2,7 @@ package exec
import (
"bytes"
"encoding/json"
"os"
"os/exec"
"path"
@ -13,28 +14,22 @@ import (
// StackManager represents a service for managing stacks.
type StackManager struct {
binaryPath string
dataPath string
signatureService portainer.DigitalSignatureService
fileService portainer.FileService
}
type dockerCLIConfiguration struct {
HTTPHeaders struct {
ManagerOperationHeader string `json:"X-PortainerAgent-ManagerOperation"`
SignatureHeader string `json:"X-PortainerAgent-Signature"`
PublicKey string `json:"X-PortainerAgent-PublicKey"`
} `json:"HttpHeaders"`
}
// NewStackManager initializes a new StackManager service.
// It also updates the configuration of the Docker CLI binary.
func NewStackManager(binaryPath string, signatureService portainer.DigitalSignatureService, fileService portainer.FileService) (*StackManager, error) {
func NewStackManager(binaryPath, dataPath string, signatureService portainer.DigitalSignatureService, fileService portainer.FileService) (*StackManager, error) {
manager := &StackManager{
binaryPath: binaryPath,
dataPath: dataPath,
signatureService: signatureService,
fileService: fileService,
}
err := manager.updateDockerCLIConfiguration(binaryPath)
err := manager.updateDockerCLIConfiguration(dataPath)
if err != nil {
return nil, err
}
@ -44,7 +39,7 @@ func NewStackManager(binaryPath string, signatureService portainer.DigitalSignat
// Login executes the docker login command against a list of registries (including DockerHub).
func (manager *StackManager) Login(dockerhub *portainer.DockerHub, registries []portainer.Registry, endpoint *portainer.Endpoint) {
command, args := prepareDockerCommandAndArgs(manager.binaryPath, endpoint)
command, args := prepareDockerCommandAndArgs(manager.binaryPath, manager.dataPath, endpoint)
for _, registry := range registries {
if registry.Authentication {
registryArgs := append(args, "login", "--username", registry.Username, "--password", registry.Password, registry.URL)
@ -60,7 +55,7 @@ func (manager *StackManager) Login(dockerhub *portainer.DockerHub, registries []
// Logout executes the docker logout command.
func (manager *StackManager) Logout(endpoint *portainer.Endpoint) error {
command, args := prepareDockerCommandAndArgs(manager.binaryPath, endpoint)
command, args := prepareDockerCommandAndArgs(manager.binaryPath, manager.dataPath, endpoint)
args = append(args, "logout")
return runCommandAndCaptureStdErr(command, args, nil, "")
}
@ -68,7 +63,7 @@ func (manager *StackManager) Logout(endpoint *portainer.Endpoint) error {
// Deploy executes the docker stack deploy command.
func (manager *StackManager) Deploy(stack *portainer.Stack, prune bool, endpoint *portainer.Endpoint) error {
stackFilePath := path.Join(stack.ProjectPath, stack.EntryPoint)
command, args := prepareDockerCommandAndArgs(manager.binaryPath, endpoint)
command, args := prepareDockerCommandAndArgs(manager.binaryPath, manager.dataPath, endpoint)
if prune {
args = append(args, "stack", "deploy", "--prune", "--with-registry-auth", "--compose-file", stackFilePath, stack.Name)
@ -87,7 +82,7 @@ func (manager *StackManager) Deploy(stack *portainer.Stack, prune bool, endpoint
// Remove executes the docker stack rm command.
func (manager *StackManager) Remove(stack *portainer.Stack, endpoint *portainer.Endpoint) error {
command, args := prepareDockerCommandAndArgs(manager.binaryPath, endpoint)
command, args := prepareDockerCommandAndArgs(manager.binaryPath, manager.dataPath, endpoint)
args = append(args, "stack", "rm", stack.Name)
return runCommandAndCaptureStdErr(command, args, nil, "")
}
@ -111,7 +106,7 @@ func runCommandAndCaptureStdErr(command string, args []string, env []string, wor
return nil
}
func prepareDockerCommandAndArgs(binaryPath string, endpoint *portainer.Endpoint) (string, []string) {
func prepareDockerCommandAndArgs(binaryPath, dataPath string, endpoint *portainer.Endpoint) (string, []string) {
// Assume Linux as a default
command := path.Join(binaryPath, "docker")
@ -120,7 +115,7 @@ func prepareDockerCommandAndArgs(binaryPath string, endpoint *portainer.Endpoint
}
args := make([]string, 0)
args = append(args, "--config", binaryPath)
args = append(args, "--config", dataPath)
args = append(args, "-H", endpoint.URL)
if !endpoint.TLSConfig.TLS && endpoint.TLSConfig.TLSSkipVerify {
@ -140,21 +135,46 @@ func prepareDockerCommandAndArgs(binaryPath string, endpoint *portainer.Endpoint
return command, args
}
func (manager *StackManager) updateDockerCLIConfiguration(binaryPath string) error {
config := dockerCLIConfiguration{}
config.HTTPHeaders.ManagerOperationHeader = "1"
func (manager *StackManager) updateDockerCLIConfiguration(dataPath string) error {
configFilePath := path.Join(dataPath, "config.json")
config, err := manager.retrieveConfigurationFromDisk(configFilePath)
if err != nil {
return err
}
signature, err := manager.signatureService.Sign(portainer.PortainerAgentSignatureMessage)
if err != nil {
return err
}
config.HTTPHeaders.SignatureHeader = signature
config.HTTPHeaders.PublicKey = manager.signatureService.EncodedPublicKey()
err = manager.fileService.WriteJSONToFile(path.Join(binaryPath, "config.json"), config)
if config["HttpHeaders"] == nil {
config["HttpHeaders"] = make(map[string]interface{})
}
headersObject := config["HttpHeaders"].(map[string]interface{})
headersObject["X-PortainerAgent-ManagerOperation"] = "1"
headersObject["X-PortainerAgent-Signature"] = signature
headersObject["X-PortainerAgent-PublicKey"] = manager.signatureService.EncodedPublicKey()
err = manager.fileService.WriteJSONToFile(configFilePath, config)
if err != nil {
return err
}
return nil
}
func (manager *StackManager) retrieveConfigurationFromDisk(path string) (map[string]interface{}, error) {
var config map[string]interface{}
raw, err := manager.fileService.GetFileContent(path)
if err != nil {
return make(map[string]interface{}), nil
}
err = json.Unmarshal([]byte(raw), &config)
if err != nil {
return nil, err
}
return config, nil
}