service icon indicating copy to clipboard operation
service copied to clipboard

Propagate windows service start parameters

Open 2opremio opened this issue 8 years ago • 15 comments

This library simply ignores and doesn't propagate the start parameters of windows services.

Those live parameters are very convenient and flexible, allowing to avoid configuration files or registry keys to store the parameters.

Related to #75

2opremio avatar Feb 19 '17 19:02 2opremio

A new method (e.g. Args() []string) could be added to Service without breaking backwards compatibility.

Would you be interested in a PR?

2opremio avatar Feb 19 '17 19:02 2opremio

The Start() method should also pass the arguments (and that one is tricky to change without breaking backwards compatibility)

2opremio avatar Feb 19 '17 22:02 2opremio

Are the args passed into Execute different then os.Args()?

kardianos avatar Feb 19 '17 22:02 kardianos

Yes, Windows seems to distinguish between:

  • The arguments (os.Args()) passed to the Service Application binary managing services
  • The arguments (provided by windows/svc.Execute()) passed to a service on start.

AFAIU the arguments passed to Execute() are the ones provided to StartService (from advapi.dll)

As an example, both sc.exe and the Services UI let you pass those arguments on start:

$ sc.exe start
DESCRIPTION:
        Starts a service running.
USAGE:
        sc <server> start [service name] <arg1> <arg2> ...
The following WinRM command responded with a non-zero exit status.
screen shot 2017-02-20 at 19 46 30

Note that, in the last example you are free to choose service start arguments different from the ones passed to the binary (-k netsvcs)

2opremio avatar Feb 20 '17 19:02 2opremio

@kardianos I got the problem too. First, when I run my code with go run, it works correctly: image The first two line print by fmt, execute before service start. The other print by log, witch would redirect to log file in service mode.

However, when I run my code with builded binary executer, the problem appeared: image image You can see that fmt print the os.Args correctly, while log missing them.

zhengxiaoyao0716 avatar Jul 27 '17 08:07 zhengxiaoyao0716

Any news about this? Something like what @2opremio proposed would be really nice to have :-)

rgl avatar Aug 19 '17 02:08 rgl

Oh, we can already manually propagate arguments! Sorry about the noise...

I ended up using something like:

	nameFlag := flag.String("name", "dummy", "Service name.")
	flag.Parse()
	s, err := service.New(
		&dummyService{},
		&service.Config{
			Arguments:   []string{"-name", *nameFlag},
			Name:        *nameFlag,
			DisplayName: "Dummy Windows Service",
			Description: "Dummy Windows Service",
		})

rgl avatar Aug 19 '17 02:08 rgl

Can this technique of passing arguments be used to say create a "Delayed" start service?

jonathan-automox avatar Aug 15 '18 18:08 jonathan-automox

Yes.

kardianos avatar Aug 16 '18 16:08 kardianos

Oh, we can already manually propagate arguments! Sorry about the noise... &service.Config{ Arguments: []string{"-name", *nameFlag}, })

@rgl , does this example actually propagate the live argument as @2opremio called out? And how to access this parameters from the actual service start method when the parameter not passed through executable but through sc.exe or service control manager?

chuanbozhang-okta avatar Jun 26 '20 05:06 chuanbozhang-okta

I did more investigation, and see adding a line of ws.Arguments = append(ws.Arguments, args...) in Execute method of service_windows.go solved the issue for me.

func (ws *windowsService) Execute(args []string, r <-chan svc.ChangeRequest, changes chan<- svc.Status) (bool, uint32) {
	const cmdsAccepted = svc.AcceptStop | svc.AcceptShutdown
	changes <- svc.Status{State: svc.StartPending}
	ws.Arguments = append(ws.Arguments, args...)	

then in my usage, I declare service.Config to my program struct, and then in program Start method access the parameter from p.config.Arguments, and I've validated that could propagate the live arguments from service control manager.

@kardianos , how do you feel this solution?

chuanbozhang-okta avatar Jun 26 '20 06:06 chuanbozhang-okta

@chuanbozhang-okta @kardianos @rgl Is support for runtime arguments like below supported in windows service start method?

sc start serviceName arg1 arg2 ... argN

to be explicit when a customer starts the service with a runtime port number, I need to access this runtime parameter somehow or injected somhow.

sc start MyGrpcService runtimePortNumber

msays2000 avatar Jul 28 '20 07:07 msays2000

@msays2000 , yes, my proposal fix above to add "ws.Arguments = append(ws.Arguments, args...)" to Execute method could fix the issue and make your usage work.

@kardianos , do you accept contribution for this? If so I could send a PR for it.

chuanbozhang-okta avatar Oct 28 '20 16:10 chuanbozhang-okta

@chuanbozhang-okta thank you for confirming. @kardianos please review and help in merging the above PR of @chuanbozhang-okta

We have a use case where we need to start a grpc service on a determined port passed to the service via its start arguments.

msays2000 avatar Oct 28 '20 16:10 msays2000

@kardianos is there an alternative to pass the arguments to a service.

msays2000 avatar Nov 08 '20 08:11 msays2000