forked from toolshed/abra
.gitea
cli
app
catalogue
internal
backup.go
cli.go
command.go
deploy.go
errors.go
list.go
recipe.go
validate.go
recipe
server
updater
cli.go
cmd
pkg
scripts
tests
.dockerignore
.drone.yml
.envrc.sample
.gitignore
.goreleaser.yml
AUTHORS.md
Dockerfile
LICENSE
Makefile
README.md
go.mod
go.sum
renovate.json
139 lines
3.5 KiB
Go
139 lines
3.5 KiB
Go
package internal
|
|
|
|
import (
|
|
"bufio"
|
|
"context"
|
|
"fmt"
|
|
"io/ioutil"
|
|
"os/exec"
|
|
"strings"
|
|
|
|
"coopcloud.tech/abra/pkg/config"
|
|
containerPkg "coopcloud.tech/abra/pkg/container"
|
|
"coopcloud.tech/abra/pkg/formatter"
|
|
"coopcloud.tech/abra/pkg/upstream/container"
|
|
"github.com/docker/cli/cli/command"
|
|
"github.com/docker/docker/api/types"
|
|
"github.com/docker/docker/api/types/filters"
|
|
dockerClient "github.com/docker/docker/client"
|
|
"github.com/docker/docker/pkg/archive"
|
|
"github.com/sirupsen/logrus"
|
|
)
|
|
|
|
// RunCmdRemote executes an abra.sh command in the target service
|
|
func RunCmdRemote(cl *dockerClient.Client, app config.App, abraSh, serviceName, cmdName, cmdArgs string) error {
|
|
filters := filters.NewArgs()
|
|
filters.Add("name", fmt.Sprintf("^%s_%s", app.StackName(), serviceName))
|
|
|
|
targetContainer, err := containerPkg.GetContainer(context.Background(), cl, filters, false)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
logrus.Debugf("retrieved %s as target container on %s", formatter.ShortenID(targetContainer.ID), app.Server)
|
|
|
|
toTarOpts := &archive.TarOptions{NoOverwriteDirNonDir: true, Compression: archive.Gzip}
|
|
content, err := archive.TarWithOptions(abraSh, toTarOpts)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
copyOpts := types.CopyToContainerOptions{AllowOverwriteDirWithFile: false, CopyUIDGID: false}
|
|
if err := cl.CopyToContainer(context.Background(), targetContainer.ID, "/tmp", content, copyOpts); err != nil {
|
|
return err
|
|
}
|
|
|
|
// FIXME: avoid instantiating a new CLI
|
|
dcli, err := command.NewDockerCli()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
shell := "/bin/bash"
|
|
findShell := []string{"test", "-e", shell}
|
|
execCreateOpts := types.ExecConfig{
|
|
AttachStderr: true,
|
|
AttachStdin: true,
|
|
AttachStdout: true,
|
|
Cmd: findShell,
|
|
Detach: false,
|
|
Tty: false,
|
|
}
|
|
|
|
if err := container.RunExec(dcli, cl, targetContainer.ID, &execCreateOpts); err != nil {
|
|
logrus.Infof("%s does not exist for %s, use /bin/sh as fallback", shell, app.Name)
|
|
shell = "/bin/sh"
|
|
}
|
|
|
|
var cmd []string
|
|
if cmdArgs != "" {
|
|
cmd = []string{shell, "-c", fmt.Sprintf("TARGET=%s; APP_NAME=%s; STACK_NAME=%s; . /tmp/abra.sh; %s %s", serviceName, app.Name, app.StackName(), cmdName, cmdArgs)}
|
|
} else {
|
|
cmd = []string{shell, "-c", fmt.Sprintf("TARGET=%s; APP_NAME=%s; STACK_NAME=%s; . /tmp/abra.sh; %s", serviceName, app.Name, app.StackName(), cmdName)}
|
|
}
|
|
|
|
logrus.Debugf("running command: %s", strings.Join(cmd, " "))
|
|
|
|
if RemoteUser != "" {
|
|
logrus.Debugf("running command with user %s", RemoteUser)
|
|
execCreateOpts.User = RemoteUser
|
|
}
|
|
|
|
execCreateOpts.Cmd = cmd
|
|
execCreateOpts.Tty = true
|
|
if Tty {
|
|
execCreateOpts.Tty = false
|
|
}
|
|
|
|
if err := container.RunExec(dcli, cl, targetContainer.ID, &execCreateOpts); err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func EnsureCommand(abraSh, recipeName, execCmd string) error {
|
|
bytes, err := ioutil.ReadFile(abraSh)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if !strings.Contains(string(bytes), execCmd) {
|
|
return fmt.Errorf("%s doesn't have a %s function", recipeName, execCmd)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// RunCmd runs a shell command and streams stdout/stderr in real-time.
|
|
func RunCmd(cmd *exec.Cmd) error {
|
|
r, err := cmd.StdoutPipe()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
cmd.Stderr = cmd.Stdout
|
|
done := make(chan struct{})
|
|
scanner := bufio.NewScanner(r)
|
|
|
|
go func() {
|
|
for scanner.Scan() {
|
|
line := scanner.Text()
|
|
fmt.Println(line)
|
|
}
|
|
done <- struct{}{}
|
|
}()
|
|
|
|
if err := cmd.Start(); err != nil {
|
|
return err
|
|
}
|
|
|
|
<-done
|
|
|
|
if err := cmd.Wait(); err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|