cli/pkg/standalone/run.go

194 lines
4.0 KiB
Go

package standalone
import (
"errors"
"fmt"
"io/ioutil"
"os"
"os/exec"
"path"
"runtime"
"strings"
"gopkg.in/yaml.v2"
"github.com/Pallinder/sillyname-go"
"github.com/phayes/freeport"
)
type RunConfig struct {
AppID string
AppPort int
Port int
Arguments []string
}
type RunOutput struct {
ActionsCMD *exec.Cmd
ActionsPort int
AppID string
AppCMD *exec.Cmd
}
type component struct {
APIVersion string `json:"apiVersion"`
Kind string `json:"kind"`
Metadata struct {
Name string `json:"name"`
} `json:"metadata"`
Spec struct {
Type string `json:"type"`
ConnectionInfo map[string]string `json:"connectionInfo"`
} `json:"spec"`
}
func getActionsCommand(appID string, actionsPort int, appPort int) (*exec.Cmd, int, error) {
if actionsPort < 0 {
port, err := freeport.GetFreePort()
if err != nil {
return nil, -1, err
}
actionsPort = port
}
actionsCMD := "actionsrt"
if runtime.GOOS == "windows" {
actionsCMD = fmt.Sprintf("%s.exe", actionsCMD)
}
args := []string{"--actions-id", appID, "--actions-http-port", fmt.Sprintf("%v", actionsPort)}
if appPort > -1 {
args = append(args, "--app-port")
args = append(args, fmt.Sprintf("%v", appPort))
}
args = append(args, "--placement-address")
if runtime.GOOS == "windows" {
args = append(args, "localhost:6050")
args = append(args, "--actions-grpc-port", "6051")
} else {
args = append(args, "localhost:50005")
}
cmd := exec.Command(actionsCMD, args...)
return cmd, actionsPort, nil
}
func getAppCommand(actionsPort int, command string, args []string) (*exec.Cmd, error) {
cmd := exec.Command(command, args...)
cmd.Env = os.Environ()
cmd.Env = append(cmd.Env, fmt.Sprintf("ACTIONS_PORT=%v", actionsPort))
return cmd, nil
}
func createRedisStateStore() error {
wd, err := os.Getwd()
if err != nil {
return err
}
redisStore := component{
APIVersion: "actions.io/v1alpha1",
Kind: "Component",
}
redisStore.Metadata.Name = "statestore"
redisStore.Spec.Type = "state.redis"
redisStore.Spec.ConnectionInfo = map[string]string{}
redisStore.Spec.ConnectionInfo["redisHost"] = "localhost:6379"
redisStore.Spec.ConnectionInfo["redisPassword"] = ""
b, err := yaml.Marshal(&redisStore)
if err != nil {
return err
}
os.Mkdir(path.Join(wd, "components"), 0777)
err = ioutil.WriteFile(path.Join(path.Join(wd, "components"), "redis.yaml"), b, 0644)
if err != nil {
return err
}
return nil
}
func createRedisPubSub() error {
wd, err := os.Getwd()
if err != nil {
return err
}
redisMessageBus := component{
APIVersion: "actions.io/v1alpha1",
Kind: "Component",
}
redisMessageBus.Metadata.Name = "messagebus"
redisMessageBus.Spec.Type = "pubsub.redis"
redisMessageBus.Spec.ConnectionInfo = map[string]string{}
redisMessageBus.Spec.ConnectionInfo["redisHost"] = "localhost:6379"
redisMessageBus.Spec.ConnectionInfo["password"] = ""
b, err := yaml.Marshal(&redisMessageBus)
if err != nil {
return err
}
os.Mkdir(path.Join(wd, "components"), 0777)
err = ioutil.WriteFile(path.Join(path.Join(wd, "components"), "redis_messagebus.yaml"), b, 0644)
if err != nil {
return err
}
return nil
}
func Run(config *RunConfig) (*RunOutput, error) {
appID := config.AppID
if appID == "" {
appID = strings.Replace(sillyname.GenerateStupidName(), " ", "-", -1)
}
err := createRedisStateStore()
if err != nil {
return nil, err
}
err = createRedisPubSub()
if err != nil {
return nil, err
}
actionsCMD, actionsPort, err := getActionsCommand(appID, config.Port, config.AppPort)
if err != nil {
return nil, err
}
runArgs := []string{}
argCount := len(config.Arguments)
if argCount == 0 {
return nil, errors.New("No app entrypoint given")
}
cmd := config.Arguments[0]
if len(config.Arguments) > 1 {
runArgs = config.Arguments[1:]
}
appCMD, err := getAppCommand(actionsPort, cmd, runArgs)
if err != nil {
return nil, err
}
return &RunOutput{
ActionsCMD: actionsCMD,
AppCMD: appCMD,
AppID: appID,
ActionsPort: actionsPort,
}, nil
}