Multiapp run and stop implementation for windows (#1315)

* windows impl for multiapp run

Signed-off-by: Pravin Pushkar <ppushkar@microsoft.com>

* Uncommenting run on windows

Signed-off-by: Pravin Pushkar <ppushkar@microsoft.com>

* fix static checks

Signed-off-by: Pravin Pushkar <ppushkar@microsoft.com>

* Kill children and grand children forcefully

Signed-off-by: Pravin Pushkar <ppushkar@microsoft.com>

* ommiting tests for wiondows

Signed-off-by: Pravin Pushkar <ppushkar@microsoft.com>

* rename method

Signed-off-by: Pravin Pushkar <ppushkar@microsoft.com>

* shut down all processes

Signed-off-by: Pravin Pushkar <ppushkar@microsoft.com>

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

Signed-off-by: Pravin Pushkar <ppushkar@microsoft.com>

* lint fix

Signed-off-by: Pravin Pushkar <ppushkar@microsoft.com>

* revert wait to kill

Signed-off-by: Pravin Pushkar <ppushkar@microsoft.com>

* Adding E2E for windows template file run

Signed-off-by: Pravin Pushkar <ppushkar@microsoft.com>

* rename job name

Signed-off-by: Pravin Pushkar <ppushkar@microsoft.com>

* review comments

Signed-off-by: Pravin Pushkar <ppushkar@microsoft.com>

* build failure

Signed-off-by: Pravin Pushkar <ppushkar@microsoft.com>

---------

Signed-off-by: Pravin Pushkar <ppushkar@microsoft.com>
Co-authored-by: Mukundan Sundararajan <65565396+mukundansundar@users.noreply.github.com>
This commit is contained in:
Pravin Pushkar 2023-08-30 11:06:40 +05:30 committed by GitHub
parent 4d586752bc
commit 6738eefe2b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 280 additions and 35 deletions

View File

@ -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)
@ -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)
}
}

View File

@ -17,7 +17,6 @@ import (
"fmt"
"os"
"path/filepath"
"runtime"
"github.com/spf13/cobra"
@ -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)

1
go.mod
View File

@ -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

8
go.sum
View File

@ -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=
@ -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=
@ -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=
@ -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=
@ -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=
@ -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=
@ -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=

View File

@ -14,10 +14,13 @@ 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"
)
@ -25,7 +28,42 @@ import (
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))
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(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
@ -33,12 +71,4 @@ func Stop(appID string, cliPIDToNoOfApps map[int]int, apps []ListOutput) error {
err = windows.SetEvent(eventHandle)
return err
}
}
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")
}

View File

@ -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.
}

View File

