* 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> * refactor(stacks): use compose library * refactor(stacks): remove utils * chore(deps): pin docker-compose-wrapper * chore(build): simplify docker-compose build * chore(build): remove ps compose script * chore(deps): update docker-compose-wrapper * fix(compose): close proxy after command 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>
114 lines
2.9 KiB
Go
114 lines
2.9 KiB
Go
package exec
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"path"
|
|
"strings"
|
|
|
|
wrapper "github.com/portainer/docker-compose-wrapper"
|
|
|
|
portainer "github.com/portainer/portainer/api"
|
|
"github.com/portainer/portainer/api/http/proxy"
|
|
"github.com/portainer/portainer/api/http/proxy/factory"
|
|
)
|
|
|
|
// ComposeStackManager is a wrapper for docker-compose binary
|
|
type ComposeStackManager struct {
|
|
wrapper *wrapper.ComposeWrapper
|
|
proxyManager *proxy.Manager
|
|
}
|
|
|
|
// NewComposeStackManager returns a docker-compose wrapper if corresponding binary present, otherwise nil
|
|
func NewComposeStackManager(binaryPath string, proxyManager *proxy.Manager) (*ComposeStackManager, error) {
|
|
wrap, err := wrapper.NewComposeWrapper(binaryPath)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &ComposeStackManager{
|
|
wrapper: wrap,
|
|
proxyManager: proxyManager,
|
|
}, nil
|
|
}
|
|
|
|
// ComposeSyntaxMaxVersion returns the maximum supported version of the docker compose syntax
|
|
func (w *ComposeStackManager) ComposeSyntaxMaxVersion() string {
|
|
return portainer.ComposeSyntaxMaxVersion
|
|
}
|
|
|
|
// Up builds, (re)creates and starts containers in the background. Wraps `docker-compose up -d` command
|
|
func (w *ComposeStackManager) Up(stack *portainer.Stack, endpoint *portainer.Endpoint) error {
|
|
url, proxy, err := w.fetchEndpointProxy(endpoint)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if proxy != nil {
|
|
defer proxy.Close()
|
|
}
|
|
|
|
envFilePath, err := createEnvFile(stack)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
filePath := stackFilePath(stack)
|
|
|
|
_, err = w.wrapper.Up(filePath, url, stack.Name, envFilePath)
|
|
return err
|
|
}
|
|
|
|
// Down stops and removes containers, networks, images, and volumes. Wraps `docker-compose down --remove-orphans` command
|
|
func (w *ComposeStackManager) Down(stack *portainer.Stack, endpoint *portainer.Endpoint) error {
|
|
url, proxy, err := w.fetchEndpointProxy(endpoint)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if proxy != nil {
|
|
defer proxy.Close()
|
|
}
|
|
|
|
filePath := stackFilePath(stack)
|
|
|
|
_, err = w.wrapper.Down(filePath, url, stack.Name)
|
|
return err
|
|
}
|
|
|
|
func stackFilePath(stack *portainer.Stack) string {
|
|
return path.Join(stack.ProjectPath, stack.EntryPoint)
|
|
}
|
|
|
|
func (w *ComposeStackManager) fetchEndpointProxy(endpoint *portainer.Endpoint) (string, *factory.ProxyServer, error) {
|
|
if strings.HasPrefix(endpoint.URL, "unix://") || strings.HasPrefix(endpoint.URL, "npipe://") {
|
|
return "", nil, nil
|
|
}
|
|
|
|
proxy, err := w.proxyManager.CreateComposeProxyServer(endpoint)
|
|
if err != nil {
|
|
return "", nil, err
|
|
}
|
|
|
|
return fmt.Sprintf("http://127.0.0.1:%d", proxy.Port), proxy, nil
|
|
}
|
|
|
|
func createEnvFile(stack *portainer.Stack) (string, error) {
|
|
if stack.Env == nil || len(stack.Env) == 0 {
|
|
return "", 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 "", err
|
|
}
|
|
|
|
for _, v := range stack.Env {
|
|
envfile.WriteString(fmt.Sprintf("%s=%s\n", v.Name, v.Value))
|
|
}
|
|
envfile.Close()
|
|
|
|
return envFilePath, nil
|
|
}
|