[Fleet] Add msi installer command for fleet server and agents (#217217)

Closes https://github.com/elastic/kibana/issues/206629

## Summary

Added MSI windows commands for fleet server, managed agents and
standalone agents.
Docs about this type of install are
[here](https://www.elastic.co/guide/en/fleet/8.17/install-agent-msi.html)

### Testing
- Add a fleet server and verify that there is a new platform type
`Windows MSI`
- It should be available also for elastic agents, both managed and
standalone

<img width="793" alt="Screenshot 2025-04-04 at 16 34 04"
src="https://github.com/user-attachments/assets/59cf5ea8-566d-4488-9a56-8ec2e9a1f3de"
/>
<img width="764" alt="Screenshot 2025-04-04 at 16 45 00"
src="https://github.com/user-attachments/assets/0d0f9b51-0982-41a4-a32f-02a46b75e5a4"
/>
<img width="784" alt="Screenshot 2025-04-04 at 17 21 34"
src="https://github.com/user-attachments/assets/3dfd0c25-c9f8-47bf-bc3d-e9c9ff9c5417"
/>


### Checklist

- [ ] Any text added follows [EUI's writing
guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses
sentence case text and includes [i18n
support](https://github.com/elastic/kibana/blob/main/src/platform/packages/shared/kbn-i18n/README.md)
- [ ]
[Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html)
was added for features that require explanation or tutorials
- [ ] [Unit or functional
tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)
were updated or added to match the most common scenarios

---------

Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
This commit is contained in:
Cristina Amico 2025-04-10 14:26:16 +02:00 committed by GitHub
parent 827199b8a1
commit f87cf9c8b4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 213 additions and 36 deletions

View file

@ -84,6 +84,7 @@ const InstallFleetServerStepContent: React.FunctionComponent<{
'rpm_x86_64',
'deb_aarch64',
'deb_x86_64',
'windows_msi',
] as PLATFORM_TYPE[]
).reduce((acc, platform) => {
acc[platform] = getInstallCommandForPlatform({

View file

@ -113,6 +113,23 @@ describe('getInstallCommandForPlatform', () => {
`);
});
it('should return the correct command if the the policyId is not set for windows MSI', () => {
const res = getInstallCommandForPlatform({
platform: 'windows_msi',
esOutputHost: 'http://elasticsearch:9200',
serviceToken: 'service-token-1',
});
expect(res).toMatchInlineSnapshot(`
"$ProgressPreference = 'SilentlyContinue'
Invoke-WebRequest -Uri https://artifacts.elastic.co/downloads/beats/elastic-agent/elastic-agent--windows-x86_64.msi -OutFile elastic-agent--windows-x86_64.msi
.\\\\elastic-agent.msi --% INSTALLARGS=\\"\`
--fleet-server-es=http://elasticsearch:9200 \`
--fleet-server-service-token=service-token-1 \`
--fleet-server-port=8220 \`
--install-servers\\""
`);
});
it('should return the correct command if the the policyId is not set for rpm', () => {
expect(
getInstallCommandForPlatform({
@ -322,6 +339,26 @@ describe('getInstallCommandForPlatform', () => {
`);
});
it('should return the correct command if the the policyId is set for windows MSI', () => {
const res = getInstallCommandForPlatform({
platform: 'windows_msi',
esOutputHost: 'http://elasticsearch:9200',
serviceToken: 'service-token-1',
policyId: 'policy-1',
});
expect(res).toMatchInlineSnapshot(`
"$ProgressPreference = 'SilentlyContinue'
Invoke-WebRequest -Uri https://artifacts.elastic.co/downloads/beats/elastic-agent/elastic-agent--windows-x86_64.msi -OutFile elastic-agent--windows-x86_64.msi
.\\\\elastic-agent.msi --% INSTALLARGS=\\"\`
--fleet-server-es=http://elasticsearch:9200 \`
--fleet-server-service-token=service-token-1 \`
--fleet-server-policy=policy-1 \`
--fleet-server-port=8220 \`
--install-servers\\""
`);
});
it('should return the correct command if the the policyId is set for rpm', () => {
expect(
getInstallCommandForPlatform({
@ -576,6 +613,31 @@ describe('getInstallCommandForPlatform', () => {
--install-servers"
`);
});
it('should return the correct command if the the policyId is set for windows MSI', () => {
const res = getInstallCommandForPlatform({
platform: 'windows_msi',
esOutputHost: 'http://elasticsearch:9200',
serviceToken: 'service-token-1',
policyId: 'policy-1',
fleetServerHost,
isProductionDeployment: true,
});
expect(res).toMatchInlineSnapshot(`
"$ProgressPreference = 'SilentlyContinue'
Invoke-WebRequest -Uri https://artifacts.elastic.co/downloads/beats/elastic-agent/elastic-agent--windows-x86_64.msi -OutFile elastic-agent--windows-x86_64.msi
.\\\\elastic-agent.msi --% INSTALLARGS=\\"--url=http://fleetserver:8220 \`
--fleet-server-es=http://elasticsearch:9200 \`
--fleet-server-service-token=service-token-1 \`
--fleet-server-policy=policy-1 \`
--certificate-authorities=<PATH_TO_CA> \`
--fleet-server-es-ca=<PATH_TO_ES_CERT> \`
--fleet-server-cert=<PATH_TO_FLEET_SERVER_CERT> \`
--fleet-server-cert-key=<PATH_TO_FLEET_SERVER_CERT_KEY> \`
--fleet-server-port=8220 \`
--install-servers\\""
`);
});
it('should return the correct command if the the policyId is set for rpm', () => {
expect(
@ -709,21 +771,21 @@ describe('getInstallCommandForPlatform', () => {
});
expect(res).toMatchInlineSnapshot(`
"curl -L -O https://artifacts.elastic.co/downloads/beats/elastic-agent/elastic-agent--amd64.deb
sudo dpkg -i elastic-agent--amd64.deb
sudo systemctl enable elastic-agent
sudo systemctl start elastic-agent
sudo elastic-agent enroll --url=http://fleetserver:8220 \\\\
--fleet-server-es=http://elasticsearch:9200 \\\\
--fleet-server-service-token=service-token-1 \\\\
--fleet-server-policy=policy-1 \\\\
--certificate-authorities='cert authorities' \\\\
--fleet-server-es-ca='path/to/EScert' \\\\
--fleet-server-cert='path/to/cert' \\\\
--fleet-server-cert-key=<PATH_TO_FLEET_SERVER_CERT_KEY> \\\\
--fleet-server-port=8220 \\\\
--install-servers"
`);
"curl -L -O https://artifacts.elastic.co/downloads/beats/elastic-agent/elastic-agent--amd64.deb
sudo dpkg -i elastic-agent--amd64.deb
sudo systemctl enable elastic-agent
sudo systemctl start elastic-agent
sudo elastic-agent enroll --url=http://fleetserver:8220 \\\\
--fleet-server-es=http://elasticsearch:9200 \\\\
--fleet-server-service-token=service-token-1 \\\\
--fleet-server-policy=policy-1 \\\\
--certificate-authorities='cert authorities' \\\\
--fleet-server-es-ca='path/to/EScert' \\\\
--fleet-server-cert='path/to/cert' \\\\
--fleet-server-cert-key=<PATH_TO_FLEET_SERVER_CERT_KEY> \\\\
--fleet-server-port=8220 \\\\
--install-servers"
`);
});
it('should return the command with SSL options and placeholders', () => {
const fullFleetServerHost = {
@ -743,21 +805,21 @@ describe('getInstallCommandForPlatform', () => {
});
expect(res).toMatchInlineSnapshot(`
"curl -L -O https://artifacts.elastic.co/downloads/beats/elastic-agent/elastic-agent--amd64.deb
sudo dpkg -i elastic-agent--amd64.deb
sudo systemctl enable elastic-agent
sudo systemctl start elastic-agent
sudo elastic-agent enroll --url=http://fleetserver:8220 \\\\
--fleet-server-es=http://elasticsearch:9200 \\\\
--fleet-server-service-token=service-token-1 \\\\
--fleet-server-policy=policy-1 \\\\
--certificate-authorities='cert authorities' \\\\
--fleet-server-es-ca=<PATH_TO_ES_CERT> \\\\
--fleet-server-cert='path/to/cert' \\\\
--fleet-server-cert-key=<PATH_TO_FLEET_SERVER_CERT_KEY> \\\\
--fleet-server-port=8220 \\\\
--install-servers"
`);
"curl -L -O https://artifacts.elastic.co/downloads/beats/elastic-agent/elastic-agent--amd64.deb
sudo dpkg -i elastic-agent--amd64.deb
sudo systemctl enable elastic-agent
sudo systemctl start elastic-agent
sudo elastic-agent enroll --url=http://fleetserver:8220 \\\\
--fleet-server-es=http://elasticsearch:9200 \\\\
--fleet-server-service-token=service-token-1 \\\\
--fleet-server-policy=policy-1 \\\\
--certificate-authorities='cert authorities' \\\\
--fleet-server-es-ca=<PATH_TO_ES_CERT> \\\\
--fleet-server-cert='path/to/cert' \\\\
--fleet-server-cert-key=<PATH_TO_FLEET_SERVER_CERT_KEY> \\\\
--fleet-server-port=8220 \\\\
--install-servers"
`);
});
});
});
@ -973,6 +1035,46 @@ describe('getInstallCommandForPlatform', () => {
--proxy-url=http://es-proxy:1111"
`);
});
it('should return the correct command if proxies are set for windows MSI', () => {
const res = getInstallCommandForPlatform({
platform: 'windows_msi',
esOutputHost: 'http://elasticsearch:9200',
esOutputProxy: {
id: 'es-proxy',
name: 'es-proxy',
url: 'http://es-proxy:1111',
is_preconfigured: false,
},
serviceToken: 'service-token-1',
policyId: 'policy-1',
fleetServerHost,
downloadSource: {
id: 'download-src',
name: 'download-src',
host: 'https://download-src/8.12.0-test/',
is_default: false,
proxy_id: 'download-proxy',
},
downloadSourceProxy: {
id: 'download-src-proxy',
name: 'download-src-proxy',
url: 'http://download-src-proxy:2222',
is_preconfigured: false,
},
});
expect(res).toMatchInlineSnapshot(`
"$ProgressPreference = 'SilentlyContinue'
Invoke-WebRequest -Uri https://download-src/8.12.0-test/beats/elastic-agent/elastic-agent--windows-x86_64.msi -OutFile elastic-agent--windows-x86_64.msi -Proxy \\"http://download-src-proxy:2222\\"
.\\\\elastic-agent.msi --% INSTALLARGS=\\"\`
--fleet-server-es=http://elasticsearch:9200 \`
--fleet-server-service-token=service-token-1 \`
--fleet-server-policy=policy-1 \`
--fleet-server-port=8220 \`
--install-servers \`
--proxy-url=http://es-proxy:1111\\""
`);
});
it('should return the correct command if proxies are set for rpm', () => {
expect(
@ -1356,6 +1458,56 @@ describe('getInstallCommandForPlatform', () => {
--proxy-header=\\"test-header=test-value\\""
`);
});
it('should return the correct command if proxies are set for windows MSI', () => {
const res = getInstallCommandForPlatform({
platform: 'windows_msi',
esOutputHost: 'http://elasticsearch:9200',
esOutputProxy: {
id: 'es-proxy',
name: 'es-proxy',
url: 'http://es-proxy:1111',
proxy_headers: {
'X-Forwarded-For': 'forwarded-value',
'test-header': 'test-value',
},
is_preconfigured: false,
},
serviceToken: 'service-token-1',
policyId: 'policy-1',
fleetServerHost,
downloadSource: {
id: 'download-src',
name: 'download-src',
host: 'https://download-src/8.12.0-test/',
is_default: false,
proxy_id: 'download-proxy',
},
downloadSourceProxy: {
id: 'download-src-proxy',
name: 'download-src-proxy',
url: 'http://download-src-proxy:2222',
proxy_headers: {
'Accept-Language': 'en-US,en;q=0.5',
'second-header': 'second-value',
},
is_preconfigured: false,
},
});
expect(res).toMatchInlineSnapshot(`
"$ProgressPreference = 'SilentlyContinue'
Invoke-WebRequest -Uri https://download-src/8.12.0-test/beats/elastic-agent/elastic-agent--windows-x86_64.msi -OutFile elastic-agent--windows-x86_64.msi -Proxy \\"http://download-src-proxy:2222\\" -Headers @{\\"Accept-Language\\"=\\"en-US,en;q=0.5\\"; \\"second-header\\"=\\"second-value\\"}
.\\\\elastic-agent.msi --% INSTALLARGS=\\"\`
--fleet-server-es=http://elasticsearch:9200 \`
--fleet-server-service-token=service-token-1 \`
--fleet-server-policy=policy-1 \`
--fleet-server-port=8220 \`
--install-servers \`
--proxy-url=http://es-proxy:1111 \`
--proxy-header=\\"X-Forwarded-For=forwarded-value\\" \`
--proxy-header=\\"test-header=test-value\\"\\""
`);
});
it('should return the correct command if proxies are set for rpm', () => {
const args = {

View file

@ -70,6 +70,12 @@ function getArtifact(
`cd elastic-agent-${kibanaVersion}-windows-x86_64`,
].join(`\n`),
},
windows_msi: {
downloadCommand: [
`$ProgressPreference = 'SilentlyContinue'`,
`Invoke-WebRequest -Uri ${ARTIFACT_BASE_URL}/elastic-agent-${kibanaVersion}-windows-x86_64.msi -OutFile elastic-agent-${kibanaVersion}-windows-x86_64.msi${appendWindowsDownloadSourceProxyArgs}`,
].join(`\n`),
},
deb_aarch64: {
downloadCommand: [
`curl -L -O ${ARTIFACT_BASE_URL}/elastic-agent-${kibanaVersion}-arm64.deb${appendCurlDownloadSourceProxyArgs}`,
@ -127,7 +133,7 @@ export function getInstallCommandForPlatform({
downloadSource?: DownloadSource;
downloadSourceProxy?: FleetProxy;
}): string {
const newLineSeparator = platform === 'windows' ? '`\n' : '\\\n';
const newLineSeparator = platform === 'windows' || platform === 'windows_msi' ? '`\n' : '\\\n';
const artifact = getArtifact(platform, kibanaVersion ?? '', downloadSource, downloadSourceProxy);
@ -195,6 +201,7 @@ export function getInstallCommandForPlatform({
mac_aarch64: `${artifact.downloadCommand}\nsudo ./elastic-agent install ${commandArgumentsStr}`,
mac_x86_64: `${artifact.downloadCommand}\nsudo ./elastic-agent install ${commandArgumentsStr}`,
windows: `${artifact.downloadCommand}\n.\\elastic-agent.exe install ${commandArgumentsStr}`,
windows_msi: `${artifact.downloadCommand}\n.\\elastic-agent.msi --% INSTALLARGS="${commandArgumentsStr}"`,
deb_aarch64: `${artifact.downloadCommand}\nsudo systemctl enable elastic-agent\nsudo systemctl start elastic-agent\nsudo elastic-agent enroll ${commandArgumentsStr}`,
deb_x86_64: `${artifact.downloadCommand}\nsudo systemctl enable elastic-agent\nsudo systemctl start elastic-agent\nsudo elastic-agent enroll ${commandArgumentsStr}`,
rpm_aarch64: `${artifact.downloadCommand}\nsudo systemctl enable elastic-agent\nsudo systemctl start elastic-agent\nsudo elastic-agent enroll ${commandArgumentsStr}`,

View file

@ -126,6 +126,10 @@ Expand-Archive .\\elastic-agent-${agentVersion}-windows-x86_64.zip -DestinationP
cd elastic-agent-${agentVersion}-windows-x86_64
.\\elastic-agent.exe install ${enrollArgs}`;
const windowsMSICommand = `$ProgressPreference = 'SilentlyContinue'
Invoke-WebRequest -Uri ${downloadBaseUrl}/beats/elastic-agent/elastic-agent-${agentVersion}-windows-x86_64.msi -OutFile elastic-agent-${agentVersion}-windows-x86_64.msi ${windowsDownloadSourceProxyArgs}
.\\elastic-agent.msi --% INSTALLARGS="${enrollArgs}"`;
const linuxDebAarch64Command = `curl -L -O ${downloadBaseUrl}/beats/elastic-agent/elastic-agent-${agentVersion}-arm64.deb ${curlDownloadSourceProxyArgs}
sudo dpkg -i elastic-agent-${agentVersion}-arm64.deb
sudo systemctl enable elastic-agent \nsudo systemctl start elastic-agent \nsudo elastic-agent enroll ${enrollArgs} \n`;
@ -152,6 +156,7 @@ sudo systemctl enable elastic-agent \nsudo systemctl start elastic-agent \nsudo
mac_aarch64: macAarch64Command,
mac_x86_64: macX8664Command,
windows: windowsCommand,
windows_msi: windowsMSICommand,
deb_aarch64: linuxDebAarch64Command,
deb_x86_64: linuxDebX8664Command,
rpm_aarch64: linuxRpmAarch64Command,

View file

@ -60,6 +60,10 @@ Expand-Archive .\elastic-agent-${agentVersion}-windows-x86_64.zip -DestinationPa
cd elastic-agent-${agentVersion}-windows-x86_64
.\\elastic-agent.exe install`;
const windowsMSICommand = `$ProgressPreference = 'SilentlyContinue'
Invoke-WebRequest -Uri ${downloadBaseUrl}/beats/elastic-agent/elastic-agent-${agentVersion}-windows-x86_64.msi -OutFile elastic-agent-${agentVersion}-windows-x86_64.msi ${windowsDownloadSourceProxyArgs}
.\\elastic-agent.msi install`;
const k8sCommand = 'kubectl apply -f elastic-agent-standalone-kubernetes.yml';
return {
@ -68,6 +72,7 @@ cd elastic-agent-${agentVersion}-windows-x86_64
mac_aarch64: macAarch64Command,
mac_x86_64: macX8664Command,
windows: windowsCommand,
windows_msi: windowsMSICommand,
deb_aarch64: linuxDebAarch64Command,
deb_x86_64: linuxDebX8664Command,
rpm_aarch64: linuxRpmAarch64Command,

View file

@ -28,7 +28,7 @@ import {
} from '../../common/constants/epm';
import {
usePlatform,
VISIBLE_PALFORM_OPTIONS,
VISIBLE_PLATFORM_OPTIONS,
EXTENDED_PLATFORM_OPTIONS,
KUBERNETES_PLATFORM_OPTION,
} from '../hooks';
@ -149,7 +149,7 @@ export const PlatformSelector: React.FunctionComponent<Props> = ({
defaultMessage: 'Platform options',
})}
>
{VISIBLE_PALFORM_OPTIONS.map((option) => (
{VISIBLE_PLATFORM_OPTIONS.map((option) => (
<EuiFilterButton
key={option.id}
hasActiveFilters={platform === option.id}
@ -197,7 +197,7 @@ export const PlatformSelector: React.FunctionComponent<Props> = ({
'data-test-subj': option['data-test-subj'],
}))}
onChange={(_allOptions, _event, option) => setPlatform(option.key)}
style={{ width: 150 }}
css={{ width: 150 }}
listProps={{ paddingSize: 'none', onFocusBadge: false }}
>
{(list) => list}

View file

@ -18,7 +18,8 @@ export type PLATFORM_TYPE =
| 'rpm_x86_64'
| 'deb_aarch64'
| 'deb_x86_64'
| 'kubernetes';
| 'kubernetes'
| 'windows_msi';
interface PLATFORM_OPTION {
label: string;
@ -26,7 +27,7 @@ interface PLATFORM_OPTION {
'data-test-subj'?: string;
}
export const VISIBLE_PALFORM_OPTIONS: PLATFORM_OPTION[] = [
export const VISIBLE_PLATFORM_OPTIONS: PLATFORM_OPTION[] = [
{
id: 'linux_aarch64',
label: i18n.translate('xpack.fleet.enrollmentInstructions.platformButtons.linux', {
@ -64,6 +65,12 @@ export const EXTENDED_PLATFORM_OPTIONS: PLATFORM_OPTION[] = [
defaultMessage: 'Windows x86_64',
}),
},
{
id: 'windows_msi',
label: i18n.translate('xpack.fleet.enrollmentInstructions.platformButtons.msi', {
defaultMessage: 'Windows MSI',
}),
},
{
id: 'linux_x86_64',
label: i18n.translate('xpack.fleet.enrollmentInstructions.platformButtons.linux', {