mirror of
https://github.com/portainer/portainer.git
synced 2025-07-22 06:49:40 +02:00
feat(compose): add docker-compose wrapper (#4713)
* feat(compose): add docker-compose wrapper ce-187 * fix(compose): pick compose implementation upon startup * Add static compose build for linux * Fix wget * Fix platofrm specific docker-compose download * Keep amd64 architecture as download parameter * Add tmp folder for docker-compose * fix: line endings * add proxy server * logs * Proxy * Add lite transport for compose * Fix local deployment * refactor: pass proxyManager by ref * fix: string conversion * refactor: compose wrapper remove unused code * fix: tests * Add edge * Fix merge issue * refactor: remove unused code * Move server to proxy implementation * Cleanup wrapper and manager * feat: pass max supported compose syntax version with each endpoint * fix: pick compose syntax version * fix: store wrapper version in portainer * Get and show composeSyntaxMaxVersion at stack creation screen * Get and show composeSyntaxMaxVersion at stack editor screen * refactor: proxy server * Fix used tmp * Bump docker-compose to 1.28.0 * remove message for docker compose limitation * fix: markup typo * Rollback docker compose to 1.27.4 * * attempt to fix the windows build issue * * attempt to debug grunt issue * * use console log in grunt file * fix: try to fix windows build by removing indirect deps from go.mod * Remove tmp folder * Remove builder stage * feat(build/windows): add git for Docker Compose * feat(build/windows): add git for Docker Compose * feat(build/windows): add git for Docker Compose * feat(build/windows): add git for Docker Compose * feat(build/windows): add git for Docker Compose * feat(build/windows): add git for Docker Compose - fixed verbose output * refactor: renames * fix(stack): get endpoint by EndpointProvider * fix(stack): use margin to add space between line instead of using br tag Co-authored-by: Stéphane Busso <stephane.busso@gmail.com> Co-authored-by: Simon Meng <simon.meng@portainer.io> Co-authored-by: yi-portainer <yi.chen@portainer.io> Co-authored-by: Steven Kang <skan070@gmail.com>
This commit is contained in:
parent
83f4c5ec0b
commit
a71e71f481
31 changed files with 750 additions and 92 deletions
132
api/exec/compose_wrapper.go
Normal file
132
api/exec/compose_wrapper.go
Normal file
|
@ -0,0 +1,132 @@
|
|||
package exec
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
portainer "github.com/portainer/portainer/api"
|
||||
"github.com/portainer/portainer/api/http/proxy"
|
||||
)
|
||||
|
||||
// ComposeWrapper is a wrapper for docker-compose binary
|
||||
type ComposeWrapper struct {
|
||||
binaryPath string
|
||||
proxyManager *proxy.Manager
|
||||
}
|
||||
|
||||
// NewComposeWrapper returns a docker-compose wrapper if corresponding binary present, otherwise nil
|
||||
func NewComposeWrapper(binaryPath string, proxyManager *proxy.Manager) *ComposeWrapper {
|
||||
if !IsBinaryPresent(programPath(binaryPath, "docker-compose")) {
|
||||
return nil
|
||||
}
|
||||
|
||||
return &ComposeWrapper{
|
||||
binaryPath: binaryPath,
|
||||
proxyManager: proxyManager,
|
||||
}
|
||||
}
|
||||
|
||||
// ComposeSyntaxMaxVersion returns the maximum supported version of the docker compose syntax
|
||||
func (w *ComposeWrapper) ComposeSyntaxMaxVersion() string {
|
||||
return portainer.ComposeSyntaxMaxVersion
|
||||
}
|
||||
|
||||
// Up builds, (re)creates and starts containers in the background. Wraps `docker-compose up -d` command
|
||||
func (w *ComposeWrapper) Up(stack *portainer.Stack, endpoint *portainer.Endpoint) error {
|
||||
_, err := w.command([]string{"up", "-d"}, stack, endpoint)
|
||||
return err
|
||||
}
|
||||
|
||||
// Down stops and removes containers, networks, images, and volumes. Wraps `docker-compose down --remove-orphans` command
|
||||
func (w *ComposeWrapper) Down(stack *portainer.Stack, endpoint *portainer.Endpoint) error {
|
||||
_, err := w.command([]string{"down", "--remove-orphans"}, stack, endpoint)
|
||||
return err
|
||||
}
|
||||
|
||||
func (w *ComposeWrapper) command(command []string, stack *portainer.Stack, endpoint *portainer.Endpoint) ([]byte, error) {
|
||||
if endpoint == nil {
|
||||
return nil, errors.New("cannot call a compose command on an empty endpoint")
|
||||
}
|
||||
|
||||
program := programPath(w.binaryPath, "docker-compose")
|
||||
|
||||
options := setComposeFile(stack)
|
||||
|
||||
options = addProjectNameOption(options, stack)
|
||||
options, err := addEnvFileOption(options, stack)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !(endpoint.URL == "" || strings.HasPrefix(endpoint.URL, "unix://") || strings.HasPrefix(endpoint.URL, "npipe://")) {
|
||||
|
||||
proxy, err := w.proxyManager.CreateComposeProxyServer(endpoint)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
defer proxy.Close()
|
||||
|
||||
options = append(options, "-H", fmt.Sprintf("http://127.0.0.1:%d", proxy.Port))
|
||||
}
|
||||
|
||||
args := append(options, command...)
|
||||
|
||||
var stderr bytes.Buffer
|
||||
cmd := exec.Command(program, args...)
|
||||
cmd.Stderr = &stderr
|
||||
|
||||
out, err := cmd.Output()
|
||||
if err != nil {
|
||||
return out, errors.New(stderr.String())
|
||||
}
|
||||
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func setComposeFile(stack *portainer.Stack) []string {
|
||||
options := make([]string, 0)
|
||||
|
||||
if stack == nil || stack.EntryPoint == "" {
|
||||
return options
|
||||
}
|
||||
|
||||
composeFilePath := path.Join(stack.ProjectPath, stack.EntryPoint)
|
||||
options = append(options, "-f", composeFilePath)
|
||||
return options
|
||||
}
|
||||
|
||||
func addProjectNameOption(options []string, stack *portainer.Stack) []string {
|
||||
if stack == nil || stack.Name == "" {
|
||||
return options
|
||||
}
|
||||
|
||||
options = append(options, "-p", stack.Name)
|
||||
return options
|
||||
}
|
||||
|
||||
func addEnvFileOption(options []string, stack *portainer.Stack) ([]string, error) {
|
||||
if stack == nil || stack.Env == nil || len(stack.Env) == 0 {
|
||||
return options, nil
|
||||
}
|
||||
|
||||
envFilePath := path.Join(stack.ProjectPath, "stack.env")
|
||||
|
||||
envfile, err := os.OpenFile(envFilePath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
|
||||
if err != nil {
|
||||
return options, err
|
||||
}
|
||||
|
||||
for _, v := range stack.Env {
|
||||
envfile.WriteString(fmt.Sprintf("%s=%s\n", v.Name, v.Value))
|
||||
}
|
||||
envfile.Close()
|
||||
|
||||
options = append(options, "--env-file", envFilePath)
|
||||
return options, nil
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue