adjust CLI to runtime 0.2.0-alpha (#21)

* adjust CLI to runtime 0.2.0-alpha

* fix typo

* change to :latest image

* fix action-id to actions-id

* make runtime api version injectible

* remove redundant print
This commit is contained in:
Yaron Schneider 2019-07-25 11:13:04 -07:00 committed by GitHub
parent 4a499aecc6
commit d977e676d5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 180 additions and 74 deletions

View File

@ -3,7 +3,7 @@
################################################################################
GIT_VERSION = $(shell git describe --always --abbrev=7 --dirty)
TARGETS ?= darwin
TARGETS ?= darwin windows linux
ARCH ?= amd64
CGO ?= 0
@ -13,11 +13,11 @@ else
CLI_VERSION := edge
endif
################################################################################
# Go build details #
################################################################################
BASE_PACKAGE_NAME := github.com/actionscore/cli
ifdef API_VERSION
RUNTIME_API_VERSION = $(API_VERSION)
else
RUNTIME_API_VERSION = 1.0
endif
################################################################################
# Dependencies #
@ -41,7 +41,7 @@ deps: dep
build:
for t in $(TARGETS); do \
CGO_ENABLED=$(CGO) GOOS=$$t GOARCH=$(ARCH) go build \
-ldflags "-X $(BASE_PACKAGE_NAME)/pkg/version.version=$(CLI_VERSION)" \
-ldflags "-X main.version=$(CLI_VERSION) -X main.apiVersion=$(RUNTIME_API_VERSION)" \
-o dist/"$$t"_$(ARCH)/actions; \
done;

View File

@ -2,7 +2,7 @@
[![Build Status](https://dev.azure.com/azure-octo/Actions/_apis/build/status/builds/cli%20build?branchName=master)](https://dev.azure.com/azure-octo/Actions/_build/latest?definitionId=6&branchName=master)
The Actions CLI allows you to setup Actions on your local dev machine or on a Kubernetes cluster, provides debugging suppors, launches and manages Actions instances.
The Actions CLI allows you to setup Actions on your local dev machine or on a Kubernetes cluster, provides debugging support, launches and manages Actions instances.
## Setup
@ -12,6 +12,8 @@ The Actions CLI allows you to setup Actions on your local dev machine or on a Ku
### Usage
#### Install Actions
To setup Actions on your local machine:
__*Note: For Windows users, run the cmd terminal in administrator mode*__
@ -29,3 +31,80 @@ $ actions init --kubernetes
⌛ Making the jump to hyperspace...
✅ Success! Get ready to rumble
```
#### Launch Actions and your app
The Actions CLI lets you debug easily by launching both Actions and your app.
Logs from both the Actions Runtime and your app will be displayed in real time!
Example of launching Actions with a node app:
```
$ actions run --app-id nodeapp node app.js
```
Example of launching Actions with a node app listening on port 3000:
```
$ actions run --app-id nodeapp --app-port 3000 node app.js
```
Example of launching Actions on port 6000:
```
$ actions run --app-id nodeapp --app-port 3000 --port 6000 node app.js
```
#### Publish/Subscribe
To use pub-sub with your app, make sure that your app has a ```POST``` HTTP endpoint with some name, say ```myevent```.
This sample assumes your app is listening on port 3000.
Launch Actions and your app:
```
$ actions run --app-id nodeapp --app-port 3000 node app.js
```
Publish a message:
```
$ actions publish --app-id nodeapp --topic myevent
```
Publish a message with a payload:
```
$ actions publish --app-id nodeapp --topic myevent --payload '{ "name": "yoda" }'
```
#### Invoking
To test your endpoints with Actions, simply expose any ```POST``` HTTP endpoint.
For this sample, we'll assume a node app listening on port 300 with a ```/mymethod``` endpoint.
Launch Actions and your app:
```
$ actions run --app-id nodeapp --app-port 3000 node app.js
```
Invoke your app:
```
$ actions send --app-id nodeapp --method mymethod
```
#### List
To list all Actions instances running on your machine:
```
$ actions list
```
To list all Actions instances running in a Kubernetes cluster:
```
$ actions list --kubernetes
```

View File

@ -4,6 +4,7 @@ import (
"fmt"
"os"
"github.com/actionscore/cli/pkg/api"
"github.com/spf13/cobra"
)
@ -20,8 +21,9 @@ A serverless runtime for hyperscale, distributed systems`,
}
// Execute adds all child commands to the root command
func Execute(version string) {
func Execute(version, apiVersion string) {
RootCmd.Version = version
api.RuntimeAPIVersion = apiVersion
if err := RootCmd.Execute(); err != nil {
fmt.Println(err)

View File

@ -33,7 +33,7 @@ var RunCmd = &cobra.Command{
return
}
actionsRunId := uuid.String()
actionsRunID := uuid.String()
if kubernetesMode {
output, err := kubernetes.Run(&kubernetes.RunConfig{
@ -148,7 +148,7 @@ var RunCmd = &cobra.Command{
<-appRunning
rundata.AppendRunData(&rundata.RunData{
ActionsRunId: actionsRunId,
ActionsRunId: actionsRunID,
AppId: output.AppID,
ActionsPort: output.ActionsPort,
AppPort: appPort,
@ -161,7 +161,7 @@ var RunCmd = &cobra.Command{
<-sigCh
print.InfoStatusEvent(os.Stdout, "\nterminated signal recieved: shutting down")
rundata.ClearRunData(actionsRunId)
rundata.ClearRunData(actionsRunID)
err = output.ActionsCMD.Process.Kill()
if err != nil {

11
main.go
View File

@ -1,12 +1,15 @@
package main
import "github.com/actionscore/cli/cmd"
import (
"github.com/actionscore/cli/cmd"
)
// Value for version is injected by the build
// Values for version and apiVersion are injected by the build
var (
version = "edge"
version = ""
apiVersion = "1.0"
)
func main() {
cmd.Execute(version)
cmd.Execute(version, apiVersion)
}

6
pkg/api/api.go Normal file
View File

@ -0,0 +1,6 @@
package api
// RuntimeAPIVersion represents the version for the Actions runtime API
var (
RuntimeAPIVersion = "1.0"
)

View File

@ -27,13 +27,13 @@ func List() ([]ListOutput, error) {
l := []ListOutput{}
for _, p := range podList.Items {
for _, c := range p.Spec.Containers {
if c.Name == "action" {
if c.Name == "actionsrt" {
lo := ListOutput{}
for i, a := range c.Args {
if a == "--app-port" {
port := c.Args[i+1]
lo.AppPort = port
} else if a == "--action-id" {
} else if a == "--actions-id" {
id := c.Args[i+1]
lo.AppID = id
}

View File

@ -2,21 +2,14 @@ package publish
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"net/http"
"time"
"github.com/actionscore/cli/pkg/api"
"github.com/actionscore/cli/pkg/standalone"
)
type messageEnvelope struct {
Topic string `json:"topic,omitempty"`
Data interface{} `json:"data,omitempty"`
CreatedAt string `json:"createdAt"`
}
func PublishTopic(appID, topic, payload string) error {
if topic == "" {
return errors.New("topic is missing")
@ -31,26 +24,14 @@ func PublishTopic(appID, topic, payload string) error {
for _, lo := range l {
if lo.AppID == appID {
m := messageEnvelope{
CreatedAt: time.Now().Format(time.RFC3339),
}
b := []byte{}
if payload != "" {
var data interface{}
err := json.Unmarshal([]byte(payload), &data)
if err != nil {
return err
}
m.Data = data
b = []byte(payload)
}
b, err := json.Marshal(&m)
if err != nil {
return err
}
_, err = http.Post(fmt.Sprintf("http://localhost:%s/invoke/%s", fmt.Sprintf("%v", lo.ActionsPort), topic), "application/json", bytes.NewBuffer(b))
url := fmt.Sprintf("http://localhost:%s/v%s/publish/%s", fmt.Sprintf("%v", lo.ActionsPort), api.RuntimeAPIVersion, topic)
_, err = http.Post(url, "application/json", bytes.NewBuffer(b))
if err != nil {
return err
}

View File

@ -6,6 +6,8 @@ import (
"io/ioutil"
"net/http"
"github.com/actionscore/cli/pkg/api"
"github.com/actionscore/cli/pkg/standalone"
)
@ -17,7 +19,7 @@ func InvokeApp(appID, method, payload string) (string, error) {
for _, lo := range list {
if lo.AppID == appID {
r, err := http.Post(fmt.Sprintf("http://localhost:%s/invoke/%s", fmt.Sprintf("%v", lo.ActionsPort), method), "application/json", bytes.NewBuffer([]byte(payload)))
r, err := http.Post(fmt.Sprintf("http://localhost:%s/v%s/invoke/%s", fmt.Sprintf("%v", lo.ActionsPort), api.RuntimeAPIVersion, method), "application/json", bytes.NewBuffer([]byte(payload)))
if err != nil {
return "", err
}
@ -35,5 +37,5 @@ func InvokeApp(appID, method, payload string) (string, error) {
}
}
return "", fmt.Errorf("App id %s not found", appID)
return "", fmt.Errorf("App ID %s not found", appID)
}

View File

@ -30,18 +30,15 @@ type RunOutput struct {
AppCMD *exec.Cmd
}
type eventSource struct {
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 struct {
RedisHost string `json:"redisHost"`
RedisPassword string `json:"redisPassword"`
} `json:"connectionInfo"`
Type string `json:"type"`
ConnectionInfo map[string]string `json:"connectionInfo"`
} `json:"spec"`
}
@ -55,22 +52,22 @@ func getActionsCommand(appID string, actionsPort int, appPort int) (*exec.Cmd, i
actionsPort = port
}
actionsCMD := "action"
actionsCMD := "actionsrt"
if runtime.GOOS == "windows" {
actionsCMD = actionsCMD + ".exe"
actionsCMD = fmt.Sprintf("%s.exe", actionsCMD)
}
args := []string{"--action-id", appID, "--action-http-port", fmt.Sprintf("%v", actionsPort)}
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, "--assigner-address")
args = append(args, "--placement-address")
if runtime.GOOS == "windows" {
args = append(args, "localhost:6050")
args = append(args, "--action-grpc-port", "6051")
args = append(args, "--actions-grpc-port", "6051")
} else {
args = append(args, "localhost:50005")
}
@ -87,30 +84,61 @@ func getAppCommand(actionsPort int, command string, args []string) (*exec.Cmd, e
return cmd, nil
}
func createStateEventSource() error {
func createRedisStateStore() error {
wd, err := os.Getwd()
if err != nil {
return err
}
es := eventSource{
redisStore := component{
APIVersion: "actions.io/v1alpha1",
Kind: "EventSource",
Kind: "Component",
}
es.Metadata.Name = "statestore"
es.Spec.Type = "actions.state.redis"
es.Spec.ConnectionInfo.RedisHost = "localhost:6379"
es.Spec.ConnectionInfo.RedisPassword = ""
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(&es)
b, err := yaml.Marshal(&redisStore)
if err != nil {
return err
}
os.Mkdir(path.Join(wd, "eventsources"), 0777)
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
}
err = ioutil.WriteFile(path.Join(path.Join(wd, "eventsources"), "redis.yaml"), b, 0644)
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
}
@ -124,7 +152,12 @@ func Run(config *RunConfig) (*RunOutput, error) {
appID = strings.Replace(sillyname.GenerateStupidName(), " ", "-", -1)
}
err := createStateEventSource()
err := createRedisStateStore()
if err != nil {
return nil, err
}
err = createRedisPubSub()
if err != nil {
return nil, err
}

View File

@ -17,9 +17,7 @@ import (
)
const baseDownloadURL = "https://actionsreleases.blob.core.windows.net/bin"
// this should be configurable by versioning
const actionsImageURL = "yaron2/actionsedge:v2"
const actionsImageURL = "actionscore.azurecr.io/actions:latest"
func Init() error {
dir, err := getActionsDir()
@ -94,7 +92,7 @@ func installAssignerBinary(wg *sync.WaitGroup, errorChan chan<- error, dir strin
osPort = 6050
}
err := runCmd("docker", "run", "--restart", "always", "-d", "-p", fmt.Sprintf("%v:50005", osPort), "--entrypoint", "./assigner", actionsImageURL)
err := runCmd("docker", "run", "--restart", "always", "-d", "-p", fmt.Sprintf("%v:50005", osPort), "--entrypoint", "./placement", actionsImageURL)
if err != nil {
errorChan <- err
return
@ -105,7 +103,7 @@ func installAssignerBinary(wg *sync.WaitGroup, errorChan chan<- error, dir strin
func installActionsBinary(wg *sync.WaitGroup, errorChan chan<- error, dir string) {
defer wg.Done()
actionsURL := fmt.Sprintf("%s/action_%s_%s.zip", baseDownloadURL, runtime.GOOS, runtime.GOARCH)
actionsURL := fmt.Sprintf("%s/actionsrt_%s_%s.zip", baseDownloadURL, runtime.GOOS, runtime.GOARCH)
filepath, err := downloadFile(dir, actionsURL)
if err != nil {
errorChan <- fmt.Errorf("Error downloading actions binary: %s", err)
@ -200,10 +198,12 @@ func moveFileToPath(filepath string) (string, error) {
if runtime.GOOS == "windows" {
p := os.Getenv("PATH")
if !strings.Contains(strings.ToLower(string(p)), strings.ToLower("c:\\actions")) {
runCmd("SETX", "PATH", p+";c:\\actions")
err := runCmd("SETX", "PATH", p+";c:\\actions")
if err != nil {
return "", err
}
}
runCmd("rename", "c:\\actions\\action", "c:\\actions\\action.exe")
return "c:\\actions\\action.exe", nil
return "c:\\actions\\actionsrt.exe", nil
}
destFilePath = path.Join("/usr/local/bin", fileName)