Skip to content

Commit

Permalink
Add support for netstandard2.0
Browse files Browse the repository at this point in the history
* Add `net472` target framework to Tests.csproj
* Add Windows build
* Cache installers on Windows
* Fix Windows `rabbitmq.conf` for TLS
* Disable AltCover on Windows
* You cannot do EXTERNAL auth without the correct plugin enabled /facepalm
* Use `LangVersion` 9 in library
* Do not error when inet_error is seen in build-windows action
  • Loading branch information
lukebakken committed Aug 27, 2024
1 parent 53b8b1d commit de2520b
Show file tree
Hide file tree
Showing 58 changed files with 4,348 additions and 3,445 deletions.
2 changes: 1 addition & 1 deletion .ci/ubuntu/enabled_plugins
Original file line number Diff line number Diff line change
@@ -1 +1 @@
[rabbitmq_auth_mechanism_ssl,rabbitmq_management].
[rabbitmq_auth_mechanism_ssl,rabbitmq_management,rabbitmq_stream,rabbitmq_stream_management,rabbitmq_top].
5 changes: 3 additions & 2 deletions .ci/ubuntu/rabbitmq.conf
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
loopback_users = none
loopback_users.guest = true

log.console = true
log.console.level = debug
Expand All @@ -16,9 +17,9 @@ ssl_options.cacertfile = /etc/rabbitmq/certs/ca_certificate.pem
ssl_options.certfile = /etc/rabbitmq/certs/server_localhost_certificate.pem
ssl_options.keyfile = /etc/rabbitmq/certs/server_localhost_key.pem
ssl_options.verify = verify_peer
ssl_options.password = grapefruit
ssl_options.depth = 1
ssl_options.fail_if_no_peer_cert = false
ssl_options.password = grapefruit
ssl_options.depth = 1

auth_mechanisms.1 = PLAIN
auth_mechanisms.2 = EXTERNAL
1 change: 1 addition & 0 deletions .ci/windows/enabled_plugins
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
[rabbitmq_auth_mechanism_ssl,rabbitmq_management,rabbitmq_stream,rabbitmq_stream_management,rabbitmq_top].
14 changes: 14 additions & 0 deletions .ci/windows/gha-log-check.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
$ProgressPreference = 'Continue'
$VerbosePreference = 'Continue'
$ErrorActionPreference = 'Stop'
Set-StrictMode -Version 2.0

$rabbitmq_log_dir = Join-Path -Path $env:AppData -ChildPath 'RabbitMQ' | Join-Path -ChildPath 'log'
Write-Host "[INFO] looking for errors in '$rabbitmq_log_dir'"

If (Get-ChildItem $rabbitmq_log_dir\*.log | Select-String -Quiet -SimpleMatch -Pattern inet_error)
{
# Note: only issuing a warning since `inet_error,econnaborted` can be found
# in Windows test runs
Write-Host "[WARNING] found inet_error in '$rabbitmq_log_dir'"
}
247 changes: 247 additions & 0 deletions .ci/windows/gha-setup.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,247 @@
$ProgressPreference = 'Continue'
$VerbosePreference = 'Continue'
$ErrorActionPreference = 'Stop'
Set-StrictMode -Version 2.0

[Net.ServicePointManager]::SecurityProtocol = [Net.ServicePointManager]::SecurityProtocol -bor 'Tls12'

New-Variable -Name curdir -Option Constant -Value $PSScriptRoot
Write-Host "[INFO] curdir: $curdir"

New-Variable -Name ci_dir -Option Constant -Value (Join-Path -Path $env:GITHUB_WORKSPACE -ChildPath '.ci')

New-Variable -Name certs_dir -Option Constant -Value (Join-Path -Path $ci_dir -ChildPath 'certs')

New-Variable -Name ci_windows_dir -Option Constant -Value (Join-Path -Path $ci_dir -ChildPath 'windows')

New-Variable -Name ca_certificate_file -Option Constant -Value `
(Resolve-Path -LiteralPath (Join-Path -Path $certs_dir -ChildPath 'ca_certificate.pem'))

New-Variable -Name enabled_plugins_file -Option Constant -Value `
(Resolve-Path -LiteralPath (Join-Path -Path $ci_windows_dir -ChildPath 'enabled_plugins'))

