Skip to content

Commit

Permalink
Flow Windows service: Support environment variables (#5762)
Browse files Browse the repository at this point in the history
* Implement windows service environment variabls

Signed-off-by: Jan-Otto Kröpke <[email protected]>

* Changelog

Signed-off-by: Jan-Otto Kröpke <[email protected]>

* Add NSIS argument

* Always override Environment, since its an expected user input

Signed-off-by: Jan-Otto Kröpke <[email protected]>

* Update cmd/grafana-agent-service/config_windows.go

Co-authored-by: Robert Fratto <[email protected]>

* Update cmd/grafana-agent-service/config_windows.go

* Update docs/sources/flow/setup/install/windows.md

Co-authored-by: Clayton Cornell <[email protected]>

* Update CHANGELOG.md

---------

Signed-off-by: Jan-Otto Kröpke <[email protected]>
Co-authored-by: mattdurham <[email protected]>
Co-authored-by: Robert Fratto <[email protected]>
Co-authored-by: Clayton Cornell <[email protected]>
  • Loading branch information
4 people authored Nov 22, 2023
1 parent d388f94 commit 8f5a8aa
Show file tree
Hide file tree
Showing 8 changed files with 52 additions and 5 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ Main (unreleased)

- Agent Management: Introduce support for templated configuration. (@jcreixell)

### Enhancements

- Flow Windows service: Support environment variables. (@jkroepke)

### Bugfixes

- Permit `X-Faro-Session-ID` header in CORS requests for the `faro.receiver`
Expand Down
11 changes: 11 additions & 0 deletions cmd/grafana-agent-service/config_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@ type config struct {
// not included.
Args []string

// Environment holds environment variables for the Grafana Agent service.
// Each item represents an environment variable in form "key=value".
// All environments variables from the current process with be merged into Environment
Environment []string

// WorkingDirectory points to the working directory to run the Grafana Agent
// binary from.
WorkingDirectory string
Expand All @@ -42,9 +47,15 @@ func loadConfig() (*config, error) {
return nil, fmt.Errorf("failed to retrieve key Arguments: %w", err)
}

env, _, err := agentKey.GetStringsValue("Environment")
if err != nil {
return nil, fmt.Errorf("failed to retrieve key Environment: %w", err)
}

return &config{
ServicePath: servicePath,
Args: args,
Environment: env,
WorkingDirectory: filepath.Dir(servicePath),
}, nil
}
7 changes: 4 additions & 3 deletions cmd/grafana-agent-service/main_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,10 @@ func main() {
}

cfg := serviceManagerConfig{
Path: managerConfig.ServicePath,
Args: managerConfig.Args,
Dir: managerConfig.WorkingDirectory,
Path: managerConfig.ServicePath,
Args: managerConfig.Args,
Environment: managerConfig.Environment,
Dir: managerConfig.WorkingDirectory,

// Send logs directly to the event logger.
Stdout: logger,
Expand Down
5 changes: 5 additions & 0 deletions cmd/grafana-agent-service/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ type serviceManagerConfig struct {
// Args of the binary to run, not including the command itself.
Args []string

// Environment of the binary to run, including the command environment itself.
Environment []string

// Dir specifies the working directory to run the binary from. If Dir is
// empty, the working directory of the current process is used.
Dir string
Expand Down Expand Up @@ -84,5 +87,7 @@ func (svc *serviceManager) buildCommand(ctx context.Context) *exec.Cmd {
cmd.Dir = svc.cfg.Dir
cmd.Stdout = svc.cfg.Stdout
cmd.Stderr = svc.cfg.Stderr
cmd.Env = os.Environ()
cmd.Env = append(cmd.Env, svc.cfg.Environment...)
return cmd
}
11 changes: 9 additions & 2 deletions cmd/grafana-agent-service/service_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,9 @@ func Test_serviceManager(t *testing.T) {
listenHost := getListenHost(t)

mgr := newServiceManager(l, serviceManagerConfig{
Path: serviceBinary,
Args: []string{"-listen-addr", listenHost},
Path: serviceBinary,
Args: []string{"-listen-addr", listenHost},
Environment: []string{"LISTEN=" + listenHost},
})
go mgr.Run(componenttest.TestContext(t))

Expand All @@ -40,6 +41,12 @@ func Test_serviceManager(t *testing.T) {
require.NoError(t, err)
require.Equal(t, []byte("Hello, world!"), resp)
})

util.Eventually(t, func(t require.TestingT) {
resp, err := makeServiceRequest(listenHost, "/echo/env", nil)
require.NoError(t, err)
require.Contains(t, string(resp), "LISTEN="+listenHost)
})
})

t.Run("terminates service binary", func(t *testing.T) {
Expand Down
4 changes: 4 additions & 0 deletions cmd/grafana-agent-service/testdata/example_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"net"
"net/http"
"os"
"strings"
)

func main() {
Expand Down Expand Up @@ -46,6 +47,9 @@ func run() error {
mux.HandleFunc("/echo/response", func(w http.ResponseWriter, r *http.Request) {
_, _ = io.Copy(w, r.Body)
})
mux.HandleFunc("/echo/env", func(w http.ResponseWriter, r *http.Request) {
_, _ = w.Write([]byte(strings.Join(os.Environ(), "\n")))
})

srv := &http.Server{Handler: mux}
_ = srv.Serve(lis)
Expand Down
8 changes: 8 additions & 0 deletions docs/sources/flow/setup/install/windows.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,14 @@ To do a silent install of Grafana Agent on Windows, perform the following steps.
* `/CONFIG=<path>` Path to the configuration file. Default: `$INSTDIR\config.river`
* `/DISABLEREPORTING=<yes|no>` Disable [data collection][]. Default: `no`
* `/DISABLEPROFILING=<yes|no>` Disable profiling endpoint. Default: `no`
* `/ENVIRONMENT="KEY=VALUE\0KEY2=VALUE2"` Define environment variables for Windows Service. Default: ``

## Service Configuration

Grafana Agent uses the Windows Registry `HKLM\Software\Grafana\Grafana Agent Flow` for service configuration.

* `Arguments` (Type `REG_MULTI_SZ`) Each value represents a binary argument for grafana-agent-flow binary.
* `Environment` (Type `REG_MULTI_SZ`) Each value represents a environment value `KEY=VALUE` for grafana-agent-flow binary.

## Uninstall

Expand Down
7 changes: 7 additions & 0 deletions packaging/grafana-agent-flow/windows/install_script.nsis
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ OutFile "${OUT}"
Var PassedInParameters
Var Config
Var ConfigFlag
Var Environment
Var DisableReporting
Var DisableReportingFlag
Var DisableProfiling
Expand All @@ -51,6 +52,7 @@ Section "install"
${GetParameters} $PassedInParameters
${GetOptions} $PassedInParameters "/DISABLEPROFILING=" $DisableProfiling
${GetOptions} $PassedInParameters "/DISABLEREPORTING=" $DisableReporting
${GetOptions} $PassedInParameters "/ENVIRONMENT=" $Environment
${GetOptions} $PassedInParameters "/CONFIG=" $Config

# Calls to functions like nsExec::ExecToLog below push the exit code to the
Expand Down Expand Up @@ -146,6 +148,11 @@ Function InitializeRegistry
Pop $0 # Ignore return result
${EndIf}

# Define the environment key, which holds environment variables to pass to the
# service.
nsExec::ExecToLog 'Reg.exe add "${REGKEY}" /reg:64 /v Environment /t REG_MULTI_SZ /d "$Environment"'
Pop $0 # Ignore return result

Return
FunctionEnd

Expand Down

0 comments on commit 8f5a8aa

Please sign in to comment.