Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Agent MSI support #212

Merged
merged 35 commits into from
Jan 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
f7f4e23
first draft
amitkanfer Nov 19, 2023
0a38799
6
amitkanfer Nov 19, 2023
98a893b
6
amitkanfer Nov 19, 2023
67cd709
Preventing agent upgrade via MSI
amitkanfer Dec 1, 2023
947738e
Update src/installer/BeatPackageCompiler/BeatPackageCompiler.cs
amitkanfer Dec 1, 2023
46c394a
Update README.md
amitkanfer Dec 3, 2023
093e120
Update README.md
amitkanfer Dec 3, 2023
1c32ac2
Fixing uninstall flow and install cleanup flow
amitkanfer Dec 3, 2023
0a40567
Merge branch 'agent_support' of https://github.com/elastic/elastic-st…
amitkanfer Dec 3, 2023
add4b02
rolling back if agent install command fails
amitkanfer Dec 3, 2023
04c589b
redirecting stdout to MSI log
amitkanfer Dec 4, 2023
818cb23
Failing the uninstall flow in case agent uninstall command fails
amitkanfer Dec 5, 2023
8bc764a
Don't attempt calling agent install if the file doesn't exist
amitkanfer Dec 5, 2023
33e978a
Merge branch 'main' into agent_support
amitkanfer Dec 11, 2023
5753acf
adding BK logic (#219)
amitkanfer Dec 12, 2023
f2f637a
Merge branch 'main' into agent_support
amitkanfer Dec 12, 2023
c6df1eb
Update build.ps1
amitkanfer Dec 12, 2023
798ff24
Clean up path length
dliappis Jan 15, 2024
0b933a9
Fix 798ff24da8f65b5b49154cd48ef04f167362b11f
dliappis Jan 15, 2024
50b68bd
Typo
dliappis Jan 15, 2024
566b9e4
Build from MANIFEST_URL and don't sign
dliappis Jan 15, 2024
87fefb7
Update README.md
amitkanfer Jan 16, 2024
0c68b23
Update README.md
amitkanfer Jan 16, 2024
f9f9370
Update README.md
amitkanfer Jan 16, 2024
dab7370
Update README.md
amitkanfer Jan 16, 2024
a3cbdc5
Redirecting stderr and removing PATH manipulation for Agent MSI
amitkanfer Jan 16, 2024
b53ea24
Remove cron schedule
dliappis Jan 17, 2024
fd4793d
Trigger 7.17 beats DRA using schedule
dliappis Jan 18, 2024
41444d5
Making sure Agent MSI runs as an administrator
amitkanfer Jan 18, 2024
7832f16
Merge branch 'agent_support' of https://github.com/elastic/elastic-st…
amitkanfer Jan 18, 2024
a245c94
Add MSI tests for Agent Pipeline (#220)
strawgate Jan 22, 2024
07d0d86
Enabling agent tests
amitkanfer Jan 26, 2024
622fd2b
Disable "Default" test case as it doesn't exist anymore. Don't fail b…
strawgate Jan 29, 2024
00dc987
Default mode clean-up
strawgate Jan 29, 2024
7c6a596
Update build.ps1
strawgate Jan 29, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 11 additions & 11 deletions .buildkite/pipeline.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,22 @@
### The following environment variables can be set for testing purposes via the buildkite UI or CLI
### RUN_SNAPSHOT: "true" - will run the snapshot workflow
### RUN_STAGING: "true" - will run the staging workflow
### DBRANCH: "main" - will override the dra branch param. Default is $BUILDKITE_BRANCH
### ONLY_AGENT: "true" - will build only the elastic-agent msi artifact
###

steps:
- group: ":beats: Stack installers Snapshot"
- group: ":package: Stack installers Snapshot"
key: "dra-snapshot"
steps:
- label: ":hammer: Build stack installers Snapshot"
- label: ":construction_worker: Build stack installers / Snapshot"
command: ".buildkite/scripts/build.ps1"
key: "build-snapshot"
artifact_paths: "bin/out/**/*.msi"
artifact_paths: "c:/users/buildkite/esi/bin/out/**/*.msi"
agents:
provider: gcp
image: family/ci-windows-2022
env:
WORKFLOW: "snapshot"
DRA_WORKFLOW: "snapshot"
- label: ":package: DRA Publish Snapshot"
if: build.branch == 'main' || build.branch =~ /^[0-9]+\.[0-9]+\$/ || build.env("RUN_SNAPSHOT") == "true"
command: ".buildkite/scripts/dra-publish.sh"
Expand All @@ -26,20 +26,20 @@ steps:
agents:
provider: gcp
env:
WORKFLOW: "snapshot"
- group: ":beats: Stack installers Staging :beats:"
DRA_WORKFLOW: "snapshot"
- group: ":package: Stack installers Staging"
key: "dra-staging"
steps:
- label: ":hammer: Build stack installers staging"
- label: ":construction_worker: Build stack installers / Staging"
if: build.branch =~ /^[0-9]+\.[0-9]+\$/ || build.env("RUN_STAGING") == "true"
command: ".buildkite/scripts/build.ps1"
key: "build-staging"
artifact_paths: "bin/out/**/*.msi"
artifact_paths: "c:/users/buildkite/esi/bin/out/**/*.msi"
agents:
provider: gcp
image: family/ci-windows-2022
env:
WORKFLOW: "staging"
DRA_WORKFLOW: "staging"
- label: ":package: DRA Publish staging"
if: build.branch =~ /^[0-9]+\.[0-9]+\$/ || build.env("RUN_STAGING") == "true"
command: ".buildkite/scripts/dra-publish.sh"
Expand All @@ -48,7 +48,7 @@ steps:
agents:
provider: gcp
env:
WORKFLOW: "staging"
DRA_WORKFLOW: "staging"

notify:
- slack: "#ingest-notifications"
Expand Down
151 changes: 94 additions & 57 deletions .buildkite/scripts/build.ps1
Original file line number Diff line number Diff line change
@@ -1,72 +1,93 @@
$ErrorActionPreference = "Stop"
Set-Strictmode -version 3

if (-not (Test-Path env:MANIFEST_URL)) {
$errorMessage = "Error: Required environment variable [MANIFEST_URL] is missing."
Write-Host $errorMessage
throw $errorMessage
}

# workaround path limitation for max 248 characters
# example: https://buildkite.com/elastic/elastic-stack-installers/builds/3104#018c5e1b-23a7-4330-ad5d-4acc69157822/74-180
cd ..
# we can't use Rename-Item because this script runs from within the existing checkout resulting in
# Rename-Item : The process cannot access the file because it is being used by another process.
Copy-Item -Path .\elastic-stack-installers -Destination c:\users\buildkite\esi -Recurse
cd c:\users\buildkite\esi

# Read the stack version from build properties
[xml]$xml = Get-Content -Path "Directory.Build.props"
$ns = New-Object Xml.XmlNamespaceManager($xml.NameTable)
$ns.AddNamespace("ns", "http://schemas.microsoft.com/developer/msbuild/2003")
$stack_version = $xml.SelectSingleNode("//ns:PropertyGroup/ns:StackVersion", $ns).InnerText
Write-Host "Building Stack version: $stack_version"
$workflow = ${env:DRA_WORKFLOW}
if ($workflow -eq "snapshot") {
$version = $stack_version + "-" + $workflow.ToUpper()
} else {
$version = $stack_version
}

echo "~~~ Installing dotnet-sdk"
Write-Host "~~~ Building Stack version: $stack_version"

Write-Output "~~~ Installing dotnet-sdk"
& "./tools/dotnet-install.ps1" -NoPath -JSonFile global.json -Architecture "x64" -InstallDir c:/dotnet-sdk
${env:PATH} = "c:\dotnet-sdk;" + ${env:PATH}
Get-Command dotnet | Select-Object -ExpandProperty Definition

echo "~~~ Reading msi certificate from vault"
$MsiCertificate=& vault read -field=cert secret/ci/elastic-elastic-stack-installers/signing_cert
$MsiPassword=& vault read -field=password secret/ci/elastic-elastic-stack-installers/signing_cert
Remove-Item Env:VAULT_TOKEN

$cert_home="C:/.cert"
New-Item $cert_home -Type Directory -Force
[IO.File]::WriteAllBytes("$cert_home/msi_certificate.p12", [Convert]::FromBase64String($MsiCertificate))
[IO.File]::WriteAllText("$cert_home/msi_password.txt", $MsiPassword)
echo "Certificate successfully written to $cert_home"

$client = new-object System.Net.WebClient
$currentDir = $(Get-Location).Path
$beats = @('auditbeat', 'filebeat', 'heartbeat', 'metricbeat', 'packetbeat', 'winlogbeat')
$ossBeats = $beats | ForEach-Object { $_ + "-oss" }
$workflow = ${env:WORKFLOW}

echo "~~~ downloading beat $workflow dependencies"
# TODO remove (and all references/conditionals below) after testing; this just helps to speed up elastic-agent specific build tests
$onlyAgent = $env:ONLY_AGENT -as [string]

Remove-Item bin/in -Recurse -Force -ErrorAction Ignore
New-Item bin/in -Type Directory -Force
if ($workflow -eq "snapshot") {
$version = $stack_version + "-" + $workflow.ToUpper()
$hostname = "artifacts-snapshot.elastic.co"
$response = Invoke-WebRequest -UseBasicParsing -Uri "https://$hostname/beats/latest/$version.json"
$json = $response.Content | ConvertFrom-Json
$buildId = $json.build_id
$prefix = "$hostname/beats/$buildId"
} else {
$version = $stack_version
$hostname = "artifacts-staging.elastic.co"
$response = Invoke-WebRequest -UseBasicParsing -Uri "https://$hostname/beats/latest/$version.json"
$json = $response.Content | ConvertFrom-Json
$buildId = $json.build_id
$prefix = "$hostname/beats/$buildId"
}
foreach ($beat in ($beats + $ossBeats)) {
try {
$beatName = $beat.Replace("-oss", "")
$url = "https://$prefix/downloads/beats/$beatName/$beat-$version-windows-x86_64.zip"
echo "Downloading from $url"

$manifestUrl = ${env:MANIFEST_URL}
$response = Invoke-WebRequest -UseBasicParsing -Uri $manifestUrl
$json = $response.Content | ConvertFrom-Json

Write-Output "~~~ Downloading $workflow dependencies"

$urls = @()

try {
$packageName = "elastic-agent"
$projectName = "$packageName-package"
$urls += $json.projects.$projectName.packages."$packageName-$version-windows-x86_64.zip".url

if ($onlyAgent -eq "true") {
Write-Output "Skipping beats because env var ONLY_AGENT is set to [$env:ONLY_AGENT]"
}
else {
$projectName = "beats"
foreach ($packageName in ($beats + $ossBeats)) {
$urls += $json.projects.$projectName.packages."$packageName-$version-windows-x86_64.zip".url
}
}
foreach ($url in $urls) {
$destFile = [System.IO.Path]::GetFileName($url)
Write-Output "Downloading from $url to $currentDir/bin/in/$destFile"
$client.DownloadFile(
$url,
"$currentDir/bin/in/$beat-$version-windows-x86_64.zip"
"$currentDir\bin\in\$destFile"
)
}
catch [System.Net.WebException] {
if ($_.Exception.InnerException) {
Write-Error $_.Exception.InnerException.Message
} else {
Write-Error $_.Exception.Message
}
throw "An error was encountered while downloading dependencies, aborting."
} catch [System.Net.WebException] {
if ($_.Exception.InnerException) {
Write-Error $_.Exception.InnerException.Message
} else {
Write-Error $_.Exception.Message
}
throw "An error was encountered while downloading dependencies, aborting."
}

echo "--- Building $workflow msi"
$args = @(
Remove-Item bin/out -Recurse -Force -ErrorAction Ignore

Write-Output "--- Building $workflow msi"
$cliArgs = @(
"run",
"--project",
"src\build\ElastiBuild.csproj",
Expand All @@ -75,25 +96,41 @@ $args = @(
"--",
"build",
"--cid",
$version,
"--cert-file",
"$cert_home/msi_certificate.p12",
"--cert-pass",
"$cert_home/msi_password.txt"
$version
)
$args += ($beats + $ossBeats)
&dotnet $args
$cliArgs += "elastic-agent"
if ($onlyAgent -ne "true") {
$cliArgs += ($beats + $ossBeats)
}

&dotnet $cliArgs
if ($LastExitcode -ne 0) {
Write-Error "Build$workflow failed with exit code $LastExitcode"
Write-Error "Build $workflow failed with exit code $LastExitcode"
exit $LastExitcode
} else {
echo "Build$workflow completed with exit code $LastExitcode"
Write-Output "Build $workflow completed with exit code $LastExitcode"
}

echo "--- Checking that all artefacts are there"
Write-Output "--- Checking that all artifacts are there"
$msiCount = Get-ChildItem bin/out -Include "*.msi" -Recurse | Measure-Object | Select-Object -ExpandProperty Count
$expected = 2 * $beats.Length

$expected = 1
if ($onlyAgent -ne "true") {
$expected += (2 * $beats.Length)
}

if ($msiCount -ne $expected) {
Write-Error "Expected $expected msi executable to be produced, but $msiCount were"
Write-Error "Failed: expected $expected msi executables to be produced, but $msiCount were found."
exit 1
} else {
Write-Output "Success, found $msiCount artifacts in bin/out."
}

try {
& (Join-Path $PSScriptRoot "test.ps1")
write-host "Testing Completed"
} catch {
write-host "Testing Failed"
write-error $_
exit 1
}
45 changes: 45 additions & 0 deletions .buildkite/scripts/test.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
$ErrorActionPreference = "Stop"
Set-Strictmode -version 3

write-host (ConvertTo-Json $PSVersiontable -Compress)
write-host "Running as: $([Environment]::UserName)"

write-host "`$env:AGENT = $($Env:AGENT)"

if ($psversiontable.psversion -lt "7.4.0") {
# Download Powershell Core, and rerun this script using Powershell Core

write-host "Downloading Powershell Core"
invoke-webrequest -uri https://github.com/PowerShell/PowerShell/releases/download/v7.4.0/PowerShell-7.4.0-win-x64.zip -outfile pwsh.zip

write-host "Expanding Powershell Core"
Expand-Archive pwsh.zip -destinationpath (Join-Path $PSScriptRoot "pwsh")

Write-host "Invoking from Powershell Core"
& (Join-Path $PSScriptRoot "pwsh/pwsh.exe") -file (Join-Path $PSScriptRoot "test.ps1")

if ($LASTEXITCODE -eq 0) {
write-host "Child pwsh process exited successfully"
exit 0
} else {
write-host "Child pwsh process returned $LASTEXITCODE, a non zero exit code"
throw "Tests failed."
}
}

$AgentMSI = Get-ChildItem bin/out -Include "elastic-agent*.msi" -Recurse

if ($AgentMSI -eq $null) {
write-error "No agent MSI found to test"
}


$OldAgentMSI = (Join-Path $PSScriptRoot "elastic-agent-8.11.4-windows-x86_64.msi")
if (-not (test-path $OldAgentMSI)) {
Write-Host "Downloading older MSI for upgrade tests"
invoke-webrequest -uri https://storage.googleapis.com/agent-msi-testing/elastic-agent-8.11.4-windows-x86_64.msi -outfile $OldAgentMSI
}

& (Join-Path $PSScriptRoot "../../src/agent-qa/Invoke-Pester.ps1") -PathToLatestMSI $AgentMSI.Fullname -PathToEarlyMSI $OldAgentMSI

write-host "Returned from Pester Test"
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -63,4 +63,6 @@ src/*.cmd
# Executable Artifacts
src/*.exe
src/*.pdb
src/*.dll
src/*.dll
pwsh
pwsh.zip
25 changes: 25 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,28 @@ Update version in `Directory.Build.props` in the branch for the related minor ve
- Add a new daily schedule for the new minor branch
- Remove the daily schedule for the previous minor branch
ex: https://github.com/elastic/elastic-stack-installers/pull/156 and https://github.com/elastic/elastic-stack-installers/pull/172

---
## Agent

In case of problems during install / uninstall of agent, please refer to the [Capturing Logs](https://github.com/elastic/elastic-stack-installers/blob/agent_support/README.md#capturing-logs) section which will enable troubleshooting.

### Install
During the install flow, The MSI installer will unpack the contents of the MSI to a temp folder and then will call the `elastic-agent install` in order to:
1. copy the files to the final destination at `c:\Program Files\Elastic\Agent`
2. register the agent as a windows service
3. enroll the agent into fleet

In order to complete step 3 above, the MSI installer shall receive command line arguments, passed with INSTALLARGS command line switch followed by `"`, for example:
```
elastic-agent.msi INSTALLARGS="--url=<fleet_url_with_port> --enrollment-token=<token>"
```

Note that the MSI will call the `elastic-agent install` command with `-f` (force) to avoid user interaction.

### Uninstall
Similarly to the install flow (described above), the MSI will call the `elastic-agent uninstall` command, and it's possible to pass arguments using `INSTALLARGS`. One common use case is uninstalling an agent which has tamper protection enabled.

### Upgrade
The Agent MSI doesn't support upgrade. Since the agents are fleet managed, upgrades shall be done using fleet (UI / API).

16 changes: 2 additions & 14 deletions catalog-info.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,6 @@ spec:
publish_commit_status: true
publish_commit_status_per_step: false
repository: elastic/elastic-stack-installers
schedules:
Daily main:
branch: main
cronline: "@daily"
message: Builds daily `main` stack-installers dra
teams:
everyone:
access_level: BUILD_AND_READ
Expand Down Expand Up @@ -93,15 +88,8 @@ spec:
publish_commit_status_per_step: false
repository: elastic/elastic-stack-installers
schedules:
Daily 8_12:
branch: "8.12"
cronline: "*/10 * * * *"
message: Checking for new beats artifacts for `8.12`
Daily 8_11:
branch: "8.11"
cronline: "*/10 * * * *"
message: Checking for new beats artifacts for `8.11`
Weekly main:
# trigger for 7_17 still needed for now, details in https://elasticco.atlassian.net/browse/REL-1004?focusedCommentId=107973
Daily 7_17:
branch: "7.17"
cronline: "*/10 * * * *"
message: Checking for new beats artifacts for `7.17`
Expand Down
11 changes: 11 additions & 0 deletions src/CustomAction.config
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup useLegacyV2RuntimeActivationPolicy="true">
<supportedRuntime version="v4.0.30319"/>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5"/>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/>
<supportedRuntime version="v2.0.50727"/>
<supportedRuntime version="v2.0.50215"/>
<supportedRuntime version="v1.1.4322"/>
</startup>
</configuration>
Loading