mirror of
https://github.com/dokku/dokku.git
synced 2026-09-02 20:22:30 +02:00
This plugin is mostly compatible with the nginx plugin, but runs the proxy within a docker container. Users do not have direct access to add custom openresty configuration at this time, but instead receive the ability to setup automatic ssl on first request via letsencrypt integration.
160 lines
4.2 KiB
Go
160 lines
4.2 KiB
Go
package common
|
|
|
|
import (
|
|
"fmt"
|
|
"io/ioutil"
|
|
"os"
|
|
"os/exec"
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
"github.com/codeskyblue/go-sh"
|
|
)
|
|
|
|
// ShellCmd represents a shell command to be run for dokku
|
|
type ShellCmd struct {
|
|
Env map[string]string
|
|
Command *exec.Cmd
|
|
CommandString string
|
|
Args []string
|
|
ShowOutput bool
|
|
ExitError *exec.ExitError
|
|
}
|
|
|
|
// NewShellCmd returns a new ShellCmd struct
|
|
func NewShellCmd(command string) *ShellCmd {
|
|
items := strings.Split(command, " ")
|
|
cmd := items[0]
|
|
args := items[1:]
|
|
return NewShellCmdWithArgs(cmd, args...)
|
|
}
|
|
|
|
// NewShellCmdWithArgs returns a new ShellCmd struct
|
|
func NewShellCmdWithArgs(cmd string, args ...string) *ShellCmd {
|
|
commandString := strings.Join(append([]string{cmd}, args...), " ")
|
|
|
|
return &ShellCmd{
|
|
Command: exec.Command(cmd, args...),
|
|
CommandString: commandString,
|
|
Args: args,
|
|
ShowOutput: true,
|
|
}
|
|
}
|
|
|
|
func (sc *ShellCmd) setup() {
|
|
env := os.Environ()
|
|
for k, v := range sc.Env {
|
|
env = append(env, fmt.Sprintf("%s=%s", k, v))
|
|
}
|
|
sc.Command.Env = env
|
|
if sc.ShowOutput {
|
|
sc.Command.Stdout = os.Stdout
|
|
sc.Command.Stderr = os.Stderr
|
|
}
|
|
}
|
|
|
|
// Execute is a lightweight wrapper around exec.Command
|
|
func (sc *ShellCmd) Execute() bool {
|
|
sc.setup()
|
|
|
|
if err := sc.Command.Run(); err != nil {
|
|
exitError, ok := err.(*exec.ExitError)
|
|
if ok {
|
|
sc.ExitError = exitError
|
|
}
|
|
return false
|
|
}
|
|
return true
|
|
}
|
|
|
|
// Start is a wrapper around exec.Command.Start()
|
|
func (sc *ShellCmd) Start() error {
|
|
sc.setup()
|
|
|
|
return sc.Command.Start()
|
|
}
|
|
|
|
// Output is a lightweight wrapper around exec.Command.Output()
|
|
func (sc *ShellCmd) Output() ([]byte, error) {
|
|
sc.setup()
|
|
return sc.Command.Output()
|
|
}
|
|
|
|
// CombinedOutput is a lightweight wrapper around exec.Command.CombinedOutput()
|
|
func (sc *ShellCmd) CombinedOutput() ([]byte, error) {
|
|
sc.setup()
|
|
return sc.Command.CombinedOutput()
|
|
}
|
|
|
|
// PlugnTrigger fire the given plugn trigger with the given args
|
|
func PlugnTrigger(triggerName string, args ...string) error {
|
|
LogDebug(fmt.Sprintf("plugn trigger %s %v", triggerName, args))
|
|
return PlugnTriggerSetup(triggerName, args...).Run()
|
|
}
|
|
|
|
// PlugnTriggerOutput fire the given plugn trigger with the given args
|
|
func PlugnTriggerOutput(triggerName string, args ...string) ([]byte, error) {
|
|
LogDebug(fmt.Sprintf("plugn trigger %s %v", triggerName, args))
|
|
rE, wE, _ := os.Pipe()
|
|
rO, wO, _ := os.Pipe()
|
|
session := PlugnTriggerSetup(triggerName, args...)
|
|
session.Stderr = wE
|
|
session.Stdout = wO
|
|
err := session.Run()
|
|
wE.Close()
|
|
wO.Close()
|
|
|
|
readStderr, _ := ioutil.ReadAll(rE)
|
|
readStdout, _ := ioutil.ReadAll(rO)
|
|
|
|
stderr := string(readStderr[:])
|
|
if err != nil {
|
|
err = fmt.Errorf(stderr)
|
|
}
|
|
|
|
if os.Getenv("DOKKU_TRACE") == "1" {
|
|
for _, line := range strings.Split(stderr, "\n") {
|
|
LogDebug(fmt.Sprintf("plugn trigger %s stderr: %s", triggerName, line))
|
|
}
|
|
for _, line := range strings.Split(string(readStdout[:]), "\n") {
|
|
LogDebug(fmt.Sprintf("plugn trigger %s stdout: %s", triggerName, line))
|
|
}
|
|
}
|
|
|
|
return readStdout, err
|
|
}
|
|
|
|
// PlugnTriggerOutputAsString fires the given plugn trigger with the given args and returns the string contents instead of bytes
|
|
func PlugnTriggerOutputAsString(triggerName string, args ...string) (string, error) {
|
|
b, err := PlugnTriggerOutput(triggerName, args...)
|
|
return strings.TrimSpace(string(b[:])), err
|
|
}
|
|
|
|
// PlugnTriggerSetup sets up a plugn trigger call
|
|
func PlugnTriggerSetup(triggerName string, args ...string) *sh.Session {
|
|
shellArgs := make([]interface{}, len(args)+2)
|
|
shellArgs[0] = "trigger"
|
|
shellArgs[1] = triggerName
|
|
for i, arg := range args {
|
|
shellArgs[i+2] = arg
|
|
}
|
|
return sh.Command("plugn", shellArgs...)
|
|
}
|
|
|
|
// PlugnTriggerExists returns whether a plugin trigger exists (ignoring the existence of any within the 20_events plugin)
|
|
func PlugnTriggerExists(triggerName string) bool {
|
|
pluginPath := MustGetEnv("PLUGIN_PATH")
|
|
pluginPathPrefix := filepath.Join(pluginPath, "enabled")
|
|
glob := filepath.Join(pluginPathPrefix, "*", triggerName)
|
|
exists := false
|
|
files, _ := filepath.Glob(glob)
|
|
for _, file := range files {
|
|
plugin := strings.Trim(strings.TrimPrefix(strings.TrimSuffix(file, "/"+triggerName), pluginPathPrefix), "/")
|
|
if plugin != "20_events" {
|
|
exists = true
|
|
break
|
|
}
|
|
}
|
|
return exists
|
|
}
|