@ -1,3 +1,6 @@
//go:build windows
// +build windows
/*
Copyright 2021 The Dapr Authors
Licensed under the Apache License, Version 2.0 (the "License");
@ -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)
@ -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())
}
}

View File

@ -1,4 +1,5 @@
//go:build e2e || template
//go:build !windows && (e2e || template)
// +build !windows
// +build e2e template
/*
@ -24,7 +25,6 @@ import (
"io/ioutil"
"os"
"path/filepath"
"runtime"
"strings"
"testing"
"time"
@ -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.
@ -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) {

View File

@ -1,4 +1,5 @@
//go:build e2e || template
//go:build !windows && (e2e || template)
// +build !windows
// +build e2e template
/*
@ -22,7 +23,6 @@ import (
"encoding/json"
"fmt"
"os"
"runtime"
"testing"
"time"
@ -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.

View File

@ -0,0 +1,144 @@
//go:build windows && (e2e || template)
// +build windows
// +build e2e template
/*
Copyright 2023 The Dapr Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package standalone_test
import (
"strings"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
type AppTestOutput struct {
appID string
appLogContents []string
daprdLogContent []string
baseLogDirPath string
appLogDoesNotExist bool
daprdLogFileDoesNotExist bool
}
func TestRunWithTemplateFile(t *testing.T) {
ensureDaprInstallation(t)
t.Cleanup(func() {
// remove dapr installation after all tests in this function.
must(t, cmdUninstall, "failed to uninstall Dapr")
})
// These tests are dependent on run template files in ../testdata/run-template-files folder.
t.Run("valid template file", func(t *testing.T) {
runFilePath := "../testdata/run-template-files/dapr.yaml"
go startAppsWithValidRunTemplate(t, runFilePath)
time.Sleep(10 * time.Second)
output, err := cmdStopWithRunTemplate(runFilePath)
assert.NoError(t, err, "failed to stop apps started with run template")
assert.Contains(t, output, "Dapr and app processes stopped successfully")
time.Sleep(5 * time.Second)
})
t.Run("valid template file with App output written to only file", func(t *testing.T) {
runFilePath := "../testdata/run-template-files/app_output_to_file_and_console.yaml"
go startAppsWithAppLogDestFile(t, runFilePath)
time.Sleep(10 * time.Second)
output, err := cmdStopWithRunTemplate(runFilePath)
assert.NoError(t, err, "failed to stop apps started with run template")
assert.Contains(t, output, "Dapr and app processes stopped successfully")
time.Sleep(5 * time.Second)
})
t.Run("valid template file with App output written to only console", func(t *testing.T) {
runFilePath := "../testdata/run-template-files/app_output_to_only_console.yaml"
go startAppsWithAppLogDestConsole(t, runFilePath)
time.Sleep(10 * time.Second)
output, err := cmdStopWithRunTemplate(runFilePath)
assert.NoError(t, err, "failed to stop apps started with run template")
assert.Contains(t, output, "Dapr and app processes stopped successfully")
time.Sleep(5 * time.Second)
})
}
func startAppsWithValidRunTemplate(t *testing.T, file string) {
args := []string{
"-f", file,
}
output, err := cmdRun("", args...)
t.Logf(output)
require.NoError(t, err, "run failed")
lines := strings.Split(output, "\n")
assert.GreaterOrEqual(t, len(lines), 7, "expected at least 7 lines in output of starting two apps")
assert.Contains(t, lines[0], "This is a preview feature and subject to change in future releases.")
assert.Contains(t, lines[1], "Validating config and starting app \"processor\"")
assert.Contains(t, lines[2], "Started Dapr with app id \"processor\". HTTP Port: 3510.")
assert.Contains(t, lines[3], "Writing log files to directory")
assert.Contains(t, lines[3], "tests\\apps\\processor\\.dapr\\logs")
assert.Contains(t, lines[4], "Validating config and starting app \"emit-metrics\"")
assert.Contains(t, lines[5], "Started Dapr with app id \"emit-metrics\". HTTP Port: 3511.")
assert.Contains(t, lines[6], "Writing log files to directory")
assert.Contains(t, lines[6], "tests\\apps\\emit-metrics\\.dapr\\logs")
}
func startAppsWithAppLogDestFile(t *testing.T, file string) {
args := []string{
"-f", file,
}
output, err := cmdRun("", args...)
t.Logf(output)
require.NoError(t, err, "run failed")
// App logs for processor app should not be printed to console and only written to file.
assert.NotContains(t, output, "== APP - processor")
// Daprd logs for processor app should only be printed to console and not written to file.
assert.Contains(t, output, "msg=\"All outstanding components processed\" app_id=processor")
// App logs for emit-metrics app should be printed to console and written to file.
assert.Contains(t, output, "== APP - emit-metrics")
// Daprd logs for emit-metrics app should only be written to file.
assert.NotContains(t, output, "msg=\"All outstanding components processed\" app_id=emit-metrics")
assert.Contains(t, output, "Received signal to stop Dapr and app processes. Shutting down Dapr and app processes.")
}
func startAppsWithAppLogDestConsole(t *testing.T, file string) {
args := []string{
"-f", file,
}
output, err := cmdRun("", args...)
t.Logf(output)
require.NoError(t, err, "run failed")
// App logs for processor app should be printed to console.
assert.Contains(t, output, "== APP - processor")
// Daprd logs for processor app should only be written to file.
assert.NotContains(t, output, "msg=\"All outstanding components processed\" app_id=processor")
// App logs for emit-metrics app should be printed to console.
assert.Contains(t, output, "== APP - emit-metrics")
// Daprd logs for emit-metrics app should only be written to file.
assert.NotContains(t, output, "msg=\"All outstanding components processed\" app_id=emit-metrics")
assert.Contains(t, output, "Received signal to stop Dapr and app processes. Shutting down Dapr and app processes.")
}

View File

@ -0,0 +1,14 @@
version: 1
apps:
- appDirPath: ../../../apps/processor/
appPort: 9081
daprHTTPPort: 3510
command: ["go","run", "app.go"]
appLogDestination: console
- appID: emit-metrics
appDirPath: ../../../apps/emit-metrics/
daprHTTPPort: 3511
env:
DAPR_HOST_ADD: localhost
command: ["go","run", "app.go"]
appLogDestination: console

View File

@ -29,6 +29,7 @@ import (
"time"
"github.com/dapr/cli/pkg/print"
daprsyscall "github.com/dapr/cli/pkg/syscall"
"github.com/docker/docker/client"
"github.com/gocarina/gocsv"
@ -51,6 +52,9 @@ const (
// DefaultAppChannelAddress is the default local network address that user application listen on.
DefaultAppChannelAddress = "127.0.0.1"
// windowsDaprAppProcJobName is the name of the Windows job object that is used to manage the Daprized app's processes on windows.
windowsDaprAppProcJobName = "dapr-app-process-job"
)
// IsValidContainerRuntime checks if the input is a valid container runtime.
@ -408,3 +412,14 @@ func FindFileInDir(dirPath, fileName string) (string, error) {
func SanitizeDir(destDir string) string {
return strings.ReplaceAll(destDir, "'", "''")
}
// Attach Job object to App Process.
func AttachJobObjectToProcess(pid string, proc *os.Process) {
// Attach a job object to the app process.
daprsyscall.AttachJobObjectToProcess(GetJobObjectNameFromPID(pid), proc)
}
// GetJobObjectNameFromPID returns the name of the Windows job object that is used to manage the Daprized app's processes on windows.
func GetJobObjectNameFromPID(pid string) string {
return pid + "-" + windowsDaprAppProcJobName
}