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

[Fleet Automation] Add a flag to force install package #33600

Merged
merged 12 commits into from
Feb 5, 2025
20 changes: 18 additions & 2 deletions .gitlab/deploy_packages/e2e.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# Jobs that deploy agent packages on QA environment, to be used by e2e tests
# Jobs that deploy agent packages on QA environment, to be used by e2e tests.
# We use two separate jobs for Windows and Linux so that a failure in deploying the
# Linux / Windows script doesn't impact the other OS (i.e. Windows scripts failing to be signed blocking Linux E2E tests).

qa_installer_script:
qa_installer_script_linux:
image: registry.ddbuild.io/ci/datadog-agent-buildimages/gitlab_agent_deploy$DATADOG_AGENT_BUILDIMAGES_SUFFIX:$DATADOG_AGENT_BUILDIMAGES
stage: deploy_packages
tags: ["arch:amd64"]
Expand All @@ -14,3 +16,17 @@ qa_installer_script:
script:
- $S3_CP_CMD --recursive --exclude "*" --include "install*.sh" "$OMNIBUS_PACKAGE_DIR" "s3://${INSTALLER_TESTING_S3_BUCKET}/${CI_COMMIT_SHA}/scripts/"
- $S3_CP_CMD --recursive --exclude "*" --include "install*.sh" "$OMNIBUS_PACKAGE_DIR" "s3://${INSTALLER_TESTING_S3_BUCKET}/pipeline-${CI_PIPELINE_ID}/scripts/"

qa_installer_script_windows:
image: registry.ddbuild.io/ci/datadog-agent-buildimages/gitlab_agent_deploy$DATADOG_AGENT_BUILDIMAGES_SUFFIX:$DATADOG_AGENT_BUILDIMAGES
stage: deploy_packages
tags: ["arch:amd64"]
rules:
- !reference [.on_installer_or_e2e_changes]
- !reference [.manual]
needs:
- powershell_script_signing
before_script:
- ls $WINDOWS_POWERSHELL_DIR
script:
- $S3_CP_CMD $WINDOWS_POWERSHELL_DIR/Install-Datadog.ps1 s3://${INSTALLER_TESTING_S3_BUCKET}/pipeline-${CI_PIPELINE_ID}/scripts/Install-Datadog.ps1
18 changes: 1 addition & 17 deletions .gitlab/deploy_packages/windows.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,23 +51,6 @@ deploy_staging_windows_tags-7:
full=id=3a6e02b08553fd157ae3fb918945dd1eaae5a1aa818940381ef07a430cf25732

# Datadog Installer
powershell_script_signing:
extends: .windows_docker_default
stage: deploy_packages
needs: []
variables:
ARCH: "x64"
rules:
!reference [.on_deploy_installer]
artifacts:
expire_in: 2 weeks
paths:
- $WINDOWS_POWERSHELL_DIR
script:
- mkdir $WINDOWS_POWERSHELL_DIR
- docker run --rm -v "$(Get-Location):c:\mnt" -e AWS_NETWORKING=true -e IS_AWS_CONTAINER=true ${WINBUILDIMAGE} powershell -C "dd-wcs sign \mnt\tools\windows\DatadogAgentInstallScript\Install-Datadog.ps1"
- copy .\tools\windows\DatadogAgentInstallScript\Install-Datadog.ps1 $WINDOWS_POWERSHELL_DIR\Install-Datadog.ps1

deploy_installer_packages_windows-x64:
rules:
!reference [.on_deploy_installer]
Expand All @@ -77,6 +60,7 @@ deploy_installer_packages_windows-x64:
needs: ["windows-installer-amd64", "powershell_script_signing"]
before_script:
- ls $OMNIBUS_PACKAGE_DIR
- ls $WINDOWS_POWERSHELL_DIR
script:
- $S3_CP_CMD
--recursive
Expand Down
4 changes: 3 additions & 1 deletion .gitlab/e2e/e2e.yml
Original file line number Diff line number Diff line change
Expand Up @@ -460,7 +460,7 @@ new-e2e-installer-script:
- deploy_suse_rpm_testing_arm64-a7
- deploy_suse_rpm_testing_x64-a7
- deploy_installer_oci
- qa_installer_script
- qa_installer_script_linux
variables:
TARGETS: ./tests/installer/script
TEAM: fleet
Expand Down Expand Up @@ -497,6 +497,7 @@ new-e2e-installer-windows:
- deploy_windows_testing-a7
- deploy_installer_oci
- deploy_agent_oci
- qa_installer_script_windows
before_script:
# CURRENT_AGENT_VERSION is used to verify the installed agent version
# Must run before new_e2e_template changes the aws profile
Expand All @@ -517,6 +518,7 @@ new-e2e-installer-windows:
- EXTRA_PARAMS: --run "TestAgentInstalls$"
- EXTRA_PARAMS: --run "TestAgentUpgrades$"
# install-script
- EXTRA_PARAMS: --run "TestInstallScript$"
- EXTRA_PARAMS: --run "TestInstallScriptWithAgentUser$"
# installer-package
- EXTRA_PARAMS: --run "TestInstaller$"
Expand Down
1 change: 1 addition & 0 deletions .gitlab/e2e_install_packages/installer.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,4 @@ qa_installer_script_main:
- ls $OMNIBUS_PACKAGE_DIR
script:
- $S3_CP_CMD --recursive --exclude "*" --include "install*.sh" "$OMNIBUS_PACKAGE_DIR" "s3://${INSTALLER_TESTING_S3_BUCKET}/scripts/"

