Merge branch 'frikky:launch' into launch

This commit is contained in:
Isoporhode
2021-10-30 17:56:21 +02:00
committed by GitHub
11 changed files with 549 additions and 58 deletions
+1 -1
View File
@@ -3846,7 +3846,7 @@ func runInitEs(ctx context.Context) {
//} //}
} else { } else {
log.Printf("[DEBUG] There are %d org(s).", len(activeOrgs)) log.Printf("[DEBUG] Found %d org(s) in total.", len(activeOrgs))
if len(activeOrgs) == 1 { if len(activeOrgs) == 1 {
if len(activeOrgs[0].Users) == 0 { if len(activeOrgs[0].Users) == 0 {
+54 -4
View File
@@ -569,7 +569,7 @@ func handleGetWorkflowqueueConfirm(resp http.ResponseWriter, request *http.Reque
// FIXME: Add authentication? // FIXME: Add authentication?
id := request.Header.Get("Org-Id") id := request.Header.Get("Org-Id")
if len(id) == 0 { if len(id) == 0 {
log.Printf("No Org-Id header set - confirm") log.Printf("[ERROR] No Org-Id header set - confirm")
resp.WriteHeader(401) resp.WriteHeader(401)
resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "Specify the org-id header."}`))) resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "Specify the org-id header."}`)))
return return
@@ -579,7 +579,7 @@ func handleGetWorkflowqueueConfirm(resp http.ResponseWriter, request *http.Reque
ctx := context.Background() ctx := context.Background()
executionRequests, err := shuffle.GetWorkflowQueue(ctx, id) executionRequests, err := shuffle.GetWorkflowQueue(ctx, id)
if err != nil { if err != nil {
log.Printf("(1) Failed reading body for workflowqueue: %s", err) log.Printf("[WARNING] (1) Failed reading body for workflowqueue: %s", err)
resp.WriteHeader(401) resp.WriteHeader(401)
resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "Entity parsing error - confirm"}`))) resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "Entity parsing error - confirm"}`)))
return return
@@ -676,6 +676,19 @@ func handleGetWorkflowqueue(resp http.ResponseWriter, request *http.Request) {
} }
ctx := context.Background() ctx := context.Background()
env, err := shuffle.GetEnvironment(ctx, id, "")
timeNow := time.Now().Unix()
if err == nil && len(env.Id) > 0 && len(env.Name) > 0 {
if time.Now().Unix() > env.Edited+60 {
env.RunningIp = request.RemoteAddr
env.Checkin = timeNow
err = shuffle.SetEnvironment(ctx, env)
if err != nil {
log.Printf("[WARNING] Failed updating environment: %s", err)
}
}
}
executionRequests, err := shuffle.GetWorkflowQueue(ctx, id) executionRequests, err := shuffle.GetWorkflowQueue(ctx, id)
if err != nil { if err != nil {
// Skipping as this comes up over and over // Skipping as this comes up over and over
@@ -685,11 +698,48 @@ func handleGetWorkflowqueue(resp http.ResponseWriter, request *http.Request) {
return return
} }
// Checking and updating the environment related to the first execution
if len(executionRequests.Data) == 0 { if len(executionRequests.Data) == 0 {
executionRequests.Data = []shuffle.ExecutionRequest{} executionRequests.Data = []shuffle.ExecutionRequest{}
} else { } else {
//log.Printf("[INFO] Executionrequests (%s): %d", id, len(executionRequests.Data)) //log.Printf("In workflowqueue with %d", len(executionRequests.Data))
//log.Printf("IDS: %#v", executionRequests.Data[0].ExecutionId)
// Try again :)
if len(env.Id) == 0 && len(env.Name) == 0 {
orgId := ""
for _, requestData := range executionRequests.Data {
execution, err := shuffle.GetWorkflowExecution(ctx, requestData.ExecutionId)
if err == nil {
if len(execution.ExecutionOrg) > 0 {
orgId = execution.ExecutionOrg
break
}
}
}
if len(orgId) > 0 {
env, err := shuffle.GetEnvironment(ctx, id, orgId)
if err != nil {
log.Printf("[WARNING] No env found matching %s - continuing without updating orborus anyway: %s", id, err)
//resp.WriteHeader(401)
//resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "No env found matching %s"}`, id)))
//return
} else {
if timeNow > env.Edited+60 {
env.RunningIp = request.RemoteAddr
env.Checkin = timeNow
err = shuffle.SetEnvironment(ctx, env)
if err != nil {
log.Printf("[WARNING] Failed updating environment: %s", err)
}
}
}
}
}
if len(executionRequests.Data) > 10 {
executionRequests.Data = executionRequests.Data[0:9]
}
} }
newjson, err := json.Marshal(executionRequests) newjson, err := json.Marshal(executionRequests)
+16 -8
View File
@@ -2717,7 +2717,7 @@ const Admin = (props) => {
style={{minWidth: 150, maxWidth: 150}} style={{minWidth: 150, maxWidth: 150}}
/> />
<ListItemText <ListItemText
primary="Orborus running (TBD)" primary="Orborus running"
style={{minWidth: 200, maxWidth: 200}} style={{minWidth: 200, maxWidth: 200}}
/> />
<ListItemText <ListItemText
@@ -2736,6 +2736,10 @@ const Admin = (props) => {
primary="Archived" primary="Archived"
style={{minWidth: 150, maxWidth: 150}} style={{minWidth: 150, maxWidth: 150}}
/> />
<ListItemText
primary="Last Changed"
style={{minWidth: 150, maxWidth: 150}}
/>
</ListItem> </ListItem>
{environments === undefined || environments === null ? null : environments.map((environment, index)=> { {environments === undefined || environments === null ? null : environments.map((environment, index)=> {
if (!showArchived && environment.archived) { if (!showArchived && environment.archived) {
@@ -2747,19 +2751,19 @@ const Admin = (props) => {
return null return null
} }
//var bgColor = "#27292d" var bgColor = "#27292d"
//if (index % 2 === 0) { if (index % 2 === 0) {
// bgColor = "#1f2023" bgColor = "#1f2023"
//} }
return ( return (
<ListItem key={index}> <ListItem key={index} style={{backgroundColor: bgColor}}>
<ListItemText <ListItemText
primary={environment.Name} primary={environment.Name}
style={{minWidth: 150, maxWidth: 150, overflow: "hidden"}} style={{minWidth: 150, maxWidth: 150, overflow: "hidden"}}
/> />
<ListItemText <ListItemText
primary={environment.Type === "cloud" ? "N/A" : "TBD"} primary={environment.Type !== "cloud" ? environment.running_ip === undefined || environment.running_ip === null || environment.running_ip.length === 0 ? "Not started" : environment.running_ip : "N/A"}
style={{minWidth: 200, maxWidth: 200, overflow: "hidden"}} style={{minWidth: 200, maxWidth: 200, overflow: "hidden"}}
/> />
<ListItemText <ListItemText
@@ -2786,6 +2790,10 @@ const Admin = (props) => {
style={{minWidth: 150, maxWidth: 150, overflow: "hidden"}} style={{minWidth: 150, maxWidth: 150, overflow: "hidden"}}
primary={environment.archived.toString()} primary={environment.archived.toString()}
/> />
<ListItemText
style={{minWidth: 150, maxWidth: 150, overflow: "hidden"}}
primary={environment.edited !== undefined && environment.edited !== null && environment.edited !== 0 ? new Date(environment.edited*1000).toISOString() : 0}
/>
</ListItem> </ListItem>
) )
})} })}
@@ -2907,7 +2915,7 @@ const Admin = (props) => {
style={{minWidth: 150, maxWidth: 150}} style={{minWidth: 150, maxWidth: 150}}
/> />
<ListItemText <ListItemText
primary="Orborus running (TBD)" primary="Orborus running"
style={{minWidth: 200, maxWidth: 200}} style={{minWidth: 200, maxWidth: 200}}
/> />
<ListItemText <ListItemText
+1
View File
@@ -7308,6 +7308,7 @@ const AngularWorkflow = (props) => {
<Button <Button
style={{borderRadius: "0px"}} style={{borderRadius: "0px"}}
variant="outlined" variant="outlined"
fullWidth
onClick={() => { onClick={() => {
getWorkflowExecution(props.match.params.key, "") getWorkflowExecution(props.match.params.key, "")
}} color="primary"> }} color="primary">
+7 -2
View File
@@ -370,8 +370,13 @@ const Apps = (props) => {
}} /> }} />
var newAppname = data.name var newAppname = data.name
newAppname = newAppname.charAt(0).toUpperCase()+newAppname.substring(1) if (newAppname === undefined) {
newAppname = newAppname.replaceAll("_", " ") newAppname = "Undefined"
} else {
newAppname = newAppname.charAt(0).toUpperCase()+newAppname.substring(1)
newAppname = newAppname.replaceAll("_", " ")
}
var sharing = "public" var sharing = "public"
if (!data.sharing) { if (!data.sharing) {
sharing = "private" sharing = "private"
+6 -4
View File
@@ -444,7 +444,7 @@ const Workflows = (props) => {
return return
} }
if (filters.includes(data)) { if (filters.includes(data) || filters.includes(data.toLowerCase())) {
return return
} }
@@ -1938,7 +1938,7 @@ const Workflows = (props) => {
}} color="primary"> }} color="primary">
{submitLoading ? {submitLoading ?
<CircularProgress /> <CircularProgress color="secondary" />
: :
"Submit" "Submit"
} }
@@ -2061,7 +2061,7 @@ const Workflows = (props) => {
<div style={flexContainerStyle}> <div style={flexContainerStyle}>
<div style={{...flexBoxStyle, ...activeWorkflowStyle}}> <div style={{...flexBoxStyle, ...activeWorkflowStyle}}>
<div style={flexContentStyle}> <div style={flexContentStyle}>
<div ><img src={mobileImage} style={iconStyle} /></div> <div><img src={mobileImage} style={iconStyle} /></div>
<div style={ blockRightStyle }> <div style={ blockRightStyle }>
<div style={counterStyle}>{workflows.length}</div> <div style={counterStyle}>{workflows.length}</div>
<div style={fontSize_16}>ACTIVE WORKFLOWS</div> <div style={fontSize_16}>ACTIVE WORKFLOWS</div>
@@ -2155,7 +2155,9 @@ const Workflows = (props) => {
}}> }}>
<Tooltip title={`Filter by ${data.app_name}`} placement="top"> <Tooltip title={`Filter by ${data.app_name}`} placement="top">
<Badge badgeContent={0} color="secondary" style={{fontSize: 10}}> <Badge badgeContent={0} color="secondary" style={{fontSize: 10}}>
<img style={{height: imgSize, width: imgSize, cursor: "pointer", borderRadius: imgSize/2, border: "2px solid rgba(255,255,255,0.7)"}} alt={data.app_name} src={data.large_image}/> <div style={{height: imgSize, width: imgSize, position: "relative", filter: "brightness(0.6)", backgroundColor: "#000", borderRadius: imgSize/2, zIndex: 100, overflow: "hidden", display: "flex", justifyContent: "center", }}>
<img style={{height: imgSize, width: imgSize, position: "absolute", top: -2, left: -2, cursor: "pointer", zIndex: 99, border: "2px solid rgba(255,255,255,0.7)", }} alt={data.app_name} src={data.large_image}/>
</div>
</Badge> </Badge>
</Tooltip> </Tooltip>
</IconButton> </IconButton>
+162 -8
View File
@@ -1,9 +1,11 @@
package main package main
/* /*
Orborus exists to listen for new workflow executions and deploy workers. Orborus exists to listen for new workflow executions whcih are deployed as workers.
*/ */
// frikky@debian:~/git/shuffle/functions/onprem/worker$ docker service create --replicas 5 --name shuffle-workers --env SHUFFLE_SWARM_CONFIG=run --publish published=33333,target=33333 ghcr.io/frikky/shuffle-worker:nightly
import ( import (
"github.com/shuffle/shuffle-shared" "github.com/shuffle/shuffle-shared"
@@ -23,6 +25,8 @@ import (
"github.com/docker/docker/api/types" "github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/container" "github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/mount"
"github.com/docker/docker/api/types/swarm"
//"github.com/docker/docker/api/types/filters" //"github.com/docker/docker/api/types/filters"
dockerclient "github.com/docker/docker/client" dockerclient "github.com/docker/docker/client"
"github.com/satori/go.uuid" "github.com/satori/go.uuid"
@@ -57,6 +61,7 @@ var runningMode = strings.ToLower(os.Getenv("RUNNING_MODE"))
var cleanupEnv = strings.ToLower(os.Getenv("CLEANUP")) var cleanupEnv = strings.ToLower(os.Getenv("CLEANUP"))
var timezone = os.Getenv("TZ") var timezone = os.Getenv("TZ")
var containerName = os.Getenv("ORBORUS_CONTAINER_NAME") var containerName = os.Getenv("ORBORUS_CONTAINER_NAME")
var swarmConfig = os.Getenv("SHUFFLE_SWARM_CONFIG")
var executionIds = []string{} var executionIds = []string{}
var dockercli *dockerclient.Client var dockercli *dockerclient.Client
@@ -129,7 +134,7 @@ func getThisContainerId() {
// Deploys the internal worker whenever something happens // Deploys the internal worker whenever something happens
// https://docs.docker.com/engine/api/sdk/examples/ // https://docs.docker.com/engine/api/sdk/examples/
func deployWorker(image string, identifier string, env []string) { func deployWorker(image string, identifier string, env []string, executionRequest shuffle.ExecutionRequest) {
// Binds is the actual "-v" volume. // Binds is the actual "-v" volume.
// Max 20% CPU every second // Max 20% CPU every second
@@ -157,6 +162,83 @@ func deployWorker(image string, identifier string, env []string) {
Env: env, Env: env,
} }
//var swarmConfig = os.Getenv("SHUFFLE_SWARM_CONFIG")
parsedUuid := uuid.NewV4()
if swarmConfig == "run" {
// frikky@debian:~/git/shuffle/functions/onprem/worker$ docker service create --replicas 5 --name shuffle-workers --env SHUFFLE_SWARM_CONFIG=run --publish published=33333,target=33333 ghcr.io/frikky/shuffle-worker:nightly
log.Printf("[DEBUG] Deploying containers with swarm")
//containerName := fmt.Sprintf("shuffle-worker-%s", parsedUuid)
containerName := fmt.Sprintf("shuffle-workers")
serviceSpec := swarm.ServiceSpec{
Annotations: swarm.Annotations{
Name: containerName,
Labels: map[string]string{},
},
EndpointSpec: &swarm.EndpointSpec{
Ports: []swarm.PortConfig{
swarm.PortConfig{
Protocol: swarm.PortConfigProtocolTCP,
PublishMode: swarm.PortConfigPublishModeIngress,
Name: "worker-port",
PublishedPort: 33333,
TargetPort: 33333,
},
},
},
TaskTemplate: swarm.TaskSpec{
Resources: &swarm.ResourceRequirements{
Reservations: &swarm.Resources{},
},
ContainerSpec: &swarm.ContainerSpec{
Image: image,
Env: []string{
fmt.Sprintf("SHUFFLE_SWARM_CONFIG=%s", os.Getenv("SHUFFLE_SWARM_CONFIG")),
},
Mounts: []mount.Mount{
mount.Mount{
Source: "/var/run/docker.sock",
Target: "/var/run/docker.sock",
Type: mount.TypeBind,
},
},
},
RestartPolicy: &swarm.RestartPolicy{
Condition: swarm.RestartPolicyConditionNone,
},
Placement: &swarm.Placement{
MaxReplicas: 1,
},
},
}
if dockerApiVersion != "" {
serviceSpec.TaskTemplate.ContainerSpec.Env = append(serviceSpec.TaskTemplate.ContainerSpec.Env, fmt.Sprintf("DOCKER_API_VERSION=%s", dockerApiVersion))
}
serviceOptions := types.ServiceCreateOptions{}
service, err := dockercli.ServiceCreate(
context.Background(),
serviceSpec,
serviceOptions,
)
if err == nil {
log.Printf("[DEBUG] Waiting 10 seconds for workers to come awake")
time.Sleep(time.Duration(10) * time.Second)
}
log.Printf("Servicecreate request: %#v %#v", service, err)
err = sendWorkerRequest(executionRequest)
if err != nil {
log.Printf("[ERROR] Failed worker request: %s", err)
} else {
log.Printf("[DEBUG] Started worker from request: %s - %#v - %s", containerName, service, err)
}
return
}
//log.Printf("[INFO] Identifier: %s", identifier) //log.Printf("[INFO] Identifier: %s", identifier)
cont, err := dockercli.ContainerCreate( cont, err := dockercli.ContainerCreate(
context.Background(), context.Background(),
@@ -169,8 +251,7 @@ func deployWorker(image string, identifier string, env []string) {
if err != nil { if err != nil {
if strings.Contains(fmt.Sprintf("%s", err), "Conflict. The container name ") { if strings.Contains(fmt.Sprintf("%s", err), "Conflict. The container name ") {
uuid := uuid.NewV4() identifier = fmt.Sprintf("%s-%s", identifier, parsedUuid)
identifier = fmt.Sprintf("%s-%s", identifier, uuid)
log.Printf("[INFO] 2 - Identifier: %s", identifier) log.Printf("[INFO] 2 - Identifier: %s", identifier)
cont, err = dockercli.ContainerCreate( cont, err = dockercli.ContainerCreate(
context.Background(), context.Background(),
@@ -212,7 +293,7 @@ func deployWorker(image string, identifier string, env []string) {
// return // return
// } // }
// err = deployWorker(cli, workerImage, containerName, env) // err = deployWorke(cli, workerImage, containerName, env)
// if err != nil { // if err != nil {
// log.Printf("Failed executing worker %s in state %s", execution.ExecutionId, containerStatus) // log.Printf("Failed executing worker %s in state %s", execution.ExecutionId, containerStatus)
// return // return
@@ -263,14 +344,16 @@ func initializeImages() {
if baseimageregistry == "" { if baseimageregistry == "" {
baseimageregistry = "docker.io" baseimageregistry = "docker.io"
baseimageregistry = "ghcr.io" baseimageregistry = "ghcr.io"
log.Printf("Setting baseimageregistry") log.Printf("[DEBUG] Setting baseimageregistry")
} }
if baseimagename == "" { if baseimagename == "" {
baseimagename = "frikky/shuffle" baseimagename = "frikky/shuffle"
baseimagename = "frikky" baseimagename = "frikky"
log.Printf("Setting baseimagename") log.Printf("[DEBUG] Setting baseimagename")
} }
log.Printf("[DEBUG] Setting swarm config to %#v. Default is empty.", swarmConfig)
// check whether they are the same first // check whether they are the same first
images := []string{ images := []string{
fmt.Sprintf("frikky/shuffle:app_sdk"), fmt.Sprintf("frikky/shuffle:app_sdk"),
@@ -569,6 +652,7 @@ func main() {
fmt.Sprintf("CLEANUP=%s", cleanupEnv), fmt.Sprintf("CLEANUP=%s", cleanupEnv),
fmt.Sprintf("TZ=%s", timezone), fmt.Sprintf("TZ=%s", timezone),
fmt.Sprintf("SHUFFLE_PASS_APP_PROXY=%s", os.Getenv("SHUFFLE_PASS_APP_PROXY")), fmt.Sprintf("SHUFFLE_PASS_APP_PROXY=%s", os.Getenv("SHUFFLE_PASS_APP_PROXY")),
fmt.Sprintf("SHUFFLE_SWARM_CONFIG=%s", os.Getenv("SHUFFLE_SWARM_CONFIG")),
} }
//log.Printf("Running worker with proxy? %s", os.Getenv("SHUFFLE_PASS_WORKER_PROXY")) //log.Printf("Running worker with proxy? %s", os.Getenv("SHUFFLE_PASS_WORKER_PROXY"))
@@ -581,7 +665,7 @@ func main() {
env = append(env, fmt.Sprintf("DOCKER_API_VERSION=%s", dockerApiVersion)) env = append(env, fmt.Sprintf("DOCKER_API_VERSION=%s", dockerApiVersion))
} }
go deployWorker(workerImage, containerName, env) go deployWorker(workerImage, containerName, env, execution)
log.Printf("[INFO] ExecutionID %s was deployed and to be removed from queue.", execution.ExecutionId) log.Printf("[INFO] ExecutionID %s was deployed and to be removed from queue.", execution.ExecutionId)
zombiecounter += 1 zombiecounter += 1
@@ -791,3 +875,73 @@ func zombiecheck(ctx context.Context, workerTimeout int) error {
return nil return nil
} }
type ExecutionRequest struct {
ExecutionId string `json:"execution_id"`
Authorization string `json:"authorization"`
HTTPProxy string `json:"http_proxy"`
HTTPSProxy string `json:"https_proxy"`
BaseUrl string `json:"base_url"`
EnvironmentName string `json:"environment_name"`
Timezone string `json:"timezone"`
Cleanup string `json:"cleanup"`
ShufflePassProxyToApp string `json:"shuffle_pass_proxy_to_app"`
}
func sendWorkerRequest(workflowExecution shuffle.ExecutionRequest) error {
parsedRequest := ExecutionRequest{
ExecutionId: workflowExecution.ExecutionId,
Authorization: workflowExecution.Authorization,
BaseUrl: os.Getenv("BASE_URL"),
EnvironmentName: os.Getenv("ENVIRONMENT_NAME"),
Timezone: os.Getenv("TZ"),
Cleanup: os.Getenv("CLEANUP"),
HTTPProxy: os.Getenv("HTTP_PROXY"),
HTTPSProxy: os.Getenv("HTTPS_PROXY"),
ShufflePassProxyToApp: os.Getenv("SHUFFLE_PASS_APP_PROXY"),
}
parsedBaseurl := baseUrl
if strings.Contains(baseUrl, ":") {
baseUrlSplit := strings.Split(baseUrl, ":")
if len(baseUrlSplit) >= 3 {
parsedBaseurl = strings.Join(baseUrlSplit[0:2], ":")
//parsedRequest.BaseUrl = fmt.Sprintf("%s:33333", parsedBaseurl)
}
}
data, err := json.Marshal(parsedRequest)
if err != nil {
log.Printf("[ERROR] Failed marshalling worker request: %s", err)
return err
}
streamUrl := fmt.Sprintf("%s:33333/api/v1/execute", parsedBaseurl)
req, err := http.NewRequest(
"POST",
streamUrl,
bytes.NewBuffer([]byte(data)),
)
client := &http.Client{}
if err != nil {
log.Printf("[ERROR] Failed creating finishing request: %s", err)
return err
}
newresp, err := client.Do(req)
if err != nil {
log.Printf("[ERROR] Error running finishing request: %s", err)
return err
}
body, err := ioutil.ReadAll(newresp.Body)
if err != nil {
log.Printf("[ERROR] Failed reading body: %s", err)
return err
} else {
log.Printf("[INFO] NEWRESP (from backend): %s", string(body))
}
return nil
}
+1 -1
View File
@@ -1,5 +1,5 @@
NAME=shuffle-worker NAME=shuffle-worker
VERSION=0.9.28 VERSION=0.9.29
echo "Running docker build with $NAME:$VERSION" echo "Running docker build with $NAME:$VERSION"
#CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o worker.bin . #CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o worker.bin .
+1 -1
View File
@@ -8,6 +8,6 @@ require (
github.com/docker/go-connections v0.4.0 // indirect github.com/docker/go-connections v0.4.0 // indirect
github.com/gorilla/mux v1.8.0 github.com/gorilla/mux v1.8.0
github.com/patrickmn/go-cache v2.1.0+incompatible github.com/patrickmn/go-cache v2.1.0+incompatible
github.com/shuffle/shuffle-shared v0.1.19 github.com/shuffle/shuffle-shared v0.1.20
go4.org v0.0.0-20201209231011-d4a079459e60 // indirect go4.org v0.0.0-20201209231011-d4a079459e60 // indirect
) )
+2
View File
@@ -571,6 +571,8 @@ github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdh
github.com/seccomp/libseccomp-golang v0.9.1/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvWlF4P2Ca7zGrPiEpWo= github.com/seccomp/libseccomp-golang v0.9.1/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvWlF4P2Ca7zGrPiEpWo=
github.com/shuffle/shuffle-shared v0.1.19 h1:bZmwdC3gKPFxtKoGEjHGY8C96+xB+cBdHaz6glP8SwA= github.com/shuffle/shuffle-shared v0.1.19 h1:bZmwdC3gKPFxtKoGEjHGY8C96+xB+cBdHaz6glP8SwA=
github.com/shuffle/shuffle-shared v0.1.19/go.mod h1:0QrK51T12CpCj/be8hXduj/RtDnoeaZ3rfogELZE2IU= github.com/shuffle/shuffle-shared v0.1.19/go.mod h1:0QrK51T12CpCj/be8hXduj/RtDnoeaZ3rfogELZE2IU=
github.com/shuffle/shuffle-shared v0.1.20 h1:Wz3DZtFtsd/F3rQuZ4KpIURM2HT1jPwEF3eJg8MX9TE=
github.com/shuffle/shuffle-shared v0.1.20/go.mod h1:0QrK51T12CpCj/be8hXduj/RtDnoeaZ3rfogELZE2IU=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/sirupsen/logrus v1.0.4-0.20170822132746-89742aefa4b2/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= github.com/sirupsen/logrus v1.0.4-0.20170822132746-89742aefa4b2/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc=
github.com/sirupsen/logrus v1.0.6/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= github.com/sirupsen/logrus v1.0.6/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc=
+298 -29
View File
@@ -31,6 +31,7 @@ import (
"github.com/gorilla/mux" "github.com/gorilla/mux"
"github.com/patrickmn/go-cache" "github.com/patrickmn/go-cache"
"github.com/satori/go.uuid"
) )
// This is getting out of hand :) // This is getting out of hand :)
@@ -59,6 +60,8 @@ var startAction string
var results []shuffle.ActionResult var results []shuffle.ActionResult
var allLogs map[string]string var allLogs map[string]string
var executionRunning bool
// removes every container except itself (worker) // removes every container except itself (worker)
func shutdown(workflowExecution shuffle.WorkflowExecution, nodeId string, reason string, handleResultSend bool) { func shutdown(workflowExecution shuffle.WorkflowExecution, nodeId string, reason string, handleResultSend bool) {
log.Printf("[INFO] Shutdown (%s) started with reason %#v. Result amount: %d. ResultsSent: %d, Send result: %#v", workflowExecution.Status, reason, len(workflowExecution.Results), requestsSent, handleResultSend) log.Printf("[INFO] Shutdown (%s) started with reason %#v. Result amount: %d. ResultsSent: %d, Send result: %#v", workflowExecution.Status, reason, len(workflowExecution.Results), requestsSent, handleResultSend)
@@ -168,8 +171,25 @@ func shutdown(workflowExecution shuffle.WorkflowExecution, nodeId string, reason
//Finished shutdown (after %d seconds). ", sleepDuration) //Finished shutdown (after %d seconds). ", sleepDuration)
// Allows everything to finish in subprocesses (apps) // Allows everything to finish in subprocesses (apps)
time.Sleep(time.Duration(sleepDuration) * time.Second) if os.Getenv("SHUFFLE_SWARM_CONFIG") != "run" {
os.Exit(3) time.Sleep(time.Duration(sleepDuration) * time.Second)
os.Exit(3)
} else {
log.Printf("[DEBUG] Sending result and resetting values (K8s & Swarm).")
environments = []string{}
parents = map[string][]string{}
children = map[string][]string{}
visited = []string{}
executed = []string{}
nextActions = []string{}
containerIds = []string{}
extra = 0
startAction = ""
results = []shuffle.ActionResult{}
allLogs = map[string]string{}
executionRunning = false
}
//cacheKey := fmt.Sprintf("workflowexecution-%s", workflowExecution.ExecutionId)
} }
// Deploys the internal worker whenever something happens // Deploys the internal worker whenever something happens
@@ -186,8 +206,12 @@ func deployApp(cli *dockerclient.Client, image string, identifier string, env []
Type: "json-file", Type: "json-file",
Config: map[string]string{}, Config: map[string]string{},
}, },
Resources: container.Resources{}, Resources: container.Resources{},
NetworkMode: container.NetworkMode(fmt.Sprintf("container:worker-%s", workflowExecution.ExecutionId)), }
if os.Getenv("SHUFFLE_SWARM_CONFIG") != "run" {
hostConfig.NetworkMode = container.NetworkMode(fmt.Sprintf("container:worker-%s", workflowExecution.ExecutionId))
log.Printf("Environments: %#v", env)
} }
// Removing because log extraction should happen first // Removing because log extraction should happen first
@@ -223,8 +247,6 @@ func deployApp(cli *dockerclient.Client, image string, identifier string, env []
} else { } else {
log.Printf("[WARNING] No mounted folders") log.Printf("[WARNING] No mounted folders")
} }
// hostConfig.Binds = volumeBinds
//}
config := &container.Config{ config := &container.Config{
Image: image, Image: image,
@@ -241,11 +263,29 @@ func deployApp(cli *dockerclient.Client, image string, identifier string, env []
) )
if err != nil { if err != nil {
//log.Printf("[ERROR] Failed creating container: %s", err)
if !strings.Contains(err.Error(), "Conflict. The container name") { if !strings.Contains(err.Error(), "Conflict. The container name") {
log.Printf("[ERROR] Container CREATE error: %s", err) log.Printf("[ERROR] Container CREATE error (1): %s", err)
}
return err return err
} else {
parsedUuid := uuid.NewV4()
identifier = fmt.Sprintf("%s-%s", identifier, parsedUuid)
log.Printf("[INFO] 2 - Identifier: %s", identifier)
cont, err = cli.ContainerCreate(
context.Background(),
config,
hostConfig,
nil,
nil,
identifier,
)
if err != nil {
log.Printf("[ERROR] Container create error (2): %s", err)
return err
}
}
} }
err = cli.ContainerStart(ctx, cont.ID, types.ContainerStartOptions{}) err = cli.ContainerStart(ctx, cont.ID, types.ContainerStartOptions{})
@@ -294,12 +334,14 @@ func deployApp(cli *dockerclient.Client, image string, identifier string, env []
} }
if exit { if exit {
log.Printf("ERROR IN CONTAINER DEPLOYMENT - ITS EXITED!") log.Printf("[DEBUG] ERROR IN CONTAINER DEPLOYMENT - ITS EXITED!")
return errors.New(fmt.Sprintf(`{"success": false, "reason": "Container %s exited prematurely.","debug": "docker logs -f %s"}`, cont.ID, cont.ID)) return errors.New(fmt.Sprintf(`{"success": false, "reason": "Container %s exited prematurely.","debug": "docker logs -f %s"}`, cont.ID, cont.ID))
} }
} }
} }
log.Printf("[DEBUG] Deployed container ID %s", cont.ID)
/* /*
//log.Printf("%#v", stats.Config.Status) //log.Printf("%#v", stats.Config.Status)
//ContainerJSONtoConfig(cj dockType.ContainerJSON) ContainerConfig { //ContainerJSONtoConfig(cj dockType.ContainerJSON) ContainerConfig {
@@ -770,10 +812,10 @@ func handleExecutionResult(workflowExecution shuffle.WorkflowExecution) {
err = runUserInput(topClient, action, workflowExecution.Workflow.ID, workflowExecution.ExecutionId, workflowExecution.Authorization, string(triggerData)) err = runUserInput(topClient, action, workflowExecution.Workflow.ID, workflowExecution.ExecutionId, workflowExecution.Authorization, string(triggerData))
if err != nil { if err != nil {
log.Printf("Failed launching backend magic: %s", err) log.Printf("[ERROR] Failed launching backend magic: %s", err)
os.Exit(3) os.Exit(3)
} else { } else {
log.Printf("Launched user input node succesfully!") log.Printf("[INFO] Launched user input node succesfully!")
os.Exit(3) os.Exit(3)
} }
@@ -880,7 +922,7 @@ func handleExecutionResult(workflowExecution shuffle.WorkflowExecution) {
if err != nil || stats.ContainerJSONBase.State.Status != "running" { if err != nil || stats.ContainerJSONBase.State.Status != "running" {
// REMOVE // REMOVE
if err == nil { if err == nil {
log.Printf("Status: %s, should kill: %s", stats.ContainerJSONBase.State.Status, identifier) log.Printf("[DEBUG] Status: %s, should kill: %s", stats.ContainerJSONBase.State.Status, identifier)
err = removeContainer(identifier) err = removeContainer(identifier)
if err != nil { if err != nil {
log.Printf("Error killing container: %s", err) log.Printf("Error killing container: %s", err)
@@ -906,19 +948,19 @@ func handleExecutionResult(workflowExecution shuffle.WorkflowExecution) {
actionData, err := json.Marshal(action) actionData, err := json.Marshal(action)
if err != nil { if err != nil {
log.Printf("Failed unmarshalling action: %s", err) log.Printf("[WARNING] Failed unmarshalling action: %s", err)
continue continue
} }
if action.AppID == "0ca8887e-b4af-4e3e-887c-87e9d3bc3d3e" { if action.AppID == "0ca8887e-b4af-4e3e-887c-87e9d3bc3d3e" {
log.Printf("\nShould run filter: %#v\n\n", action) log.Printf("[DEBUG] Should run filter: %#v\n\n", action)
runFilter(workflowExecution, action) runFilter(workflowExecution, action)
continue continue
} }
executionData, err := json.Marshal(workflowExecution) executionData, err := json.Marshal(workflowExecution)
if err != nil { if err != nil {
log.Printf("Failed marshalling executiondata: %s", err) log.Printf("[ERROR] Failed marshalling executiondata: %s", err)
executionData = []byte("") executionData = []byte("")
} }
@@ -942,7 +984,7 @@ func handleExecutionResult(workflowExecution shuffle.WorkflowExecution) {
} }
// Fixes issue: // Fixes issue:
// standard_init_linux.go:185: exec user process caused "argument list too long" // standard_go init_linux.go:185: exec user process caused "argument list too long"
// https://devblogs.microsoft.com/oldnewthing/20100203-00/?p=15083 // https://devblogs.microsoft.com/oldnewthing/20100203-00/?p=15083
// FIXME: Ensure to NEVER do this anymore // FIXME: Ensure to NEVER do this anymore
@@ -976,6 +1018,7 @@ func handleExecutionResult(workflowExecution shuffle.WorkflowExecution) {
if strings.Contains(err.Error(), "exited prematurely") { if strings.Contains(err.Error(), "exited prematurely") {
log.Printf("[DEBUG] Shutting down (2)") log.Printf("[DEBUG] Shutting down (2)")
shutdown(workflowExecution, action.ID, fmt.Sprintf("%s", err.Error()), true) shutdown(workflowExecution, action.ID, fmt.Sprintf("%s", err.Error()), true)
return
} }
err := downloadDockerImageBackend(topClient, image) err := downloadDockerImageBackend(topClient, image)
@@ -988,6 +1031,7 @@ func handleExecutionResult(workflowExecution shuffle.WorkflowExecution) {
if strings.Contains(err.Error(), "exited prematurely") { if strings.Contains(err.Error(), "exited prematurely") {
log.Printf("[DEBUG] Shutting down (41)") log.Printf("[DEBUG] Shutting down (41)")
shutdown(workflowExecution, action.ID, fmt.Sprintf("%s", err.Error()), true) shutdown(workflowExecution, action.ID, fmt.Sprintf("%s", err.Error()), true)
return
} }
} else { } else {
executed = true executed = true
@@ -1001,6 +1045,7 @@ func handleExecutionResult(workflowExecution shuffle.WorkflowExecution) {
if strings.Contains(err.Error(), "exited prematurely") { if strings.Contains(err.Error(), "exited prematurely") {
log.Printf("[DEBUG] Shutting down (3)") log.Printf("[DEBUG] Shutting down (3)")
shutdown(workflowExecution, action.ID, fmt.Sprintf("%s", err.Error()), true) shutdown(workflowExecution, action.ID, fmt.Sprintf("%s", err.Error()), true)
return
} }
//log.Printf("[WARNING] Failed CLEANUP execution. Downloading image %s remotely.", image) //log.Printf("[WARNING] Failed CLEANUP execution. Downloading image %s remotely.", image)
@@ -1012,6 +1057,7 @@ func handleExecutionResult(workflowExecution shuffle.WorkflowExecution) {
log.Printf("[ERROR] Failed getting %s. Couldn't be find locally, AND is missing.", image) log.Printf("[ERROR] Failed getting %s. Couldn't be find locally, AND is missing.", image)
log.Printf("[DEBUG] Shutting down (4)") log.Printf("[DEBUG] Shutting down (4)")
shutdown(workflowExecution, action.ID, fmt.Sprintf("%s", err.Error()), true) shutdown(workflowExecution, action.ID, fmt.Sprintf("%s", err.Error()), true)
return
} }
buildBuf := new(strings.Builder) buildBuf := new(strings.Builder)
@@ -1020,11 +1066,13 @@ func handleExecutionResult(workflowExecution shuffle.WorkflowExecution) {
log.Printf("[ERROR] Error in IO copy: %s", err) log.Printf("[ERROR] Error in IO copy: %s", err)
log.Printf("[DEBUG] Shutting down (5)") log.Printf("[DEBUG] Shutting down (5)")
shutdown(workflowExecution, action.ID, fmt.Sprintf("%s", err.Error()), true) shutdown(workflowExecution, action.ID, fmt.Sprintf("%s", err.Error()), true)
return
} else { } else {
if strings.Contains(buildBuf.String(), "errorDetail") { if strings.Contains(buildBuf.String(), "errorDetail") {
log.Printf("[ERROR] Docker build:\n%s\nERROR ABOVE: Trying to pull tags from: %s", buildBuf.String(), image) log.Printf("[ERROR] Docker build:\n%s\nERROR ABOVE: Trying to pull tags from: %s", buildBuf.String(), image)
log.Printf("[DEBUG] Shutting down (6)") log.Printf("[DEBUG] Shutting down (6)")
shutdown(workflowExecution, action.ID, fmt.Sprintf("%s", err.Error()), true) shutdown(workflowExecution, action.ID, fmt.Sprintf("%s", err.Error()), true)
return
} }
log.Printf("[INFO] Successfully downloaded %s", image) log.Printf("[INFO] Successfully downloaded %s", image)
@@ -1037,6 +1085,7 @@ func handleExecutionResult(workflowExecution shuffle.WorkflowExecution) {
if strings.Contains(err.Error(), "exited prematurely") { if strings.Contains(err.Error(), "exited prematurely") {
log.Printf("[DEBUG] Shutting down (7)") log.Printf("[DEBUG] Shutting down (7)")
shutdown(workflowExecution, action.ID, fmt.Sprintf("%s", err.Error()), true) shutdown(workflowExecution, action.ID, fmt.Sprintf("%s", err.Error()), true)
return
} }
if strings.Contains(err.Error(), "No such image") { if strings.Contains(err.Error(), "No such image") {
@@ -1044,6 +1093,7 @@ func handleExecutionResult(workflowExecution shuffle.WorkflowExecution) {
log.Printf("[ERROR] Image doesn't exist. Shutting down") log.Printf("[ERROR] Image doesn't exist. Shutting down")
log.Printf("[DEBUG] Shutting down (8)") log.Printf("[DEBUG] Shutting down (8)")
shutdown(workflowExecution, action.ID, fmt.Sprintf("%s", err.Error()), true) shutdown(workflowExecution, action.ID, fmt.Sprintf("%s", err.Error()), true)
return
} }
} }
} }
@@ -1056,6 +1106,7 @@ func handleExecutionResult(workflowExecution shuffle.WorkflowExecution) {
if strings.Contains(err.Error(), "exited prematurely") { if strings.Contains(err.Error(), "exited prematurely") {
log.Printf("[DEBUG] Shutting down (9)") log.Printf("[DEBUG] Shutting down (9)")
shutdown(workflowExecution, action.ID, fmt.Sprintf("%s", err.Error()), true) shutdown(workflowExecution, action.ID, fmt.Sprintf("%s", err.Error()), true)
return
} }
// Trying to replace with lowercase to deploy again. This seems to work with Dockerhub well. // Trying to replace with lowercase to deploy again. This seems to work with Dockerhub well.
@@ -1066,6 +1117,7 @@ func handleExecutionResult(workflowExecution shuffle.WorkflowExecution) {
if strings.Contains(err.Error(), "exited prematurely") { if strings.Contains(err.Error(), "exited prematurely") {
log.Printf("[DEBUG] Shutting down (10)") log.Printf("[DEBUG] Shutting down (10)")
shutdown(workflowExecution, action.ID, fmt.Sprintf("%s", err.Error()), true) shutdown(workflowExecution, action.ID, fmt.Sprintf("%s", err.Error()), true)
return
} }
log.Printf("[DEBUG] Failed deploy. Downloading image %s", image) log.Printf("[DEBUG] Failed deploy. Downloading image %s", image)
@@ -1079,6 +1131,7 @@ func handleExecutionResult(workflowExecution shuffle.WorkflowExecution) {
if strings.Contains(err.Error(), "exited prematurely") { if strings.Contains(err.Error(), "exited prematurely") {
log.Printf("[DEBUG] Shutting down (40)") log.Printf("[DEBUG] Shutting down (40)")
shutdown(workflowExecution, action.ID, fmt.Sprintf("%s", err.Error()), true) shutdown(workflowExecution, action.ID, fmt.Sprintf("%s", err.Error()), true)
return
} }
} else { } else {
executed = true executed = true
@@ -1092,6 +1145,7 @@ func handleExecutionResult(workflowExecution shuffle.WorkflowExecution) {
if strings.Contains(err.Error(), "exited prematurely") { if strings.Contains(err.Error(), "exited prematurely") {
log.Printf("[DEBUG] Shutting down (11)") log.Printf("[DEBUG] Shutting down (11)")
shutdown(workflowExecution, action.ID, fmt.Sprintf("%s", err.Error()), true) shutdown(workflowExecution, action.ID, fmt.Sprintf("%s", err.Error()), true)
return
} }
log.Printf("[WARNING] Failed deploying image THREE TIMES. Attempting to download %s as last resort from backend and dockerhub.", image) log.Printf("[WARNING] Failed deploying image THREE TIMES. Attempting to download %s as last resort from backend and dockerhub.", image)
@@ -1101,6 +1155,7 @@ func handleExecutionResult(workflowExecution shuffle.WorkflowExecution) {
log.Printf("[ERROR] Failed getting %s. The couldn't be find locally, AND is missing.", image) log.Printf("[ERROR] Failed getting %s. The couldn't be find locally, AND is missing.", image)
log.Printf("[DEBUG] Shutting down (12)") log.Printf("[DEBUG] Shutting down (12)")
shutdown(workflowExecution, action.ID, fmt.Sprintf("%s", err.Error()), true) shutdown(workflowExecution, action.ID, fmt.Sprintf("%s", err.Error()), true)
return
} }
buildBuf := new(strings.Builder) buildBuf := new(strings.Builder)
@@ -1109,11 +1164,13 @@ func handleExecutionResult(workflowExecution shuffle.WorkflowExecution) {
log.Printf("[ERROR] Error in IO copy: %s", err) log.Printf("[ERROR] Error in IO copy: %s", err)
log.Printf("[DEBUG] Shutting down (13)") log.Printf("[DEBUG] Shutting down (13)")
shutdown(workflowExecution, action.ID, fmt.Sprintf("%s", err.Error()), true) shutdown(workflowExecution, action.ID, fmt.Sprintf("%s", err.Error()), true)
return
} else { } else {
if strings.Contains(buildBuf.String(), "errorDetail") { if strings.Contains(buildBuf.String(), "errorDetail") {
log.Printf("[ERROR] Docker build:\n%s\nERROR ABOVE: Trying to pull tags from: %s", buildBuf.String(), image) log.Printf("[ERROR] Docker build:\n%s\nERROR ABOVE: Trying to pull tags from: %s", buildBuf.String(), image)
log.Printf("[DEBUG] Shutting down (14)") log.Printf("[DEBUG] Shutting down (14)")
shutdown(workflowExecution, action.ID, fmt.Sprintf("Error deploying container: %s", buildBuf.String()), true) shutdown(workflowExecution, action.ID, fmt.Sprintf("Error deploying container: %s", buildBuf.String()), true)
return
} }
log.Printf("[INFO] Successfully downloaded %s", image) log.Printf("[INFO] Successfully downloaded %s", image)
@@ -1126,6 +1183,7 @@ func handleExecutionResult(workflowExecution shuffle.WorkflowExecution) {
if strings.Contains(err.Error(), "exited prematurely") { if strings.Contains(err.Error(), "exited prematurely") {
log.Printf("[DEBUG] Shutting down (15)") log.Printf("[DEBUG] Shutting down (15)")
shutdown(workflowExecution, action.ID, fmt.Sprintf("%s", err.Error()), true) shutdown(workflowExecution, action.ID, fmt.Sprintf("%s", err.Error()), true)
return
} }
if strings.Contains(err.Error(), "No such image") { if strings.Contains(err.Error(), "No such image") {
@@ -1133,6 +1191,7 @@ func handleExecutionResult(workflowExecution shuffle.WorkflowExecution) {
log.Printf("[ERROR] Image doesn't exist. Shutting down") log.Printf("[ERROR] Image doesn't exist. Shutting down")
log.Printf("[DEBUG] Shutting down (16)") log.Printf("[DEBUG] Shutting down (16)")
shutdown(workflowExecution, action.ID, fmt.Sprintf("%s", err.Error()), true) shutdown(workflowExecution, action.ID, fmt.Sprintf("%s", err.Error()), true)
return
} }
} }
} }
@@ -1174,6 +1233,7 @@ func handleExecutionResult(workflowExecution shuffle.WorkflowExecution) {
validateFinished(workflowExecution) validateFinished(workflowExecution)
log.Printf("[DEBUG] Shutting down (17)") log.Printf("[DEBUG] Shutting down (17)")
shutdown(workflowExecution, "", "", true) shutdown(workflowExecution, "", "", true)
return
} }
} }
@@ -1597,7 +1657,7 @@ func handleWorkflowQueue(resp http.ResponseWriter, request *http.Request) {
} }
if workflowExecution.Status == "FINISHED" { if workflowExecution.Status == "FINISHED" {
log.Printf("Workflowexecution is already FINISHED. No further action can be taken") log.Printf("[DEBUG] Workflowexecution is already FINISHED. No further action can be taken")
resp.WriteHeader(401) resp.WriteHeader(401)
resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "Workflowexecution is already finished because it has status %s"}`, workflowExecution.LastNode, workflowExecution.Status))) resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "Workflowexecution is already finished because it has status %s"}`, workflowExecution.LastNode, workflowExecution.Status)))
return return
@@ -1734,7 +1794,7 @@ func getWorkflowExecution(ctx context.Context, id string) (*shuffle.WorkflowExec
} }
func sendResult(workflowExecution shuffle.WorkflowExecution, data []byte) { func sendResult(workflowExecution shuffle.WorkflowExecution, data []byte) {
if workflowExecution.ExecutionSource == "default" { if workflowExecution.ExecutionSource == "default" && os.Getenv("SHUFFLE_SWARM_CONFIG") != "run" {
log.Printf("[INFO] Not sending backend info since source is default") log.Printf("[INFO] Not sending backend info since source is default")
return return
} }
@@ -1774,7 +1834,7 @@ func validateFinished(workflowExecution shuffle.WorkflowExecution) {
//if len(workflowExecution.Results) == len(workflowExecution.Workflow.Actions)+extra { //if len(workflowExecution.Results) == len(workflowExecution.Workflow.Actions)+extra {
if (len(environments) == 1 && requestsSent == 0 && len(workflowExecution.Results) >= 1) || (len(workflowExecution.Results) >= len(workflowExecution.Workflow.Actions) && len(workflowExecution.Workflow.Actions) > 0) { if (len(environments) == 1 && requestsSent == 0 && len(workflowExecution.Results) >= 1) || (len(workflowExecution.Results) >= len(workflowExecution.Workflow.Actions) && len(workflowExecution.Workflow.Actions) > 0) {
requestsSent += 1 requestsSent += 1
//log.Printf("[FINISHED] Should send full result to %s", baseUrl) log.Printf("[FINISHED] Should send full result to %s", baseUrl)
//data = fmt.Sprintf(`{"execution_id": "%s", "authorization": "%s"}`, executionId, authorization) //data = fmt.Sprintf(`{"execution_id": "%s", "authorization": "%s"}`, executionId, authorization)
shutdownData, err := json.Marshal(workflowExecution) shutdownData, err := json.Marshal(workflowExecution)
@@ -1858,7 +1918,6 @@ func setWorkflowExecution(ctx context.Context, workflowExecution shuffle.Workflo
} else { } else {
log.Printf("[DEBUG] NOT shutting down with dbSave (%s)", workflowExecution.ExecutionSource) log.Printf("[DEBUG] NOT shutting down with dbSave (%s)", workflowExecution.ExecutionSource)
} }
} }
return nil return nil
@@ -1900,15 +1959,27 @@ func webserverSetup(workflowExecution shuffle.WorkflowExecution) net.Listener {
// container being launched and port being assigned to webserver // container being launched and port being assigned to webserver
listener, err := getAvailablePort() listener, err := getAvailablePort()
if err != nil { if err != nil {
log.Printf("Failed to created listener: %s", err) log.Printf("[ERROR] Failed to create init listener: %s", err)
log.Printf("[DEBUG] Shutting down (26)") return listener
shutdown(workflowExecution, "", "", true)
} }
port := listener.Addr().(*net.TCPAddr).Port
log.Printf("\n\nStarting webserver on port %d with hostname: %s\n\n", port, hostname)
log.Printf("OLD HOSTNAME: %s", appCallbackUrl) log.Printf("OLD HOSTNAME: %s", appCallbackUrl)
appCallbackUrl = fmt.Sprintf("http://%s:%d", hostname, port) if os.Getenv("SHUFFLE_SWARM_CONFIG") == "run" {
log.Printf("\n\nStarting webserver on port 33333 with hostname: %s\n\n", hostname)
appCallbackUrl = fmt.Sprintf("http://%s:33333", hostname)
listener, err = net.Listen("tcp", ":33333")
if err != nil {
log.Printf("[ERROR] Failed to assign port to 33333")
return nil
}
return listener
} else {
port := listener.Addr().(*net.TCPAddr).Port
log.Printf("\n\nStarting webserver on port %d with hostname: %s\n\n", port, hostname)
appCallbackUrl = fmt.Sprintf("http://%s:%d", hostname, port)
}
log.Printf("NEW HOSTNAME: %s", appCallbackUrl) log.Printf("NEW HOSTNAME: %s", appCallbackUrl)
return listener return listener
@@ -1918,6 +1989,13 @@ func runWebserver(listener net.Listener) {
r := mux.NewRouter() r := mux.NewRouter()
r.HandleFunc("/api/v1/streams", handleWorkflowQueue).Methods("POST") r.HandleFunc("/api/v1/streams", handleWorkflowQueue).Methods("POST")
r.HandleFunc("/api/v1/streams/results", handleGetStreamResults).Methods("POST", "OPTIONS") r.HandleFunc("/api/v1/streams/results", handleGetStreamResults).Methods("POST", "OPTIONS")
if os.Getenv("SHUFFLE_SWARM_CONFIG") == "run" {
requestCache = cache.New(5*time.Minute, 10*time.Minute)
log.Printf("[DEBUG] Running webserver config for SWARM and K8s")
r.HandleFunc("/api/v1/execute", handleRunExecution).Methods("POST", "OPTIONS")
}
http.Handle("/", r) http.Handle("/", r)
//log.Fatal(http.ListenAndServe(port, nil)) //log.Fatal(http.ListenAndServe(port, nil))
@@ -2028,6 +2106,22 @@ func main() {
} }
log.Printf("[INFO] Running with timezone %s", timezone) log.Printf("[INFO] Running with timezone %s", timezone)
if os.Getenv("SHUFFLE_SWARM_CONFIG") == "run" {
workflowExecution := shuffle.WorkflowExecution{}
listener := webserverSetup(workflowExecution)
//err := executionInit(workflowExecution)
//if err != nil {
// log.Printf("[INFO] Workflow setup failed: %s", workflowExecution.ExecutionId, err)
// log.Printf("[DEBUG] Shutting down (30)")
// shutdown(workflowExecution, "", "", true)
//}
//go func() {
// time.Sleep(time.Duration(1))
// handleExecutionResult(workflowExecution)
//}()
runWebserver(listener)
}
//imageName := fmt.Sprintf("%s/%s:shuffle_openapi_1.0.0", registryName, baseimagename) //imageName := fmt.Sprintf("%s/%s:shuffle_openapi_1.0.0", registryName, baseimagename)
//downloadDockerImageBackend(client, imageName) //downloadDockerImageBackend(client, imageName)
@@ -2042,7 +2136,6 @@ func main() {
log.Printf("[WARNING] Running test environment for worker by executing workflow %s", testing) log.Printf("[WARNING] Running test environment for worker by executing workflow %s", testing)
authorization, executionId = runTestExecution(client, testing, shuffle_apikey) authorization, executionId = runTestExecution(client, testing, shuffle_apikey)
//os.Exit(3)
} else { } else {
authorization = os.Getenv("AUTHORIZATION") authorization = os.Getenv("AUTHORIZATION")
executionId = os.Getenv("EXECUTIONID") executionId = os.Getenv("EXECUTIONID")
@@ -2077,6 +2170,7 @@ func main() {
log.Printf("[DEBUG] Shutting down (29)") log.Printf("[DEBUG] Shutting down (29)")
shutdown(workflowExecution, "", "", true) shutdown(workflowExecution, "", "", true)
} }
topClient = client topClient = client
firstRequest := true firstRequest := true
@@ -2174,12 +2268,29 @@ func main() {
//wg.Add(1) //wg.Add(1)
//wg.Wait() //wg.Wait()
} else { } else {
log.Printf("\n\n[INFO] Running NON-OPTIMIZED execution for type %s with %d environments. This only happens when ran manually. Status: %s\n\n", workflowExecution.ExecutionSource, len(environments), workflowExecution.Status) log.Printf("\n\n[INFO] Running NON-OPTIMIZED execution for type %s with %d environment(s). This only happens when ran manually OR when running with subflows. Status: %s\n\n", workflowExecution.ExecutionSource, len(environments), workflowExecution.Status)
//err := executionInit(workflowExecution) //err := executionInit(workflowExecution)
//if err != nil { //if err != nil {
// log.Printf("[INFO] Workflow setup failed: %s", workflowExecution.ExecutionId, err) // log.Printf("[INFO] Workflow setup failed: %s", workflowExecution.ExecutionId, err)
// shutdown(workflowExecution, "", "", true) // shutdown(workflowExecution, "", "", true)
//} //}
// Trying to make worker into microservice~ :)
if os.Getenv("SHUFFLE_SWARM_CONFIG") == "run" {
listener := webserverSetup(workflowExecution)
err := executionInit(workflowExecution)
if err != nil {
log.Printf("[INFO] Workflow setup failed: %s", workflowExecution.ExecutionId, err)
log.Printf("[DEBUG] Shutting down (30)")
shutdown(workflowExecution, "", "", true)
}
go func() {
time.Sleep(time.Duration(1))
handleExecutionResult(workflowExecution)
}()
runWebserver(listener)
}
} }
} }
@@ -2206,3 +2317,161 @@ func main() {
time.Sleep(time.Duration(sleepTime) * time.Second) time.Sleep(time.Duration(sleepTime) * time.Second)
} }
} }
func handleRunExecution(resp http.ResponseWriter, request *http.Request) {
if executionRunning {
log.Println("[WARNING] An execution is already running on this worker")
resp.WriteHeader(500)
resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "An execution is already running"}`)))
return
}
executionRunning = true
body, err := ioutil.ReadAll(request.Body)
if err != nil {
executionRunning = false
log.Println("[WARNING] Failed reading body for stream result queue")
resp.WriteHeader(401)
resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "%s"}`, err)))
return
}
type ExecutionRequest struct {
ExecutionId string `json:"execution_id"`
Authorization string `json:"authorization"`
HTTPProxy string `json:"http_proxy"`
HTTPSProxy string `json:"https_proxy"`
ShufflePassProxyToApp string `json:"shuffle_pass_proxy_to_app`
BaseUrl string `json:"base_url"`
EnvironmentName string `json:"environment_name"`
Timezone string `json:"timezone"`
Cleanup string `json:"cleanup"`
}
var execRequest ExecutionRequest
err = json.Unmarshal(body, &execRequest)
if err != nil {
executionRunning = false
log.Printf("[WARNING] Failed shuffle.WorkflowExecution unmarshaling: %s", err)
resp.WriteHeader(401)
resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "%s"}`, err)))
return
}
//if strings.ToLower(os.Getenv("SHUFFLE_PASS_APP_PROXY")) == "true" {
if len(execRequest.HTTPProxy) > 0 {
log.Printf("[DEBUG] Sending proxy info to child process")
os.Setenv("SHUFFLE_PASS_APP_PROXY", execRequest.ShufflePassProxyToApp)
}
if len(execRequest.HTTPProxy) > 0 {
log.Printf("[DEBUG] Running with default HTTP proxy %s", execRequest.HTTPProxy)
os.Setenv("HTTP_PROXY", execRequest.HTTPProxy)
}
if len(execRequest.HTTPSProxy) > 0 {
log.Printf("[DEBUG] Running with default HTTPS proxy %s", execRequest.HTTPSProxy)
os.Setenv("HTTPS_PROXY", execRequest.HTTPSProxy)
}
if len(execRequest.EnvironmentName) > 0 {
os.Setenv("ENVIRONMENT_NAME", execRequest.EnvironmentName)
environment = execRequest.EnvironmentName
}
if len(execRequest.Timezone) > 0 {
os.Setenv("TZ", execRequest.Timezone)
timezone = execRequest.Timezone
}
if len(execRequest.Cleanup) > 0 {
os.Setenv("CLEANUP", execRequest.Cleanup)
cleanupEnv = execRequest.Cleanup
}
if len(execRequest.BaseUrl) > 0 {
os.Setenv("BASE_URL", execRequest.BaseUrl)
baseUrl = execRequest.BaseUrl
}
topClient = &http.Client{}
var workflowExecution shuffle.WorkflowExecution
data = fmt.Sprintf(`{"execution_id": "%s", "authorization": "%s"}`, execRequest.ExecutionId, execRequest.Authorization)
streamResultUrl := fmt.Sprintf("%s/api/v1/streams/results", baseUrl)
req, err := http.NewRequest(
"POST",
streamResultUrl,
bytes.NewBuffer([]byte(data)),
)
newresp, err := topClient.Do(req)
if err != nil {
executionRunning = false
log.Printf("[ERROR] Failed making request: %s", err)
resp.WriteHeader(401)
resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "%s"}`, err)))
return
}
body, err = ioutil.ReadAll(newresp.Body)
if err != nil {
executionRunning = false
log.Printf("[ERROR] Failed reading body: %s", err)
resp.WriteHeader(401)
resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "%s"}`, err)))
return
}
if newresp.StatusCode != 200 {
executionRunning = false
log.Printf("[ERROR] Bad statuscode: %d, %s", newresp.StatusCode, string(body))
if strings.Contains(string(body), "Workflowexecution is already finished") {
log.Printf("[DEBUG] Shutting down (19)")
//shutdown(workflowExecution, "", "", true)
}
resp.WriteHeader(401)
resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "Bad statuscode: %d"}`, newresp.StatusCode)))
return
}
err = json.Unmarshal(body, &workflowExecution)
if err != nil {
executionRunning = false
log.Printf("[ERROR] Failed workflowExecution unmarshal: %s", err)
resp.WriteHeader(401)
resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "%s"}`, err)))
return
}
if workflowExecution.Status == "FINISHED" || workflowExecution.Status == "SUCCESS" {
executionRunning = false
log.Printf("[INFO] Workflow %s is finished. Exiting worker.", workflowExecution.ExecutionId)
log.Printf("[DEBUG] Shutting down (20)")
resp.WriteHeader(401)
resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "Bad status %s"}`, workflowExecution.Status)))
return
}
log.Printf("[INFO] Status: %s, Results: %d, actions: %d", workflowExecution.Status, len(workflowExecution.Results), len(workflowExecution.Workflow.Actions)+extra)
if workflowExecution.Status != "EXECUTING" {
executionRunning = false
log.Printf("[WARNING] Exiting as worker execution has status %s!", workflowExecution.Status)
log.Printf("[DEBUG] Shutting down (21)")
resp.WriteHeader(401)
resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "Bad status %s"}`, workflowExecution.Status)))
return
}
log.Printf("[DEBUG] Starting execution :O")
resp.WriteHeader(200)
resp.Write([]byte(fmt.Sprintf(`{"success": true}`)))
cacheKey := fmt.Sprintf("workflowexecution-%s", workflowExecution.ExecutionId)
requestCache.Set(cacheKey, &workflowExecution, cache.DefaultExpiration)
err = executionInit(workflowExecution)
if err != nil {
log.Printf("[INFO] Workflow setup failed: %s", workflowExecution.ExecutionId, err)
log.Printf("[DEBUG] Shutting down (30)")
shutdown(workflowExecution, "", "", true)
}
handleExecutionResult(workflowExecution)
}