Skip to content

Commit 8c38321

Browse files
authored
Merge pull request #27 from harness/msi
Created msi installer for windows
2 parents 50b1bc6 + 538b927 commit 8c38321

File tree

10 files changed

+347
-3
lines changed

10 files changed

+347
-3
lines changed

README.md

+40-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Lite-engine
1+
# Harness-Docker-Runner
22

33
How to use:
44

@@ -8,6 +8,45 @@ How to use:
88
* Start server: go run main.go server
99
* Client call to check health status of server: go run main.go client.
1010

11+
### Instruction for Running it as Windows Service
12+
13+
If you want to install Harness-Docker-Runner as a service in Windows, please follow the bellow instructions.
14+
15+
#### Instruction for creating msi from Exe file
16+
* choco install go-msi (https://github.com/mh-cbon/go-msi)
17+
* create the binary for harness-docker-runner-windows-amd64.exe
18+
```
19+
go build -o harness-docker-runner-windows-amd64.exe
20+
```
21+
* run the below command from root directory of Harness-Docker-Runner to create msi
22+
```
23+
go-msi make --msi harness-docker-runner-svc.msi --version your_version
24+
```
25+
26+
#### Installation
27+
* Download the msi (harness-docker-runner-svc.msi) from latest github release
28+
* Double click on the msi to start the installation process
29+
* Accept the liecence, click next and finish the installation.
30+
* You can test your service availibility by running below command in your cmd terminal
31+
```
32+
curl http://localhost:3000/healthz
33+
```
34+
* Logs for the runner can be found in path : C:\Windows\system32\harness-docker-runner-timestamp.log
35+
36+
#### Uninstallation
37+
* Double click on the msi to start the installation process
38+
* You will see three options Change, Repair and Remove
39+
* Click on Remove and finish.
40+
41+
#### Additional Instructions
42+
* Service will automatically started even if you re-started your VM
43+
* Please do not attemp to start/stop/delete the service manually, it may cause issue in uninstallation.
44+
* In case you see any issues and not able to verfiy the runner, Uninstall and install again using the msi
45+
46+
#### Error and Resolutions
47+
* For the below both the error, we need to give a full permission to our msi file to get it working. Since this is an extenal msi which is not trusted by windows security, it blocks it initially which can be handle by manually assigning the required permissions from Properties => Security tab.
48+
* If you are facing Error code 2502 or 2503 during installation, please follow the below instruction or link: https://help.krisp.ai/hc/en-us/articles/8083286001820-Error-during-installation-2502-and-2503#h_01HNCW0XCN8AJCWK84K8MQVY7Y
49+
* For error "This installation package could not be opened" then please follow this link: https://answers.microsoft.com/en-us/windows/forum/all/this-installation-package-could-not-be/d6d913e9-aac7-429a-ac0d-c39ad3a7c5eb
1150
## Release procedure
1251

1352
Run the changelog generator.

cli/server/server.go

+16
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ import (
1010
"fmt"
1111
"os"
1212
"os/signal"
13+
RunTime "runtime"
14+
"time"
1315

1416
"github.com/harness/harness-docker-runner/config"
1517
"github.com/harness/harness-docker-runner/engine"
@@ -142,4 +144,18 @@ func initLogging(c *config.Config) {
142144
if c.Trace {
143145
l.SetLevel(logrus.TraceLevel)
144146
}
147+
148+
if RunTime.GOOS == "windows" {
149+
dir, _ := os.Getwd()
150+
logFilePath := dir + string(os.PathSeparator) + "harness-docker-runner-" + time.Now().Format("2-January-2006") + ".log"
151+
logrus.Infoln("Logs will be dumped to : " + logFilePath)
152+
file, err := os.OpenFile(logFilePath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
153+
if err != nil {
154+
logger.L.Logger.Infoln("Failed to open log file:", err)
155+
}
156+
157+
// Set the logger's output to the file
158+
logger.L.Logger.SetOutput(file)
159+
}
160+
145161
}

go.mod

+1
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ require (
6868
)
6969

7070
require (
71+
github.com/kardianos/service v1.2.2 // indirect
7172
github.com/99designs/httpsignatures-go v0.0.0-20170731043157-88528bf4ca7e // indirect
7273
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect
7374
github.com/Microsoft/go-winio v0.6.0 // indirect

go.sum

+2
Original file line numberDiff line numberDiff line change
@@ -612,6 +612,8 @@ github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/X
612612
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
613613
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
614614
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
615+
github.com/kardianos/service v1.2.2 h1:ZvePhAHfvo0A7Mftk/tEzqEZ7Q4lgnR8sGz4xu1YX60=
616+
github.com/kardianos/service v1.2.2/go.mod h1:CIMRFEJVL+0DS1a3Nx06NaMn4Dz63Ng6O7dl0qH0zVM=
615617
github.com/kelseyhightower/envconfig v1.4.0 h1:Im6hONhd3pLkfDFsbRgu68RDNkGF1r3dvMUtDTo2cv8=
616618
github.com/kelseyhightower/envconfig v1.4.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg=
617619
github.com/keybase/go-ps v0.0.0-20190827175125-91aafc93ba19 h1:WjT3fLi9n8YWh/Ih8Q1LHAPsTqGddPcHqscN+PJ3i68=

main.go

+38-2
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,47 @@
55
package main
66

77
import (
8-
"github.com/harness/harness-docker-runner/cli"
8+
"runtime"
99

10+
"github.com/harness/harness-docker-runner/cli"
1011
_ "github.com/joho/godotenv/autoload"
12+
"github.com/kardianos/service"
1113
)
1214

1315
func main() {
14-
cli.Command()
16+
if runtime.GOOS == "windows" {
17+
svcConfig := &service.Config{
18+
Name: "harness-docker-runner-svc",
19+
DisplayName: "harness-docker-runner-svc",
20+
Description: "This is a service runing for harness-docker-runner",
21+
}
22+
23+
runAsService(svcConfig, func() {
24+
cli.Command()
25+
})
26+
} else {
27+
cli.Command()
28+
}
29+
}
30+
31+
func runAsService(svcConfig *service.Config, run func()) error {
32+
s, err := service.New(&program{exec: run}, svcConfig)
33+
if err != nil {
34+
return err
35+
}
36+
return s.Run()
37+
}
38+
39+
type program struct {
40+
exec func()
41+
}
42+
43+
func (p *program) Start(s service.Service) error {
44+
// Start should not block. Do the actual work async.
45+
go p.exec()
46+
return nil
47+
}
48+
func (p *program) Stop(s service.Service) error {
49+
// Stop should not block. Return with a few seconds.
50+
return nil
1551
}

templates/LicenseAgreementDlg_HK.wxs

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
3+
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
4+
<Fragment>
5+
<UI>
6+
<Dialog Id="LicenseAgreementDlg_HK" Width="370" Height="270" Title="!(loc.LicenseAgreementDlg_Title)">
7+
<Control Id="LicenseAcceptedCheckBox" Type="CheckBox" X="20" Y="207" Width="330" Height="18" CheckBoxValue="1" Property="LicenseAccepted" Text="!(loc.LicenseAgreementDlgLicenseAcceptedCheckBox)" />
8+
<Control Id="Back" Type="PushButton" X="180" Y="243" Width="56" Height="17" Text="!(loc.WixUIBack)" />
9+
<Control Id="Next" Type="PushButton" X="236" Y="243" Width="56" Height="17" Default="yes" Text="!(loc.WixUINext)">
10+
<Publish Event="SpawnWaitDialog" Value="WaitForCostingDlg">CostingComplete = 1</Publish>
11+
<Condition Action="disable">
12+
<![CDATA[LicenseAccepted <> "1"]]>
13+
</Condition>
14+
<Condition Action="enable">LicenseAccepted = "1"</Condition>
15+
</Control>
16+
<Control Id="Cancel" Type="PushButton" X="304" Y="243" Width="56" Height="17" Cancel="yes" Text="!(loc.WixUICancel)">
17+
<Publish Event="SpawnDialog" Value="CancelDlg">1</Publish>
18+
</Control>
19+
<Control Id="BannerBitmap" Type="Bitmap" X="0" Y="0" Width="370" Height="44" TabSkip="no" Text="!(loc.LicenseAgreementDlgBannerBitmap)" />
20+
<Control Id="LicenseText" Type="ScrollableText" X="20" Y="60" Width="330" Height="140" Sunken="yes" TabSkip="no">
21+
{{if gt (.License | len) 0}}
22+
<Text SourceFile="{{.License}}" />
23+
{{end}}
24+
</Control>
25+
<Control Id="Print" Type="PushButton" X="112" Y="243" Width="56" Height="17" Text="!(loc.WixUIPrint)">
26+
<Publish Event="DoAction" Value="WixUIPrintEula">1</Publish>
27+
</Control>
28+
<Control Id="BannerLine" Type="Line" X="0" Y="44" Width="370" Height="0" />
29+
<Control Id="BottomLine" Type="Line" X="0" Y="234" Width="370" Height="0" />
30+
<Control Id="Description" Type="Text" X="25" Y="23" Width="340" Height="15" Transparent="yes" NoPrefix="yes" Text="!(loc.LicenseAgreementDlgDescription)" />
31+
<Control Id="Title" Type="Text" X="15" Y="6" Width="200" Height="15" Transparent="yes" NoPrefix="yes" Text="!(loc.LicenseAgreementDlgTitle)" />
32+
</Dialog>
33+
</UI>
34+
</Fragment>
35+
</Wix>

templates/WixUI_HK.wxs

+62
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
3+
<Fragment>
4+
<UI Id="WixUI_HK">
5+
<TextStyle Id="WixUI_Font_Normal" FaceName="Tahoma" Size="8" />
6+
<TextStyle Id="WixUI_Font_Bigger" FaceName="Tahoma" Size="12" />
7+
<TextStyle Id="WixUI_Font_Title" FaceName="Tahoma" Size="9" Bold="yes" />
8+
9+
<Property Id="DefaultUIFont" Value="WixUI_Font_Normal" />
10+
<Property Id="WixUI_Mode" Value="InstallDir" />
11+
12+
<DialogRef Id="BrowseDlg" />
13+
<DialogRef Id="DiskCostDlg" />
14+
<DialogRef Id="ErrorDlg" />
15+
<DialogRef Id="FatalError" />
16+
<DialogRef Id="FilesInUse" />
17+
<DialogRef Id="MsiRMFilesInUse" />
18+
<DialogRef Id="PrepareDlg" />
19+
<DialogRef Id="ProgressDlg" />
20+
<DialogRef Id="ResumeDlg" />
21+
<DialogRef Id="UserExit" />
22+
23+
<!-- Make sure to include custom dialogs in the installer database via a DialogRef command,
24+
especially if they are not included explicitly in the publish chain below -->
25+
<DialogRef Id="LicenseAgreementDlg_HK" />
26+
27+
<Publish Dialog="BrowseDlg" Control="OK" Event="DoAction" Value="WixUIValidatePath" Order="3">1</Publish>
28+
<Publish Dialog="BrowseDlg" Control="OK" Event="SpawnDialog" Value="InvalidDirDlg" Order="4">
29+
<![CDATA[WIXUI_INSTALLDIR_VALID<>"1"]]>
30+
</Publish>
31+
32+
<Publish Dialog="ExitDialog" Control="Finish" Event="EndDialog" Value="Return" Order="999">1</Publish>
33+
34+
<Publish Dialog="WelcomeDlg" Control="Next" Event="NewDialog" {{if gt (.License | len) 0}} Value="LicenseAgreementDlg_HK" {{else}} Value="InstallDirDlg" {{end}}>NOT Installed</Publish>
35+
<Publish Dialog="WelcomeDlg" Control="Next" Event="NewDialog" Value="VerifyReadyDlg">Installed AND PATCH</Publish>
36+
37+
<Publish Dialog="LicenseAgreementDlg_HK" Control="Back" Event="NewDialog" Value="WelcomeDlg">1</Publish>
38+
<Publish Dialog="LicenseAgreementDlg_HK" Control="Next" Event="NewDialog" Value="InstallDirDlg">LicenseAccepted = "1"</Publish>
39+
40+
<Publish Dialog="InstallDirDlg" Control="Back" Event="NewDialog" Value="LicenseAgreementDlg_HK">1</Publish>
41+
<Publish Dialog="InstallDirDlg" Control="Next" Event="SetTargetPath" Value="[WIXUI_INSTALLDIR]" Order="1">1</Publish>
42+
<Publish Dialog="InstallDirDlg" Control="Next" Event="DoAction" Value="WixUIValidatePath" Order="2">NOT WIXUI_DONTVALIDATEPATH</Publish>
43+
<Publish Dialog="InstallDirDlg" Control="Next" Event="SpawnDialog" Value="InvalidDirDlg" Order="3">
44+
<![CDATA[NOT WIXUI_DONTVALIDATEPATH AND WIXUI_INSTALLDIR_VALID<>"1"]]>
45+
</Publish>
46+
<Publish Dialog="InstallDirDlg" Control="Next" Event="NewDialog" Value="VerifyReadyDlg" Order="4">WIXUI_DONTVALIDATEPATH OR WIXUI_INSTALLDIR_VALID="1"</Publish>
47+
48+
<Publish Dialog="InstallDirDlg" Control="ChangeFolder" Property="_BrowseProperty" Value="[WIXUI_INSTALLDIR]" Order="1">1</Publish>
49+
<Publish Dialog="InstallDirDlg" Control="ChangeFolder" Event="SpawnDialog" Value="BrowseDlg" Order="2">1</Publish>
50+
51+
<Publish Dialog="VerifyReadyDlg" Control="Back" Event="NewDialog" Value="MaintenanceTypeDlg" Order="2">Installed</Publish>
52+
53+
<Publish Dialog="MaintenanceWelcomeDlg" Control="Next" Event="NewDialog" Value="MaintenanceTypeDlg">1</Publish>
54+
55+
<Publish Dialog="MaintenanceTypeDlg" Control="RepairButton" Event="NewDialog" Value="VerifyReadyDlg">1</Publish>
56+
<Publish Dialog="MaintenanceTypeDlg" Control="RemoveButton" Event="NewDialog" Value="VerifyReadyDlg">1</Publish>
57+
<Publish Dialog="MaintenanceTypeDlg" Control="Back" Event="NewDialog" Value="MaintenanceWelcomeDlg">1</Publish>
58+
</UI>
59+
60+
<UIRef Id="WixUI_Common" />
61+
</Fragment>
62+
</Wix>

templates/product.wxs

+114
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
<?xml version="1.0"?>
2+
3+
<?if $(sys.BUILDARCH)="x86" ?>
4+
<?define Program_Files="ProgramFilesFolder" ?>
5+
<?elseif $(sys.BUILDARCH)="x64" ?>
6+
<?define Program_Files="ProgramFiles64Folder" ?>
7+
<?else ?>
8+
<?error Unsupported value of sys.BUILDARCH=$(sys.BUILDARCH) ?>
9+
<?endif ?>
10+
11+
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
12+
13+
<Product Id="*" UpgradeCode="{{.UpgradeCode}}" Name="{{.Product}}" Version="{{.VersionOk}}" Manufacturer="{{.Company}}" Language="1033">
14+
15+
<Package InstallerVersion="200" Compressed="yes" Comments="Windows Installer Package" InstallScope="perMachine" />
16+
17+
<Media Id="1" Cabinet="product.cab" EmbedCab="yes" />
18+
19+
<Upgrade Id="{{.UpgradeCode}}">
20+
<UpgradeVersion Minimum="{{.VersionOk}}" OnlyDetect="yes" Property="NEWERVERSIONDETECTED" />
21+
<UpgradeVersion Minimum="0.0.0" Maximum="{{.VersionOk}}" IncludeMinimum="yes" IncludeMaximum="no" Property="OLDERVERSIONBEINGUPGRADED" />
22+
</Upgrade>
23+
<Condition Message="A newer version of this software is already installed.">NOT NEWERVERSIONDETECTED</Condition>
24+
25+
<Directory Id="TARGETDIR" Name="SourceDir">
26+
27+
<Directory Id="$(var.Program_Files)">
28+
<Directory Id="INSTALLDIR" Name="{{.Product}}">
29+
{{if gt (.Files.Items | len) 0}}
30+
<Component Id="ApplicationFiles" Guid="{{.Files.GUID}}">
31+
{{range $i, $e := .Files.Items}}
32+
<File Id="ApplicationFile{{$i}}" Source="{{$e}}" />
33+
{{end}}
34+
</Component>
35+
{{end}}
36+
{{if gt (.Directories | len) 0}}
37+
{{range $i, $e := .Directories}}
38+
<Directory Id="APPDIR{{$i}}" Name="{{$e}}" />
39+
{{end}}
40+
{{end}}
41+
</Directory>
42+
</Directory>
43+
{{if gt (.Env.Vars | len) 0}}
44+
<Component Id="ENVS" Guid="{{.Env.GUID}}">
45+
{{range $i, $e := .Env.Vars}}
46+
<Environment Id="ENV{{$i}}" Name="{{$e.Name}}" Value="{{$e.Value}}" Permanent="{{$e.Permanent}}" Part="{{$e.Part}}" Action="{{$e.Action}}" System="{{$e.System}}" />
47+
{{end}}
48+
</Component>
49+
{{end}}
50+
51+
{{if gt (.Shortcuts.Items | len) 0}}
52+
<Directory Id="ProgramMenuFolder">
53+
<Directory Id="ProgramMenuSubfolder" Name="{{.Product}}">
54+
<Component Id="ApplicationShortcuts" Guid="{{.Shortcuts.GUID}}">
55+
{{range $i, $e := .Shortcuts.Items}}
56+
<Shortcut Id="ApplicationShortcut{{$i}}" Name="{{$e.Name}}" Description="{{$e.Description}}" Target="{{$e.Target}}" WorkingDirectory="{{$e.WDir}}" {{if gt ($e.Arguments | len) 0}} Arguments="{{$e.Arguments}}" {{end}}>
57+
{{if gt ($e.Icon | len) 0}}
58+
<Icon Id="Icon{{$i}}" SourceFile="{{$e.Icon}}" />
59+
{{end}}
60+
</Shortcut>
61+
<RegistryValue Root="HKCU" Key="Software\{{$.Company}}\{{$.Product}}" Name="installed{{$i}}" Type="integer" Value="1" KeyPath="yes" />
62+
{{end}}
63+
<RemoveFolder Id="ProgramMenuSubfolder" On="uninstall" />
64+
</Component>
65+
</Directory>
66+
</Directory>
67+
{{end}}
68+
</Directory>
69+
{{range $i, $e := .InstallHooks}}
70+
<SetProperty Id="CustomInstallExec{{$i}}" Value="{{$e.CookedCommand}}" Before="CustomInstallExec{{$i}}" Sequence="execute" />
71+
<CustomAction Id="CustomInstallExec{{$i}}" BinaryKey="WixCA" DllEntry="WixQuietExec" Execute="deferred" Return="check" Impersonate="no" />
72+
{{end}}
73+
{{range $i, $e := .UninstallHooks}}
74+
<SetProperty Id="CustomUninstallExec{{$i}}" Value="{{$e.CookedCommand}}" Before="CustomUninstallExec{{$i}}" Sequence="execute" />
75+
<CustomAction Id="CustomUninstallExec{{$i}}" BinaryKey="WixCA" DllEntry="WixQuietExec" Execute="deferred" Return="check" Impersonate="no" />
76+
{{end}}
77+
<InstallExecuteSequence>
78+
<RemoveExistingProducts After="InstallValidate" />
79+
{{range $i, $e := .InstallHooks}}
80+
<Custom Action="CustomInstallExec{{$i}}" After="{{if eq $i 0}}InstallFiles{{else}}CustomInstallExec{{dec $i}}{{end}}">NOT Installed AND NOT REMOVE</Custom>
81+
{{end}}
82+
{{range $i, $e := .UninstallHooks}}
83+
<Custom Action="CustomUninstallExec{{$i}}" After="{{if eq $i 0}}InstallInitialize{{else}}CustomUninstallExec{{dec $i}}{{end}}">REMOVE ~= "ALL"</Custom>
84+
{{end}}
85+
</InstallExecuteSequence>
86+
87+
<Feature Id="DefaultFeature" Level="1">
88+
{{if gt (.Env.Vars | len) 0}}
89+
<ComponentRef Id="ENVS" />
90+
{{end}}
91+
{{if gt (.Files.Items | len) 0}}
92+
<ComponentRef Id="ApplicationFiles" />
93+
{{end}}
94+
{{if gt (.Shortcuts.Items | len) 0}}
95+
<ComponentRef Id="ApplicationShortcuts" />
96+
{{end}}
97+
{{range $i, $e := .Directories}}
98+
<ComponentGroupRef Id="AppFiles{{$i}}" />
99+
{{end}}
100+
</Feature>
101+
102+
<UI>
103+
<!-- Define the installer UI -->
104+
<UIRef Id="WixUI_HK" />
105+
</UI>
106+
107+
<Property Id="WIXUI_INSTALLDIR" Value="INSTALLDIR" />
108+
109+
<!-- this should help to propagate env var changes -->
110+
<CustomActionRef Id="WixBroadcastEnvironmentChange" />
111+
112+
</Product>
113+
114+
</Wix>

uninstall.bat

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
@echo off
2+
setlocal enabledelayedexpansion
3+
4+
set "SERVICE_NAME=harness-docker-runner-svc"
5+
6+
sc query "%SERVICE_NAME%" | find "STATE" | find /i "RUNNING" >nul
7+
if %errorlevel% EQU 0 (
8+
echo Service "%SERVICE_NAME%" is running.
9+
echo Stopping service "%SERVICE_NAME%"...
10+
sc.exe stop "%SERVICE_NAME%"
11+
)
12+
13+
sc query "%SERVICE_NAME%" | find "STATE" | find /i "STOPPED" >nul
14+
if %errorlevel% EQU 0 (
15+
echo Service "%SERVICE_NAME%" is stopped.
16+
echo Deleting service "%SERVICE_NAME%"...
17+
sc.exe delete "%SERVICE_NAME%"
18+
)

0 commit comments

Comments
 (0)