mh-cbon / go-msi

Easy way to generate msi package for a Go project
https://mh-cbon.github.io/go-msi/
MIT License
454 stars 57 forks source link

Add support for windows services #9

Open 2opremio opened 7 years ago

2opremio commented 7 years ago

In many (or at least some) cases, golang binaries will work as a daemons executing 24/7

It would be great if the manifest was extended to define services. These services would be started automatically upon installation and stopped/removed on uninstallation.

Alternatively, we do this manually, but for that we need #2

mh-cbon commented 7 years ago

Hi,

after some researches and according to my current understanding, services can be installed via a wix declaration within the wix file.

See this example, The most interesting part is,

<!-- The files inside this DirectoryRef are linked to the Test Service directory via INSTALLFOLDER -->
<DirectoryRef Id="INSTALLFOLDER">
    <!-- Create a single component which is the TestService.exe file -->
    <Component Id="$(var.TestService.TargetFileName)">
        <!-- Copies the TestService.exe file using the project reference preprocessor variables -->
        <File Id="$(var.TestService.TargetFileName)" Source="$(var.TestService.TargetPath)" KeyPath="yes" />
        <!-- Remove all files from the INSTALLFOLDER on uninstall -->
        <RemoveFile Id="ALLFILES" Name="*.*" On="both" />
        <!-- Tell WiX to install the Service -->
        <ServiceInstall Id="ServiceInstaller" 
            Type="ownProcess" 
            Name="TestService" 
            DisplayName="$(var.Name)" 
            Description="A Test Service that logs dummy text on an interval to a text file." 
            Start="auto" 
            ErrorControl="normal" />
        <!-- Tell WiX to start the Service -->
        <ServiceControl Id="StartService" Start="install" Stop="both" Remove="uninstall" Name="TestService" Wait="yes" />
    </Component>
</DirectoryRef>

Where ServiceInstall must be within a Component and those little thing,

    The service executable installed will point to the KeyPath 
for the Component. Therefore, you must ensure that the 
correct executable is either the first child File element 
under this Component or explicitly mark the appropriate 
File element as KeyPath='yes'.

See also the File.KeyPath property,

Name Type Description Required
KeyPath YesNoType Set to yes in order to force this file to be the key path for the parent component. -

The ServiceControl already defines setup/uninstall behaviors.

Then compare with the current template here, under this Directory node, there should be a new component node to define services.

One bogus thing, the File node of the ServiceInstall will be declared twice in one to many ways

Does it matter any how ? Will Wix complain or misbehave ?

Next step is to work on the schema update of the file config, https://github.com/mh-cbon/go-msi/blob/master/wix.json New fields needs to be created to update the templates so new services can be created.

Note how a service file might end up being declared twice in files and (the tbd) services sections, if that should happen, it would be great to find an elegant way to get ride of this duplication, its an easy source of error.

I d familiarize with the demo to use it as a sandbox to better understand the behavior of Wix. Usually i run it once, then i update the code, then i run vagrant rsync, then i re build and re run the setup starting at the section # generate the build

Then just code the update in a new PR, the code is straight forward (except the way wix works), make use of generate-templates subcommand to develop.

This update should not break api.

For reference, check also, http://www.schiffhauer.com/wix-template-for-installing-a-windows-service/

Given the existence of the ServiceInstall node it is not needed to involve a bat file to setup a service, imho.

That s it!

2opremio commented 7 years ago

Thanks for the detailed description!

However, after further digging, since:

  1. Services can be easily created by sc create or even from Go itself.
  2. I need installation hooks for other purposes.

I am thinking of simply implementing #2 and invoking sc.exe during installation to register the service.

As an alternative to invoking sc.exe, I am considering to implement a register subcommand in my program, like postgres does with pg_ctl register, and do the registration from Golang instead.

mh-cbon commented 7 years ago

yes, this or that, i m happy to see this feature enhanced based on use cases that helps me to decide what s best.

but great idea for sure.

solvingj commented 7 years ago

I stumbled across this issue today and I'm glad I did. I was planning on using it to install windows services in the coming weeks and hope it's possible by the time I get there. I'd suggest avoiding the scripting method with sc.exe if we can get this to work. I wrote a program in AutoIt in 2004 which essentially automated the ancestors of sc.exe from the Windows SDK and turned any .exe into a system service. It worked but was always a hack. It worked on Server 2003 and XP, but doubt it works today. Hopefully we can get the go-msi schema modified to support this.

https://github.com/solvingJ/simpleservice-win-au3

mh-cbon commented 7 years ago

@solvingj i m not very clear about AutoIt and how that works, nor what it requires prior to run.

To go further, in any cases, i suggest to demonstrate the changes to apply to this demo program to install it as a service using this/or/that solution.

In my experience windows service are painful to implement because the implementation needs to be aware. it is intrusive, yet necessary for fine grain response of the application to the os messages.

solvingj commented 7 years ago

Yeah, the AutoIt thing isn't helpful to us here. I don't know what the solution is, will have to look into it further.