-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add Windows service support (#429)
- Loading branch information
1 parent
d97e7c1
commit 2ad57d6
Showing
8 changed files
with
247 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,9 +6,10 @@ | |
|
||
# Compiled binary | ||
/alloydb-auth-proxy | ||
/alloydb-auth-proxy.exe | ||
|
||
/key.json | ||
|
||
/logs/ | ||
|
||
|
||
### SAMPLES | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,127 @@ | ||
// Copyright 2023 Google LLC | ||
// | ||
// 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 | ||
// | ||
// https://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 main | ||
|
||
import ( | ||
"context" | ||
"errors" | ||
"os" | ||
"path/filepath" | ||
"time" | ||
|
||
"github.com/GoogleCloudPlatform/alloydb-auth-proxy/cmd" | ||
"github.com/GoogleCloudPlatform/alloydb-auth-proxy/internal/log" | ||
"golang.org/x/sys/windows/svc" | ||
"gopkg.in/natefinch/lumberjack.v2" | ||
) | ||
|
||
type windowsService struct{} | ||
|
||
func (m *windowsService) Execute(_ []string, r <-chan svc.ChangeRequest, changes chan<- svc.Status) (bool, uint32) { | ||
// start the service | ||
changes <- svc.Status{State: svc.StartPending} | ||
|
||
// set up the log file | ||
exePath, err := os.Executable() | ||
if err != nil { | ||
changes <- svc.Status{State: svc.StopPending} | ||
return true, 101 // service specific exit code=101 | ||
} | ||
|
||
logFolder := filepath.Join(filepath.Dir(exePath), "logs") | ||
os.Mkdir(logFolder, 0644) // ignore all errors | ||
|
||
logFile := &lumberjack.Logger{ | ||
Filename: filepath.Join(logFolder, "alloydb-auth-proxy.log"), | ||
MaxSize: 50, // megabytes | ||
MaxBackups: 10, | ||
MaxAge: 30, //days | ||
} | ||
|
||
logger := log.NewStdLogger(logFile, logFile) | ||
logger.Infof("Starting...") | ||
|
||
// start the main command | ||
ctx, cancel := context.WithCancel(context.Background()) | ||
defer cancel() | ||
|
||
app := cmd.NewCommand(cmd.WithLogger(logger)) | ||
|
||
cmdErrCh := make(chan error, 1) | ||
go func() { | ||
cmdErrCh <- app.ExecuteContext(ctx) | ||
}() | ||
|
||
// now running | ||
changes <- svc.Status{State: svc.Running, Accepts: svc.AcceptStop | svc.AcceptShutdown} | ||
|
||
var cmdErr error | ||
|
||
loop: | ||
for { | ||
select { | ||
case err := <-cmdErrCh: | ||
cmdErr = err | ||
break loop | ||
|
||
case c := <-r: | ||
switch c.Cmd { | ||
case svc.Interrogate: | ||
changes <- c.CurrentStatus | ||
// testing deadlock from https://code.google.com/archive/p/winsvc/issues/4 | ||
time.Sleep(100 * time.Millisecond) | ||
changes <- c.CurrentStatus | ||
|
||
case svc.Stop, svc.Shutdown: | ||
cancel() | ||
|
||
default: | ||
logger.Errorf("unexpected control request #%d", c) | ||
} | ||
} | ||
} | ||
|
||
// start shutting down | ||
logger.Infof("Stopping...") | ||
|
||
changes <- svc.Status{State: svc.StopPending} | ||
|
||
if cmdErr != nil && errors.Is(cmdErr, context.Canceled) { | ||
logger.Errorf("Unexpected error: %v", cmdErr) | ||
return true, 2 | ||
} | ||
|
||
return false, 0 | ||
} | ||
|
||
func main() { | ||
// determine if running as a windows service | ||
inService, err := svc.IsWindowsService() | ||
if err != nil { | ||
os.Exit(99) // failed to determine service status | ||
} | ||
|
||
// running as service? | ||
if inService { | ||
err := svc.Run("alloydb-auth-proxy", &windowsService{}) | ||
if err != nil { | ||
os.Exit(100) // failed to execute service | ||
} | ||
return | ||
} | ||
|
||
// run as commandline | ||
cmd.Execute() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
# AlloyDB Auth Proxy Windows Service Guide | ||
|
||
This document covers running the *AlloyDB Auth Proxy* as a service | ||
on the Windows operating system. | ||
|
||
It was originally built and tested using Go 1.20.2 on Windows Server 2019. | ||
|
||
## Install the Windows Service | ||
|
||
Prerequisites: A built binary for Windows of the AlloyDB Auth Proxy is required. | ||
Either build it from source or | ||
[download a release](https://github.com/GoogleCloudPlatform/alloydb-auth-proxy/releases) | ||
of a Windows pre-built version, e.g. `alloydb-auth-proxy.x64.exe`. | ||
|
||
First, install the binary by: | ||
|
||
1. Create a new empty folder, e.g. `C:\Program Files\alloydb-auth-proxy` | ||
2. Copy the binary and helper batch files | ||
3. Modify the batch files as needed: | ||
- `SERVICE` is the Windows internal service name (as shown in the Task Manager) | ||
- `DISPLAYNAME` is the service name (as shown in the Windows Administration Console (MMC)) | ||
- `CREDENTIALSFILE` is the *full* path to the credentials file, where `%~dp0` points to the full path of the script file folder. | ||
- `INSTANCEURI` is the AlloyDB Instance URI in the format of `projects/<PROJECT>/locations/<REGION>/clusters/<CLUSTER>/instances/<INSTANCE>` | ||
- Please note that the `--credentials-file \"%CREDENTIALSFILE%\"` argument is optional and is not needed if the local machine runs within the Google Cloud Compute Engine and "defaults" to the VM instance service account. | ||
4. Grant *read & execute* access to the `Network Service` user | ||
5. Create a `logs` sub-folder, e.g. `C:\Program Files\alloydb-auth-proxy\logs` | ||
6. Grant *modify* access to the `Network Service` user | ||
7. Run the `windows_install_service.bat` batch file within an *elevated* command line prompt (read: *Run as Administrator*). | ||
|
||
After that, perform the setup: | ||
|
||
1. Copy the JSON credentials file, if required | ||
2. Modify the `windows_install_service.bat` file to your needs | ||
3. Run the `windows_install_service.bat` file from the commandline | ||
|
||
Please see the FAQ below for common error messages. | ||
|
||
## Uninstall the Windows Service | ||
|
||
To uninstall the Windows Service, perform the following steps: | ||
|
||
1. Modify the `windows_remove_service.bat` file to your needs | ||
2. Run the `windows_remove_service.bat` file from the commandline | ||
|
||
## FAQ | ||
|
||
### Error Message: *Access is denied* | ||
|
||
The error message `Access is denied.` (or `System error 5 has occurred.`) occurs when | ||
trying to start the installed service but the service account does not have access | ||
to the service's file directory. | ||
|
||
Usually this is the *Network Service* built-in user. | ||
|
||
Please note that write access is also required for creating and managing the log files, e.g.: | ||
|
||
- `alloydb-auth-proxy.log` | ||
- `alloydb-auth-proxy-2016-11-04T18-30-00.000.log` | ||
|
||
### Error Message: *The specified service has been marked for deletion.* | ||
|
||
The error message `The specified service has been marked for deletion.` occurs when | ||
reinstalling the service and the previous deletion request could not be completed | ||
(e.g. because the service was still running or opened in the service manager). | ||
|
||
In this case, the local machine needs to be restarted. | ||
|
||
### Why not running as the *System* user? | ||
|
||
Since the AlloyDB Auth Proxy does not require any file system access, | ||
besides the log files, extensive operating system access is not required. | ||
|
||
The *Network Service* accounts allow binding ports while not granting | ||
access to file system resources. | ||
|
||
### Why not using *Automatic (Delayed Start)* startup type? | ||
|
||
The service is installed in the *Automatic* startup type, by default. | ||
|
||
The alternative *Automatic (Delayed Start)* startup type was introduced | ||
by Microsoft for services that are not required for operating system operations | ||
like Windows Update and similar services. | ||
|
||
However, if the primary purpose of the local machine is to provide services | ||
which require access to the cloud database, then the start of the service | ||
should not be delayed. | ||
|
||
Delayed services might be started even minutes after operating system startup. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
@echo off | ||
|
||
setlocal | ||
|
||
set SERVICE=alloydb-auth-proxy | ||
set DISPLAYNAME=Google AlloyDB Auth Proxy | ||
set CREDENTIALSFILE=%~dp0key.json | ||
set INSTANCEURI=projects/<PROJECT>/locations/<REGION>/clusters/<CLUSTER>/instances/<INSTANCE> | ||
|
||
sc.exe create "%SERVICE%" binPath= "\"%~dp0alloydb-auth-proxy.exe\" --credentials-file \"%CREDENTIALSFILE%\" %INSTANCEURI%" obj= "NT AUTHORITY\Network Service" start= auto displayName= "%DISPLAYNAME%" | ||
sc.exe failure "%SERVICE%" reset= 0 actions= restart/0/restart/0/restart/0 | ||
net start "%SERVICE%" | ||
|
||
endlocal |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
@echo off | ||
|
||
setlocal | ||
|
||
set SERVICE=alloydb-auth-proxy | ||
|
||
net stop "%SERVICE%" | ||
sc.exe delete "%SERVICE%" | ||
|
||
endlocal |