21 changes: 21 additions & 0 deletions .gitlab/package_build/installer.yml
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,27 @@ installer-install-scripts:
paths:
- $OMNIBUS_PACKAGE_DIR

#
# Windows install script
#
powershell_script_signing:
extends: .windows_docker_default
stage: package_build
needs: []
variables:
ARCH: "x64"
rules:
- !reference [.except_mergequeue]
- when: on_success
artifacts:
expire_in: 2 weeks
paths:
- $WINDOWS_POWERSHELL_DIR
script:
- mkdir $WINDOWS_POWERSHELL_DIR
- docker run --rm -v "$(Get-Location):c:\mnt" -e AWS_NETWORKING=true -e IS_AWS_CONTAINER=true ${WINBUILDIMAGE} powershell -C "dd-wcs sign \mnt\tools\windows\DatadogAgentInstallScript\Install-Datadog.ps1"
- copy .\tools\windows\DatadogAgentInstallScript\Install-Datadog.ps1 $WINDOWS_POWERSHELL_DIR\Install-Datadog.ps1

#
# The installer program
#
Expand Down
5 changes: 5 additions & 0 deletions cmd/installer/subcommands/installer/command.go
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,7 @@ func setupCommand() *cobra.Command {

func installCommand() *cobra.Command {
var installArgs []string
var forceInstall bool
cmd := &cobra.Command{
Use: "install <url>",
Short: "Install a package",
Expand All @@ -296,10 +297,14 @@ func installCommand() *cobra.Command {
}
defer func() { i.stop(err) }()
i.span.SetTag("params.url", args[0])
if forceInstall {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if this is an issue, forceInstall seems used here whereas it's not initialized on line 287, and the definition of the flag is set below. It's maybe normal but I prefer to ask my noob question just in case.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It will be false by default. And will take the value given by the --force flag. Because of line 307.
That's a bit misleading but since this line will be executed only once the command is actually ran. The value should properly be updated by the line that appears later in the code

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, thanks @KevinFairise2 - that's actually how the arguments work in a cobra command. The RunE command uses the local variables whose address is captured in the cmd.Flags() to be updated below.

return i.ForceInstall(i.ctx, args[0], installArgs)
}
return i.Install(i.ctx, args[0], installArgs)
},
}
cmd.Flags().StringArrayVarP(&installArgs, "install_args", "A", nil, "Arguments to pass to the package")
cmd.Flags().BoolVar(&forceInstall, "force", false, "Install packages, even if they are already up-to-date.")
return cmd
}

Expand Down
8 changes: 5 additions & 3 deletions pkg/fleet/daemon/daemon_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,6 @@
// This product includes software developed at Datadog (https://www.datadoghq.com/).
// Copyright 2016-present Datadog, Inc.

// for now the installer is not supported on windows
//go:build !windows

package daemon

import (
Expand Down Expand Up @@ -67,6 +64,11 @@ func (m *testPackageManager) Install(ctx context.Context, url string, installArg
return args.Error(0)
}

func (m *testPackageManager) ForceInstall(ctx context.Context, url string, installArgs []string) error {
args := m.Called(ctx, url, installArgs)
return args.Error(0)
}

func (m *testPackageManager) Remove(ctx context.Context, pkg string) error {
args := m.Called(ctx, pkg)
return args.Error(0)
Expand Down
24 changes: 22 additions & 2 deletions pkg/fleet/installer/installer.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ type Installer interface {
ConfigStates() (map[string]repository.State, error)

Install(ctx context.Context, url string, args []string) error
ForceInstall(ctx context.Context, url string, args []string) error
Remove(ctx context.Context, pkg string) error
Purge(ctx context.Context)

Expand Down Expand Up @@ -151,8 +152,28 @@ func (i *installerImpl) IsInstalled(_ context.Context, pkg string) (bool, error)
return hasPackage, nil
}

// ForceInstall installs or updates a package, even if it's already installed
func (i *installerImpl) ForceInstall(ctx context.Context, url string, args []string) error {
return i.doInstall(ctx, url, args, func(dbPkg db.Package, pkg *oci.DownloadedPackage) bool {
if dbPkg.Name == pkg.Name && dbPkg.Version == pkg.Version {
log.Warnf("package %s version %s is already installed, updating it anyway", pkg.Name, pkg.Version)
}
return true
})
}

// Install installs or updates a package.
func (i *installerImpl) Install(ctx context.Context, url string, args []string) error {
return i.doInstall(ctx, url, args, func(dbPkg db.Package, pkg *oci.DownloadedPackage) bool {
if dbPkg.Name == pkg.Name && dbPkg.Version == pkg.Version {
log.Warnf("package %s version %s is already installed", pkg.Name, pkg.Version)
return false
}
return true
})
}

func (i *installerImpl) doInstall(ctx context.Context, url string, args []string, shouldInstallPredicate func(dbPkg db.Package, pkg *oci.DownloadedPackage) bool) error {
i.m.Lock()
defer i.m.Unlock()
pkg, err := i.downloader.Download(ctx, url) // Downloads pkg metadata only
Expand All @@ -168,8 +189,7 @@ func (i *installerImpl) Install(ctx context.Context, url string, args []string)
if err != nil && !errors.Is(err, db.ErrPackageNotFound) {
return fmt.Errorf("could not get package: %w", err)
}
if dbPkg.Name == pkg.Name && dbPkg.Version == pkg.Version {
log.Infof("package %s version %s is already installed", pkg.Name, pkg.Version)
if !shouldInstallPredicate(dbPkg, pkg) {
return nil
}
err = i.preparePackage(ctx, pkg.Name, args) // Preinst
Expand Down
Loading
Loading