Support running service as systemd and Windows service. Create installer scripts for Linux & Windows. (#121)

- New installer scripts for Linux and Windows make it easy to configure the service as a service 😎. Scripts are wrapped inside the existing service .zip files for easy access 💯.
- Service now supports running as a systemd service on Linux! Uses Microsoft.Extensions.Hosting.Systemd nuget so it's well supported 🆒. Thanks @patelp3989 for the advice on how to set this up! This also fixes a Linux bug where volatile state wasn't wiped on boot.
- Use Microsoft.Extensions.Hosting.WindowsService nuget instead of DotNetCore.WindowsService as the latter was intended as a stopgap until the ASP.NET concepts were available in .NET Core. They are now, so let's use them! 😲
- Moved service .zip creation out of .yml and into a standalone PowerShell script for debuggability. 🪲
- Refactored service C# files for readability. Biggest change: moved IPC endpoint methods to their own file as they are 95% boilerplate code with little chance of breaking. 🥱
This commit is contained in:
Jake Friedman 2021-04-10 17:09:12 -07:00 коммит произвёл GitHub
Родитель 792a55a85d
Коммит 729599ee2a
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
17 изменённых файлов: 1611 добавлений и 1409 удалений

Просмотреть файл

@ -50,34 +50,6 @@ SOFTWARE.
=========================================
END OF IpcServiceFramework NOTICES, INFORMATION, AND LICENSE
2. DotNetCore.WindowsService
%% DotNetCore.WindowsService NOTICES, INFORMATION, AND LICENSE BEGIN HERE
=========================================
MIT License
Copyright (c) 2016 Peter Kottas
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
=========================================
END OF DotNetCore.WindowsService NOTICES, INFORMATION, AND LICENSE
%% Pe-Utility NOTICES, INFORMATION, AND LICENSE BEGIN HERE
=========================================

Просмотреть файл

@ -124,8 +124,6 @@ Please refer to [SECURITY.md](./SECURITY.md).
[IpcServiceFramework](https://github.com/jacqueskang/IpcServiceFramework) - Jacques Kang - [MIT License](https://github.com/jacqueskang/IpcServiceFramework/blob/develop/LICENSE)
[DotNetCore.WindowsService](https://github.com/PeterKottas/DotNetCore.WindowsService) - Peter Kottas - [MIT License](https://github.com/PeterKottas/DotNetCore.WindowsService/blob/master/LICENSE)
[Pe-Utility](https://github.com/AndresTraks/pe-utility) - Andres Traks - [MIT License](https://github.com/AndresTraks/pe-utility/blob/master/LICENSE)
[WindowsDevicePortalWrapper (mgurlitz .NET Standard fork)](https://github.com/mgurlitz/WindowsDevicePortalWrapper/tree/feat-standard) - Microsoft Corporation and mgurlitz - [MIT License](https://github.com/mgurlitz/WindowsDevicePortalWrapper/blob/feat-standard/License.txt)

Просмотреть файл

@ -0,0 +1,72 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT license.
# Creates a .zip file with the service and installer.
Param
(
[Parameter(Mandatory = $true)][string]$BuildConfiguration,
[Parameter(Mandatory = $true)][string]$BuildPlatform,
[Parameter(Mandatory = $true)][string]$BuildOS,
[Parameter(Mandatory = $true)][string]$BinDir,
[Parameter(Mandatory = $true)][string]$DestinationDir
)
[string]$randString = Get-Random
$tmpdir = join-path "$([System.IO.Path]::GetTempPath())" "$randString"
if ((Test-Path $tmpdir) -eq $false)
{
$null = New-Item -Path $tmpdir -ItemType Directory
}
[string]$randString = Get-Random
$tmppublishdir = join-path "$([System.IO.Path]::GetTempPath())" "$randString"
if ((Test-Path $tmpdir) -eq $false)
{
$null = New-Item -Path $tmpdir -ItemType Directory
}
if ($null -ne $($env:VERSIONSUFFIXVPACK))
{
$version = "$($env:VERSIONPREFIX)$($env:VERSIONSUFFIXVPACK)"
}
else
{
$version = "$($env:VERSIONPREFIX)"
}
# copy install scripts to temp dir
$installdir = Join-Path $env:FORepoRoot "install"
if ($BuildOS -eq "win")
{
$files = Get-ChildItem -Path $installdir -Filter "*.ps1"
}
else
{
$files = Get-ChildItem -Path $installdir -Filter "*"
}
# Set $variables$ in tempdir files
foreach ($file in $files)
{
$destfile = Join-Path $tmpdir $($file.Name)
$null = Get-Content $file.FullName -raw |
ForEach-Object{$_ -replace '\$Version\$', "$version"} |
ForEach-Object{$_ -replace '\$BuildPlatform\$', "$BuildPlatform"} |
ForEach-Object{$_ -replace '\$BuildOS\$', "$BuildOS"} |
Set-Content $destfile -NoNewline
}
# create bin zip in temp dir
$publishdir = Join-Path $BinDir "$BuildConfiguration/Publish/$BuildOS/Microsoft.FactoryOrchestrator.Service.$BuildOS-$BuildPlatform"
Copy-Item -Path $publishdir -recurse -exclude "*.pdb" -destination $tmppublishdir
Compress-Archive -Path "$tmppublishdir/*" -DestinationPath "$tmpdir/Microsoft.FactoryOrchestrator.Service-$version-$BuildOS-$BuildPlatform-bin.zip" -Force
# create zip with bin zip and install files
if ((Test-Path $DestinationDir) -eq $false)
{
$null = New-Item -Path $DestinationDir -ItemType Directory
}
Compress-Archive -Path "$tmpdir/*" -DestinationPath "$DestinationDir/Microsoft.FactoryOrchestrator.Service-$version-$BuildOS-$BuildPlatform.zip" -Force
# clean temp dirs
Remove-Item $tmpdir -Recurse -Force
Remove-Item $tmppublishdir -Recurse -Force

Просмотреть файл

@ -79,7 +79,7 @@ stages:
displayName: 'Create NET Core Test Files Zip'
inputs:
targetType: filePath
filePath: $(Build.SourcesDirectory)/build/internal/CreateTestZip.ps1
filePath: $(FORepoRoot)/build/internal/CreateTestZip.ps1
arguments: '-TestBinRoot $(Build.ARTIFACTSTAGINGDIRECTORY)/bin/tests/$(BuildConfiguration)/AnyCPU/ -OutFolder $(Build.ARTIFACTSTAGINGDIRECTORY)/bin/tests/TestZip'
failOnStderr: true
pwsh: true

Просмотреть файл

@ -2,36 +2,15 @@ parameters:
BuildConfiguration: 'Release'
BuildPlatform: 'x86'
BuildOS: 'win'
BinDir: '$(Build.ARTIFACTSTAGINGDIRECTORY)/bin/'
# Publishes Service. Creates Service vPacks.
steps:
- task: CopyFiles@2
- task: PowerShell@2
displayName: 'Create Service Zip ${{ parameters.BuildOS }}-${{ parameters.BuildPlatform }}'
inputs:
sourceFolder: '$(Build.ARTIFACTSTAGINGDIRECTORY)\bin\${{ parameters.BuildConfiguration }}\Publish\${{ parameters.BuildOS }}\Microsoft.FactoryOrchestrator.Service.${{ parameters.BuildOS }}-${{ parameters.BuildPlatform }}'
contents: '*.pdb'
targetFolder: '$(Build.ARTIFACTSTAGINGDIRECTORY)\bin\${{ parameters.BuildConfiguration }}\Publish\${{ parameters.BuildOS }}\Microsoft.FactoryOrchestrator.Service.${{ parameters.BuildOS }}-${{ parameters.BuildPlatform }}.Symbols'
displayName: "Copy pdbs ${{ parameters.BuildOS }}-${{ parameters.BuildPlatform }}"
- task: ArchiveFiles@2
inputs:
rootFolderOrFile: '$(Build.ARTIFACTSTAGINGDIRECTORY)\bin\${{ parameters.BuildConfiguration }}\Publish\${{ parameters.BuildOS }}\Microsoft.FactoryOrchestrator.Service.${{ parameters.BuildOS }}-${{ parameters.BuildPlatform }}.Symbols'
includeRootFolder: false
archiveType: 'zip' # Options: zip, 7z, tar, wim
archiveFile: '$(Build.ARTIFACTSTAGINGDIRECTORY)\bin\${{ parameters.BuildConfiguration }}\Publish\Zips\Microsoft.FactoryOrchestrator.Service-$(VERSIONPREFIX)$(VERSIONSUFFIXVPACK)-${{ parameters.BuildOS }}-${{ parameters.BuildPlatform }}.Symbols.zip'
replaceExistingArchive: true
displayName: "Create pdb-only zip ${{ parameters.BuildOS }}-${{ parameters.BuildPlatform }}"
- task: DeleteFiles@1
inputs:
SourceFolder: '$(Build.ARTIFACTSTAGINGDIRECTORY)\bin\${{ parameters.BuildConfiguration }}\Publish\${{ parameters.BuildOS }}\Microsoft.FactoryOrchestrator.Service.${{ parameters.BuildOS }}-${{ parameters.BuildPlatform }}'
Contents: '*.pdb'
displayName: "Delete pdbs ${{ parameters.BuildOS }}-${{ parameters.BuildPlatform }}"
- task: ArchiveFiles@2
inputs:
rootFolderOrFile: '$(Build.ARTIFACTSTAGINGDIRECTORY)\bin\${{ parameters.BuildConfiguration }}\Publish\${{ parameters.BuildOS }}\Microsoft.FactoryOrchestrator.Service.${{ parameters.BuildOS }}-${{ parameters.BuildPlatform }}'
includeRootFolder: false
archiveType: 'zip' # Options: zip, 7z, tar, wim
archiveFile: '$(Build.ARTIFACTSTAGINGDIRECTORY)\bin\${{ parameters.BuildConfiguration }}\Publish\Zips\Microsoft.FactoryOrchestrator.Service-$(VERSIONPREFIX)$(VERSIONSUFFIXVPACK)-${{ parameters.BuildOS }}-${{ parameters.BuildPlatform }}.zip'
replaceExistingArchive: true
displayName: "Create bin-only service zip ${{ parameters.BuildOS }}-${{ parameters.BuildPlatform }}"
targetType: filePath
filePath: $(FORepoRoot)/build/internal/CreateServiceZip.ps1
arguments: ' -BuildConfiguration ${{ parameters.BuildConfiguration }} -BuildPlatform ${{ parameters.BuildPlatform }} -BuildOS ${{ parameters.BuildOS }} -BinDir ${{ parameters.BinDir }} -DestinationDir ${{ parameters.BinDir }}${{ parameters.BuildConfiguration }}/Publish/Zips/'
failOnStderr: true
pwsh: true
timeoutInMinutes: 5

Просмотреть файл

@ -0,0 +1,53 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT license.
#requires -RunAsAdministrator
Param
(
[switch]$AutoStart
)
$ErrorActionPreference = "stop"
if (-not $IsWindows)
{
$command = $PSCommandPath.Replace(".ps1", ".sh")
if ($AutoStart)
{
. sudo bash $command enable
}
else
{
. sudo bash $command
}
}
else
{
$installdir = Join-Path -path $env:ProgramFiles -childpath "FactoryOrchestrator"
# Uninstall existing service, if installed
$ErrorActionPreference = "SilentlyContinue"
$service = Get-Service -Name "Microsoft.FactoryOrchestrator"
$ErrorActionPreference = "stop"
if ($null -ne $service)
{
Set-Service -InputObject $service -Status Stopped
Remove-Service -InputObject $service
}
if ((Test-Path $installdir) -ne $false)
{
Remove-Item $installdir -Recurse -Force
}
# Install new service
$binzip = Join-Path $PSScriptRoot "Microsoft.FactoryOrchestrator.Service-$Version$-$BuildOS$-$BuildPlatform$-bin.zip"
Expand-Archive $binzip -DestinationPath $installdir
$null = New-Service -Name "Microsoft.FactoryOrchestrator" -BinaryPathName "$installdir\Microsoft.FactoryOrchestrator.Service.exe" -Description "Factory Orchestrator service version $Version$" -StartupType Manual
Write-Host "FactoryOrchestrator service version $Version$ is installed to $installdir and configured as a Windows service!"
Write-Host "Start it manually with: Start-Service -Name `"Microsoft.FactoryOrchestrator`""
if ($AutoStart)
{
Set-Service -Name "Microsoft.FactoryOrchestrator" -StartupType Automatic
Write-Host "The FactoryOrchestrator service is set to `"Auto`" start! It will start on next boot or if started manually."
}
}

Просмотреть файл

@ -0,0 +1,52 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT license.
# exit when any command fails
set -e
# keep track of the last executed command
trap 'last_command=$current_command; current_command=$BASH_COMMAND' DEBUG
# echo an error message before exiting
trap 'echo "Command \"${last_command}\" failed with exit code $?!"; echo ""; echo "Factory Orchestrator might not be installed or configured correctly."' EXIT
if [ ! "$EUID" = 0 ]
then
echo "sudo elevation required. Please re-run with sudo."
trap '' EXIT
exit 1
fi
SCRIPTDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"
# copy .service files
sudo cp -f $SCRIPTDIR/*.service /etc/systemd/system/
sudo systemctl daemon-reload
# delete old service files if present
if [ -d "/usr/sbin/FactoryOrchestrator" ]
then
rm -r -f /usr/sbin/FactoryOrchestrator
fi
# unzip binary files
sudo unzip -q -d /usr/sbin/FactoryOrchestrator -o $SCRIPTDIR/Microsoft.FactoryOrchestrator.Service-10.0.0-foo-linux-x64-bin.zip
sudo cp -f $SCRIPTDIR/Microsoft.FactoryOrchestrator.CleanVolatile.sh /usr/sbin/FactoryOrchestrator/
# mark everything as executable
sudo chmod -R +x /usr/sbin/FactoryOrchestrator/*
echo ""
echo "The FactoryOrchestrator service is installed as a systemd service!"
echo "Binaies are located at /usr/sbin/FactoryOrchestrator/"
echo "Start it manually with: sudo systemctl start Microsoft.FactoryOrchestrator.service"
echo ""
if [ ! -z "$1" ]&& [ $1 = "enable" ];
then
sudo systemctl enable Microsoft.FactoryOrchestrator.CleanVolatile.service
sudo systemctl enable Microsoft.FactoryOrchestrator.service
echo "The FactoryOrchestrator service is enabled! It will start on next boot or if started manually."
else
echo "The service must be manually started. If you wish to later enable it to start on next boot, run:"
echo "sudo systemctl enable Microsoft.FactoryOrchestrator.CleanVolatile.service; sudo systemctl enable Microsoft.FactoryOrchestrator.service"
fi
trap '' EXIT

Просмотреть файл

@ -0,0 +1,14 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT license.
[Unit]
Description=Microsoft Factory Orchestrator volatile file cleanup service
[Service]
Type=oneshot
ExecStart=/bin/bash /usr/sbin/FactoryOrchestrator/Microsoft.FactoryOrchestrator.CleanVolatile.sh
RemainAfterExit=true
StandardOutput=journal
[Install]
WantedBy=multi-user.target

Просмотреть файл

@ -0,0 +1,4 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT license.
rm /var/log/FactoryOrchestrator/FactoryOrchestratorVolatileServiceStatus.xml

Просмотреть файл

@ -0,0 +1,13 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT license.
[Unit]
Description=Microsoft Factory Orchestrator service
After=Microsoft.FactoryOrchestrator.CleanVolatile.service
Requires=Microsoft.FactoryOrchestrator.CleanVolatile.service
[Service]
Type=notify
ExecStart=/usr/sbin/FactoryOrchestrator/Microsoft.FactoryOrchestrator.Service
[Install]
WantedBy=multi-user.target

Просмотреть файл

@ -1,21 +0,0 @@
MIT License
Copyright (c) 2016 Peter Kottas
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

Просмотреть файл

@ -34,7 +34,6 @@
<StackPanel Orientation="Vertical" VerticalAlignment="Bottom" Grid.Row="3" Margin="5">
<TextBlock x:Name="oss" x:Uid="OSSAcknowledgments" HorizontalAlignment="Center" Style="{StaticResource SubtitleTextBlockStyle}"/>
<TextBlock Text="IpcServiceFramework - Jacques Kang - MIT License - https://github.com/jacqueskang/IpcServiceFramework" HorizontalAlignment="Left"/>
<TextBlock Text="DotNetCore.WindowsService - Peter Kottas - MIT License - https://github.com/PeterKottas/DotNetCore.WindowsService" HorizontalAlignment="Left"/>
<TextBlock Text="WindowsDevicePortalWrapper - Microsoft Corporation and mgurlitz - MIT License - https://github.com/mgurlitz/WindowsDevicePortalWrapper/tree/feat-standard" HorizontalAlignment="Left"/>
<TextBlock Text="Pe-Utility - Andres Traks - MIT License - https://github.com/AndresTraks/pe-utility" HorizontalAlignment="Left"/>
</StackPanel>

Просмотреть файл

@ -54,7 +54,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "OSS", "OSS", "{AB6C2AD9-125
ProjectSection(SolutionItems) = preProject
..\oss\cgmanifest.json = ..\oss\cgmanifest.json
..\oss\Directory.Build.props = ..\oss\Directory.Build.props
..\oss\DotNetCore.WindowsService.txt = ..\oss\DotNetCore.WindowsService.txt
..\oss\IpcServiceFramework.txt = ..\oss\IpcServiceFramework.txt
..\oss\Pe-Utility.txt = ..\oss\Pe-Utility.txt
EndProjectSection
@ -144,6 +143,12 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ServerLibraryUnitTests", "T
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ClientSampleIntegrationTests", "Tests\ClientSampleIntegrationTest\ClientSampleIntegrationTests.csproj", "{9E8EA146-0C62-419D-8ADA-80635F96D30C}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "install", "install", "{B414E410-80A7-435D-B578-D4AD08222EE7}"
ProjectSection(SolutionItems) = preProject
..\install\install.sh = ..\install\install.sh
..\install\Microsoft.FactoryOrchestrator.Service.service = ..\install\Microsoft.FactoryOrchestrator.Service.service
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU

Просмотреть файл

@ -50,7 +50,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "OSS", "OSS", "{AB6C2AD9-125
ProjectSection(SolutionItems) = preProject
..\oss\cgmanifest.json = ..\oss\cgmanifest.json
..\oss\Directory.Build.props = ..\oss\Directory.Build.props
..\oss\DotNetCore.WindowsService.txt = ..\oss\DotNetCore.WindowsService.txt
..\oss\IpcServiceFramework.txt = ..\oss\IpcServiceFramework.txt
..\oss\Pe-Utility.txt = ..\oss\Pe-Utility.txt
EndProjectSection

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -18,13 +18,14 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="3.1.7" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="3.1.7" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="3.1.7" />
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="3.1.7" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="5.0.1" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="5.0.0" />
<PackageReference Include="Microsoft.Extensions.Hosting.Systemd" Version="5.0.1" />
<PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="5.0.1" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="5.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="5.0.0" />
<PackageReference Include="Microsoft.Extensions.PlatformAbstractions" Version="1.1.0" />
<PackageReference Include="Microsoft.Win32.Registry" Version="4.7.0" />
<PackageReference Include="PeterKottas.DotNetCore.WindowsService" Version="2.0.11" />
<PackageReference Include="Microsoft.Win32.Registry" Version="5.0.0" />
</ItemGroup>
<ItemGroup>

Разница между файлами не показана из-за своего большого размера Загрузить разницу