Write-Host "[INFO] importing CA cert from '$ca_certificate_file'"
Import-Certificate -Verbose -CertStoreLocation Cert:\LocalMachine\Root -FilePath $ca_certificate_file

New-Variable -Name versions_path -Option Constant -Value `
(Resolve-Path -LiteralPath (Join-Path -Path $ci_windows_dir -ChildPath 'versions.json'))
$versions = Get-Content $versions_path | ConvertFrom-Json
Write-Host "[INFO] versions: $versions"
$erlang_ver = $versions.erlang
$rabbitmq_ver = $versions.rabbitmq

$base_installers_dir = Join-Path -Path $HOME -ChildPath 'installers'
if (-Not (Test-Path $base_installers_dir))
{
New-Item -Verbose -ItemType Directory $base_installers_dir
}

$erlang_download_url = "https://github.com/erlang/otp/releases/download/OTP-$erlang_ver/otp_win64_$erlang_ver.exe"
$erlang_installer_path = Join-Path -Path $base_installers_dir -ChildPath "otp_win64_$erlang_ver.exe"
$erlang_install_dir = Join-Path -Path $HOME -ChildPath 'erlang'

Write-Host '[INFO] Downloading Erlang...'

if (-Not (Test-Path -LiteralPath $erlang_installer_path))
{
Invoke-WebRequest -UseBasicParsing -Uri $erlang_download_url -OutFile $erlang_installer_path
}
else
{
Write-Host "[INFO] Found '$erlang_installer_path' in cache!"
}

Write-Host "[INFO] Installing Erlang to $erlang_install_dir..."
& $erlang_installer_path '/S' "/D=$erlang_install_dir" | Out-Null

# https://github.com/rabbitmq/rabbitmq-server/releases/download/v4.0.0-beta.5/rabbitmq-server-windows-4.0.0-beta.5.zip
$rabbitmq_installer_download_url = "https://github.com/rabbitmq/rabbitmq-server/releases/download/v$rabbitmq_ver/rabbitmq-server-$rabbitmq_ver.exe"
$rabbitmq_installer_path = Join-Path -Path $base_installers_dir -ChildPath "rabbitmq-server-$rabbitmq_ver.exe"
Write-Host "[INFO] rabbitmq installer path $rabbitmq_installer_path"

if (Test-Path -LiteralPath 'HKLM:\SOFTWARE\WOW6432Node\')
{
New-Variable -Name erlangRegKeyPath -Option Constant `
-Value 'HKLM:\SOFTWARE\WOW6432Node\Ericsson\Erlang'
}
else
{
New-Variable -Name erlangRegKeyPath -Option Constant `
-Value 'HKLM:\SOFTWARE\Ericsson\Erlang'
}

New-Variable -Name erlangRegKey -Option Constant `
-Value (Get-ChildItem $erlangRegKeyPath)

if ($erlangRegKey -eq $null) {
Write-Error "Could not find Erlang installation registry key at $erlangRegKeyPath"
}

New-Variable -Name erlangErtsVersion -Option Constant `
-Value (Select-Object -InputObject $erlangRegKey -Last 1).PSChildName
Write-Verbose "erlangErtsVersion: $erlangErtsVersion"

New-Variable -Name erlangErtsRegKeyPath -Option Constant `
-Value "HKLM:\SOFTWARE\WOW6432Node\Ericsson\Erlang\$erlangErtsVersion"

New-Variable -Name erlangErtsRegKey -Option Constant `
-Value (Get-ItemProperty -LiteralPath HKLM:\SOFTWARE\WOW6432Node\Ericsson\Erlang\$erlangErtsVersion)

if ($erlangErtsRegKey -eq $null) {
Write-Error "Could not find Erlang erts registry key at $erlangErtsRegKeyPath"
}

New-Variable -Name erlangProgramFilesPath -Option Constant `
-Value ($erlangErtsRegKey.'(default)')

if (Test-Path -LiteralPath $erlangProgramFilesPath) {
Write-Verbose "Erlang installation directory: '$erlangProgramFilesPath'"
}
else {
Write-Error 'Could not find Erlang installation directory!'
}

New-Variable -Name allowedExes -Option Constant -Value @('erl.exe', 'epmd.exe', 'werl.exe')

New-Variable -Name exes -Option Constant -Value `
$(Get-ChildItem -Filter '*.exe' -Recurse -LiteralPath $erlangProgramFilesPath | Where-Object { $_.Name -in $allowedExes })

foreach ($exe in $exes) {
$fwRuleName = "rabbitmq-allow-$($exe.Name)-$(Get-Random)"
Write-Verbose "Updating or creating firewall rule for '$exe' - fwRuleName: $fwRuleName"
if (!(Get-NetFirewallRule -ErrorAction 'SilentlyContinue' -Name $fwRuleName)) {
New-NetFirewallRule -Enabled True -Name $fwRuleName -DisplayName $fwRuleName -Direction In -Program $exe -Profile Any -Action Allow
}
else {
Set-NetFirewallRule -Enabled True -Name $fwRuleName -DisplayName $fwRuleName -Direction In -Program $exe -Profile Any -Action Allow
}
}

Write-Host "[INFO] Setting ERLANG_HOME to '$erlangProgramFilesPath'..."
$env:ERLANG_HOME = $erlangProgramFilesPath
[Environment]::SetEnvironmentVariable('ERLANG_HOME', $erlangProgramFilesPath, 'Machine')
Add-Content -Verbose -LiteralPath $env:GITHUB_ENV -Value "ERLANG_HOME=$erlangProgramFilesPath"

Write-Host "[INFO] Setting RABBITMQ_SERVER_ADDITIONAL_ERL_ARGS..."
$env:RABBITMQ_SERVER_ADDITIONAL_ERL_ARGS = '-rabbitmq_stream advertised_host localhost'
[Environment]::SetEnvironmentVariable('RABBITMQ_SERVER_ADDITIONAL_ERL_ARGS', '-rabbitmq_stream advertised_host localhost', 'Machine')

Write-Host '[INFO] Downloading RabbitMQ...'

if (-Not (Test-Path -LiteralPath $rabbitmq_installer_path))
{
Invoke-WebRequest -UseBasicParsing -Uri $rabbitmq_installer_download_url -OutFile $rabbitmq_installer_path
}
else
{
Write-Host "[INFO] Found '$rabbitmq_installer_path' in cache!"
}

Write-Host "[INFO] Installer dir '$base_installers_dir' contents:"
Get-ChildItem -Verbose -LiteralPath $base_installers_dir

$rabbitmq_conf_in_file = Join-Path -Path $ci_windows_dir -ChildPath 'rabbitmq.conf.in'
$rabbitmq_appdata_dir = Join-Path -Path $env:AppData -ChildPath 'RabbitMQ'
New-Item -Path $rabbitmq_appdata_dir -ItemType Directory
$rabbitmq_conf_file = Join-Path -Path $rabbitmq_appdata_dir -ChildPath 'rabbitmq.conf'
$rabbitmq_enabled_plugins_file = Join-Path -Path $rabbitmq_appdata_dir -ChildPath 'enabled_plugins'

Write-Host "[INFO] Creating RabbitMQ configuration file in '$rabbitmq_appdata_dir'"
Get-Content $rabbitmq_conf_in_file | %{ $_ -replace '@@CERTS_DIR@@', $certs_dir } | %{ $_ -replace '\\', '/' } | Set-Content -LiteralPath $rabbitmq_conf_file
Get-Content $rabbitmq_conf_file

Write-Host "[INFO] Copying '$enabled_plugins_file' to '$rabbitmq_enabled_plugins_file'"
Copy-Item -Verbose -Force -LiteralPath $enabled_plugins_file -Destination $rabbitmq_enabled_plugins_file

Write-Host '[INFO] Creating Erlang cookie files...'

function Set-ErlangCookie
{
Param($Path, $Value = 'RABBITMQ-COOKIE')
Remove-Item -Force $Path -ErrorAction SilentlyContinue
[System.IO.File]::WriteAllText($Path, $Value, [System.Text.Encoding]::ASCII)
}

$erlang_cookie_user = Join-Path -Path $HOME -ChildPath '.erlang.cookie'
$erlang_cookie_system = Join-Path -Path $env:SystemRoot -ChildPath 'System32\config\systemprofile\.erlang.cookie'

Set-ErlangCookie -Path $erlang_cookie_user
Set-ErlangCookie -Path $erlang_cookie_system

Write-Host '[INFO] Installing and starting RabbitMQ...'

& $rabbitmq_installer_path '/S' | Out-Null
(Get-Service -Name RabbitMQ).Status

$rabbitmq_base_path = (Get-ItemProperty -Name Install_Dir -LiteralPath 'HKLM:\SOFTWARE\WOW6432Node\VMware, Inc.\RabbitMQ Server').Install_Dir
$regPath = 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\RabbitMQ'
if (Test-Path -LiteralPath 'HKLM:\SOFTWARE\WOW6432Node\')
{
$regPath = 'HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\RabbitMQ'
}
$rabbitmq_version = (Get-ItemProperty $regPath 'DisplayVersion').DisplayVersion
Write-Host "[INFO] RabbitMQ version path: $rabbitmq_base_path and version: $rabbitmq_version"

$rabbitmq_home = Join-Path -Path $rabbitmq_base_path -ChildPath "rabbitmq_server-$rabbitmq_version"
Write-Host "[INFO] Setting RABBITMQ_HOME to '$rabbitmq_home'..."
[Environment]::SetEnvironmentVariable('RABBITMQ_HOME', $rabbitmq_home, 'Machine')
$env:RABBITMQ_HOME = $rabbitmq_home

$rabbitmqctl_path = Join-Path -Path $rabbitmq_base_path -ChildPath "rabbitmq_server-$rabbitmq_version" | Join-Path -ChildPath 'sbin' | Join-Path -ChildPath 'rabbitmqctl.bat'
$rabbitmq_plugins_path = Join-Path -Path $rabbitmq_base_path -ChildPath "rabbitmq_server-$rabbitmq_version" | Join-Path -ChildPath 'sbin' | Join-Path -ChildPath 'rabbitmq-plugins.bat'

$epmd_running = $false
[int]$count = 1

$epmd_exe = Join-Path -Path $erlangProgramFilesPath -ChildPath "erts-$erlangErtsVersion" | Join-Path -ChildPath 'bin' | Join-Path -ChildPath 'epmd.exe'

Write-Host "[INFO] Waiting for epmd ($epmd_exe) to report that RabbitMQ has started..."

Do {
$epmd_running = & $epmd_exe -names | Select-String -CaseSensitive -SimpleMatch -Quiet -Pattern 'name rabbit at port'
if ($epmd_running -eq $true) {
Write-Host '[INFO] epmd reports that RabbitMQ is running!'
break
}

if ($count -gt 60) {
throw '[ERROR] too many tries waiting for epmd to report RabbitMQ running!'
}

Write-Host "[INFO] epmd NOT reporting yet that RabbitMQ is running, count: '$count'..."
$count = $count + 1
Start-Sleep -Seconds 5

} While ($true)

[int]$count = 1

Do {
$proc_id = (Get-Process -Name erl).Id
if (-Not ($proc_id -is [array])) {
& $rabbitmqctl_path await_startup
if ($LASTEXITCODE -ne 0) {
throw "[ERROR] 'rabbitmqctl await_startup' returned error: $LASTEXITCODE"
}
break
}

if ($count -gt 120) {
throw '[ERROR] too many tries waiting for just one erl process to be running!'
}

Write-Host '[INFO] multiple erl instances running still...'
$count = $count + 1
Start-Sleep -Seconds 5

} While ($true)

$ErrorActionPreference = 'Continue'
Write-Host '[INFO] Getting RabbitMQ status...'
& $rabbitmqctl_path status

echo Q | openssl s_client -connect localhost:5671 -CAfile "$certs_dir/ca_certificate.pem" -cert "$certs_dir/client_localhost_certificate.pem" -key "$certs_dir/client_localhost_key.pem" -pass pass:grapefruit
if ($LASTEXITCODE -ne 0)
{
throw "[ERROR] 'openssl s_client' returned error: $LASTEXITCODE"
}
23 changes: 23 additions & 0 deletions .ci/windows/rabbitmq.conf.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
loopback_users = none
loopback_users.guest = true

log.console = false
log.file.level = debug
log.exchange = false

listeners.tcp.default = 5672
listeners.ssl.default = 5671
reverse_dns_lookups = false

deprecated_features.permit.amqp_address_v1 = false

ssl_options.cacertfile = @@CERTS_DIR@@/ca_certificate.pem
ssl_options.certfile = @@CERTS_DIR@@/server_localhost_certificate.pem
ssl_options.keyfile = @@CERTS_DIR@@/server_localhost_key.pem
ssl_options.verify = verify_peer
ssl_options.password = grapefruit
ssl_options.depth = 1
ssl_options.fail_if_no_peer_cert = false

auth_mechanisms.1 = PLAIN
auth_mechanisms.2 = EXTERNAL
4 changes: 4 additions & 0 deletions .ci/windows/versions.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"erlang": "26.2.5.2",
"rabbitmq": "4.0.0-beta.5"
}
49 changes: 41 additions & 8 deletions .github/workflows/build-test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,46 @@ on:


jobs:
build:
build-win32:
runs-on: windows-latest
# https://github.com/NuGet/Home/issues/11548
env:
NUGET_CERT_REVOCATION_MODE: offline
steps:
- uses: actions/checkout@v4
- uses: actions/cache@v4
with:
# Note: the cache path is relative to the workspace directory
# https://docs.github.com/en/actions/using-workflows/caching-dependencies-to-speed-up-workflows#using-the-cache-action
path: ~/installers
key: ${{ runner.os }}-v0-${{ hashFiles('.ci/windows/versions.json') }}
- uses: actions/cache@v4
with:
path: |
~/.nuget/packages
~/AppData/Local/NuGet/v3-cache
key: ${{ runner.os }}-v0-nuget-${{ hashFiles('**/*.csproj') }}
restore-keys: |
${{ runner.os }}-v0-nuget-
- name: Build (Debug)
run: dotnet build ${{ github.workspace }}\Build.csproj
- name: Verify
run: dotnet format ${{ github.workspace }}\rabbitmq-amqp-dotnet-client.sln --no-restore --verify-no-changes
- name: Install and Start RabbitMQ
id: install-start-rabbitmq
run: ${{ github.workspace }}\.ci\windows\gha-setup.ps1
- name: Test
timeout-minutes: 15
run: dotnet test ${{ github.workspace }}\Build.csproj --no-restore --no-build --logger 'console;verbosity=detailed'
- name: Check for errors in RabbitMQ logs
run: ${{ github.workspace }}\.ci\windows\gha-log-check.ps1
- name: Maybe upload RabbitMQ logs
if: failure()
uses: actions/upload-artifact@v4
with:
name: rabbitmq-logs-integration-win32
path: ~/AppData/Roaming/RabbitMQ/log/
build-ubuntu:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
Expand All @@ -20,21 +59,15 @@ jobs:
- name: Build (Debug)
run: dotnet build ${{ github.workspace }}/Build.csproj
- name: Verify
run: dotnet format ${{ github.workspace }}/Build.csproj --no-restore --verify-no-changes
run: dotnet format ${{ github.workspace }}/rabbitmq-amqp-dotnet-client.sln --no-restore --verify-no-changes
- name: Start RabbitMQ
id: start-rabbitmq
# Note: not using toxiproxy yet
# run: ${{ github.workspace }}/.ci/ubuntu/gha-setup.sh toxiproxy
run: ${{ github.workspace }}/.ci/ubuntu/gha-setup.sh
- name: Test
timeout-minutes: 15
run: dotnet test ${{ github.workspace }}/Build.csproj --no-restore --no-build --logger "console;verbosity=detailed" /p:AltCover=true /p:AltCoverStrongNameKey=${{github.workspace}}/rabbit.snk
- name: Check for errors in RabbitMQ logs
run: ${{ github.workspace}}/.ci/ubuntu/gha-log-check.sh
# Note: not using toxiproxy yet
# - name: Maybe collect toxiproxy logs
# if: failure()
# run: docker logs rabbitmq-amqp-dotnet-client-toxiproxy > ${{ github.workspace }}/.ci/ubuntu/log/toxiproxy.log
- name: Maybe upload RabbitMQ logs
if: failure()
uses: actions/upload-artifact@v4
Expand Down
Loading

0 comments on commit de2520b

Please sign in to comment.