Skip to content

Commit

Permalink
Multiapp run and stop implementation for windows (#1315)
Browse files Browse the repository at this point in the history
* windows impl for multiapp run

Signed-off-by: Pravin Pushkar <[email protected]>

* Uncommenting run on windows

Signed-off-by: Pravin Pushkar <[email protected]>

* fix static checks

Signed-off-by: Pravin Pushkar <[email protected]>

* Kill children and grand children forcefully

Signed-off-by: Pravin Pushkar <[email protected]>

* ommiting tests for wiondows

Signed-off-by: Pravin Pushkar <[email protected]>

* rename method

Signed-off-by: Pravin Pushkar <[email protected]>

* shut down all processes

Signed-off-by: Pravin Pushkar <[email protected]>

* Use job handle and named evens together to kill the processes

Signed-off-by: Pravin Pushkar <[email protected]>

* lint fix

Signed-off-by: Pravin Pushkar <[email protected]>

* revert wait to kill

Signed-off-by: Pravin Pushkar <[email protected]>

* Adding E2E for windows template file run

Signed-off-by: Pravin Pushkar <[email protected]>

* rename job name

Signed-off-by: Pravin Pushkar <[email protected]>

* review comments

Signed-off-by: Pravin Pushkar <[email protected]>

* build failure

Signed-off-by: Pravin Pushkar <[email protected]>

---------

Signed-off-by: Pravin Pushkar <[email protected]>
Co-authored-by: Mukundan Sundararajan <[email protected]>
  • Loading branch information
pravinpushkar and mukundansundar committed Aug 30, 2023
1 parent 4d58675 commit 6738eef
Show file tree
Hide file tree
Showing 12 changed files with 280 additions and 35 deletions.
6 changes: 2 additions & 4 deletions cmd/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,10 +112,6 @@ dapr run --run-file /path/to/directory
},
Run: func(cmd *cobra.Command, args []string) {
if len(runFilePath) > 0 {
if runtime.GOOS == string(windowsOsType) {
print.FailureStatusEvent(os.Stderr, "The run command with run file is not supported on Windows")
os.Exit(1)
}
runConfigFilePath, err := getRunFilePath(runFilePath)
if err != nil {
print.FailureStatusEvent(os.Stderr, "Failed to get run file path: %v", err)
Expand Down Expand Up @@ -562,6 +558,8 @@ func executeRun(runTemplateName, runFilePath string, apps []runfileconfig.App) (

if runState.AppCMD.Command.Process != nil {
putAppProcessIDInMeta(runState)
// Attach a windows job object to the app process.
utils.AttachJobObjectToProcess(strconv.Itoa(os.Getpid()), runState.AppCMD.Command.Process)
}
}

Expand Down
5 changes: 0 additions & 5 deletions cmd/stop.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ import (
"fmt"
"os"
"path/filepath"
"runtime"

"github.com/spf13/cobra"

Expand All @@ -43,10 +42,6 @@ dapr stop --run-file /path/to/directory
Run: func(cmd *cobra.Command, args []string) {
var err error
if len(runFilePath) > 0 {
if runtime.GOOS == string(windowsOsType) {
print.FailureStatusEvent(os.Stderr, "Stop command with run file is not supported on Windows")
os.Exit(1)
}
runFilePath, err = getRunFilePath(runFilePath)
if err != nil {
print.FailureStatusEvent(os.Stderr, "Failed to get run file path: %v", err)
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ require (
github.com/josharian/intern v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/compress v1.16.3 // indirect
github.com/kolesnikovae/go-winjob v1.0.0
github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 // indirect
github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 // indirect
github.com/lestrrat-go/blackmagic v1.0.1 // indirect
Expand Down
8 changes: 8 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ github.com/Microsoft/hcsshim v0.9.6/go.mod h1:7pLA8lDk46WKDWlVsENo92gC0XFa8rbKfy
github.com/Microsoft/hcsshim/test v0.0.0-20201218223536-d3e5debf77da/go.mod h1:5hlzMzRKMLyo42nCZ9oml8AdTlq/0cvIaBv6tK1RehU=
github.com/Microsoft/hcsshim/test v0.0.0-20210227013316-43a75bb4edd3/go.mod h1:mw7qgWloBUl75W/gVH3cQszUg1+gUITj7D6NY7ywVnY=
github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=
github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
github.com/Pallinder/sillyname-go v0.0.0-20130730142914-97aeae9e6ba1 h1:ReSY7H5Nf08bSzShfWAUTCthIsK08iNitWGX5YFQGXE=
github.com/Pallinder/sillyname-go v0.0.0-20130730142914-97aeae9e6ba1/go.mod h1:cTmXjiBQMtbZnpc/yLode6SPqKmzeL7xJlD+9R9zxoc=
Expand Down Expand Up @@ -417,6 +418,7 @@ github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs=
github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw=
github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk=
github.com/flowstack/go-jsonschema v0.1.1/go.mod h1:yL7fNggx1o8rm9RlgXv7hTBWxdBM0rVwpMwimd3F3N0=
github.com/form3tech-oss/jwt-go v3.2.3+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k=
github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
Expand Down Expand Up @@ -715,6 +717,7 @@ github.com/jmoiron/sqlx v1.3.5 h1:vFFPA71p1o5gAeqtEAwLU4dnX2napprKtHr7PYIcN3g=
github.com/jmoiron/sqlx v1.3.5/go.mod h1:nRVWtLre0KfCLJvgxzCsLVMogSvQ1zNJtpYr2Ccp0mQ=
github.com/joefitzgerald/rainbow-reporter v0.1.0/go.mod h1:481CNgqmVHQZzdIbN52CupLJyoVwB10FQ/IQlF1pdL8=
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
github.com/jonboulle/clockwork v0.2.2/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8=
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
Expand All @@ -739,6 +742,8 @@ github.com/klauspost/compress v1.11.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYs
github.com/klauspost/compress v1.11.13/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
github.com/klauspost/compress v1.16.3 h1:XuJt9zzcnaz6a16/OU53ZjWp/v7/42WcR5t2a0PcNQY=
github.com/klauspost/compress v1.16.3/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
github.com/kolesnikovae/go-winjob v1.0.0 h1:OKEtCHB3sYNAiqNwGDhf08Y6luM7C8mP+42rp1N6SeE=
github.com/kolesnikovae/go-winjob v1.0.0/go.mod h1:k0joOLP3/NBrRmDQjPV2+oN1TPmEWt6arTNtFjVeQuM=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
Expand Down Expand Up @@ -1049,6 +1054,7 @@ github.com/sclevine/spec v1.2.0/go.mod h1:W4J29eT/Kzv7/b9IWLB055Z+qvVC9vt0Arko24
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
github.com/seccomp/libseccomp-golang v0.9.1/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvWlF4P2Ca7zGrPiEpWo=
github.com/seccomp/libseccomp-golang v0.9.2-0.20220502022130-f33da4d89646/go.mod h1:JA8cRccbGaA1s33RQf7Y1+q9gHmZX1yB/z9WDN1C6fg=
github.com/segmentio/asm v1.2.0/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs=
github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ=
github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI=
github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
Expand All @@ -1069,6 +1075,7 @@ github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1
github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
github.com/soheilhy/cmux v0.1.5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0=
github.com/sony/gobreaker v0.5.0 h1:dRCvqm0P490vZPmy7ppEk2qCnCieBooFJ+YoXGYB+yg=
github.com/sony/gobreaker v0.5.0/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
Expand Down Expand Up @@ -1139,6 +1146,7 @@ github.com/tklauser/numcpus v0.4.0 h1:E53Dm1HjH1/R2/aoCtXtPgzmElmn51aOkhCFSuZq//
github.com/tklauser/numcpus v0.4.0/go.mod h1:1+UI3pD8NW14VMwdgJNJ1ESk2UnwhAnz5hMwiKKqXCQ=
github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
github.com/urfave/cli v0.0.0-20171014202726-7bc6a0acffa5/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
Expand Down
52 changes: 41 additions & 11 deletions pkg/standalone/stop_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,31 +14,61 @@ limitations under the License.
package standalone

import (
"errors"
"fmt"
"strconv"
"syscall"
"time"

"github.com/dapr/cli/utils"
"github.com/kolesnikovae/go-winjob"
"golang.org/x/sys/windows"
)

// Stop terminates the application process.
func Stop(appID string, cliPIDToNoOfApps map[int]int, apps []ListOutput) error {
for _, a := range apps {
if a.AppID == appID {
eventName, _ := syscall.UTF16FromString(fmt.Sprintf("dapr_cli_%v", a.CliPID))
eventHandle, err := windows.OpenEvent(windows.EVENT_MODIFY_STATE, false, &eventName[0])
if err != nil {
return err
}

err = windows.SetEvent(eventHandle)
return err
return setStopEvent(a.CliPID)
}
}
return fmt.Errorf("couldn't find app id %s", appID)
}

// StopAppsWithRunFile terminates the daprd and application processes with the given run file.
func StopAppsWithRunFile(runFilePath string) error {
return errors.New("stopping apps with run template file is not supported on windows")
func StopAppsWithRunFile(runTemplatePath string) error {
apps, err := List()
if err != nil {
return err
}
for _, a := range apps {
if a.RunTemplatePath == runTemplatePath {
return disposeJobHandle(a.CliPID)
}
}
return fmt.Errorf("couldn't find apps with run file %q", runTemplatePath)
}

func disposeJobHandle(cliPID int) error {
jobObjectName := utils.GetJobObjectNameFromPID(strconv.Itoa(cliPID))
jbobj, err := winjob.Open(jobObjectName)
if err != nil {
return fmt.Errorf("error opening job object: %w", err)
}
err = jbobj.TerminateWithExitCode(0)
if err != nil {
return fmt.Errorf("error terminating job object: %w", err)
}
time.Sleep(5 * time.Second)
return setStopEvent(cliPID)
}

func setStopEvent(cliPID int) error {
eventName, _ := syscall.UTF16FromString(fmt.Sprintf("dapr_cli_%v", cliPID))
eventHandle, err := windows.OpenEvent(windows.EVENT_MODIFY_STATE, false, &eventName[0])
if err != nil {
return err
}

err = windows.SetEvent(eventHandle)
return err
}
6 changes: 6 additions & 0 deletions pkg/syscall/syscall.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,9 @@ func CreateProcessGroupID() {
print.WarningStatusEvent(os.Stdout, "Failed to create process group id: %s", err.Error())
}
}

// AttachJobObjectToProcess attaches the process to a job object.
func AttachJobObjectToProcess(jobName string, proc *os.Process) {
// This is a no-op on Linux/Mac.
// Instead, we use process group ID to kill all the processes.
}
47 changes: 45 additions & 2 deletions pkg/syscall/syscall_windows.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
//go:build windows
// +build windows

/*
Copyright 2021 The Dapr Authors
Licensed under the Apache License, Version 2.0 (the "License");
Expand All @@ -18,12 +21,17 @@ import (
"os"
"os/signal"
"syscall"
"unsafe"

"golang.org/x/sys/windows"

"github.com/dapr/cli/pkg/print"
"github.com/kolesnikovae/go-winjob"
"github.com/kolesnikovae/go-winjob/jobapi"
)

var jbObj *winjob.JobObject

func SetupShutdownNotify(sigCh chan os.Signal) {
signal.Notify(sigCh, syscall.SIGTERM, syscall.SIGINT)

Expand All @@ -43,6 +51,41 @@ func SetupShutdownNotify(sigCh chan os.Signal) {

// CreateProcessGroupID creates a process group ID for the current process.
func CreateProcessGroupID() {
// No-op on Windows
print.WarningStatusEvent(os.Stdout, "Creating process group id is not implemented on Windows")
// This is a no-op on windows.
// Process group ID is not used for killing all the processes on windows.
// Instead, we use combination of named event and job object to kill all the processes.
}

// AttachJobObjectToProcess attaches the process to a job object.
// It creates the job object if it doesn't exist.
func AttachJobObjectToProcess(jobName string, proc *os.Process) {
if jbObj != nil {
err := jbObj.Assign(proc)
if err != nil {
print.WarningStatusEvent(os.Stdout, "failed to assign process to job object: %s", err.Error())
}
return
}
jbObj, err := winjob.Create(jobName)
if err != nil {
print.WarningStatusEvent(os.Stdout, "failed to create job object: %s", err.Error())
return
}
// Below lines control the relation between Job object and processes attached to it.
// By passing JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE flag, it will make sure that when
// job object is closed all the processed must also be exited.
info := windows.JOBOBJECT_EXTENDED_LIMIT_INFORMATION{
BasicLimitInformation: windows.JOBOBJECT_BASIC_LIMIT_INFORMATION{
LimitFlags: windows.JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE,
},
}
err = jobapi.SetInformationJobObject(jbObj.Handle, jobapi.JobObjectExtendedLimitInformation, unsafe.Pointer(&info), uint32(unsafe.Sizeof(info)))
if err != nil {
print.WarningStatusEvent(os.Stdout, "failed to set job object info: %s", err.Error())
return
}
err = jbObj.Assign(proc)
if err != nil {
print.WarningStatusEvent(os.Stdout, "failed to assign process to job object: %s", err.Error())
}
}
10 changes: 2 additions & 8 deletions tests/e2e/standalone/run_template_test.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
//go:build e2e || template
//go:build !windows && (e2e || template)
// +build !windows
// +build e2e template

/*
Expand All @@ -24,7 +25,6 @@ import (
"io/ioutil"
"os"
"path/filepath"
"runtime"
"strings"
"testing"
"time"
Expand All @@ -43,9 +43,6 @@ type AppTestOutput struct {
}

func TestRunWithTemplateFile(t *testing.T) {
if runtime.GOOS == "windows" {
t.Skip("Skipping test on Windows")
}
ensureDaprInstallation(t)
t.Cleanup(func() {
// remove dapr installation after all tests in this function.
Expand Down Expand Up @@ -373,9 +370,6 @@ func TestRunWithTemplateFile(t *testing.T) {
}

func TestRunTemplateFileWithoutDaprInit(t *testing.T) {
if runtime.GOOS == "windows" {
t.Skip("Skipping test on Windows")
}
// remove any dapr installation before this test.
must(t, cmdUninstall, "failed to uninstall Dapr")
t.Run("valid template file without dapr init", func(t *testing.T) {
Expand Down
7 changes: 2 additions & 5 deletions tests/e2e/standalone/stop_with_run_template_test.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
//go:build e2e || template
//go:build !windows && (e2e || template)
// +build !windows
// +build e2e template

/*
Expand All @@ -22,7 +23,6 @@ import (
"encoding/json"
"fmt"
"os"
"runtime"
"testing"
"time"

Expand All @@ -31,9 +31,6 @@ import (
)

func TestStopAppsStartedWithRunTemplate(t *testing.T) {
if runtime.GOOS == "windows" {
t.Skip("Skipping test on windows")
}
ensureDaprInstallation(t)
t.Cleanup(func() {
// remove dapr installation after all tests in this function.
Expand Down
Loading

0 comments on commit 6738eef

Please sign in to comment.