Skip to content

Commit e0b3a4a

Browse files
[8.19] (backport #7999) [deb/rpm] copy run folder from old agent installation (#8060)
* [deb/rpm] copy run folder from old agent installation (#7999) * fix: copy run folder from old agent installation * fix: add debian OS support in deb related integration tests * doc: add changelog fragment * fix: deduplicate similar code and improve code readability * fix: typo * fix: preserve mode,ownership,timestamps during cp (cherry picked from commit 815c264) # Conflicts: # dev-tools/packaging/templates/linux/preinstall.sh.tmpl # pkg/testing/fixture.go # testing/integration/linux_deb_test.go * fix: resolve conflicts --------- Co-authored-by: Panos Koutsovasilis <[email protected]>
1 parent ba73dfa commit e0b3a4a

File tree

7 files changed

+113
-7
lines changed

7 files changed

+113
-7
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
kind: bug-fix
2+
summary: Preserve agent run state on DEB and RPM upgrades
3+
component: "elastic-agent"
4+
pr: https://github.com/elastic/elastic-agent/pull/7999
5+
issue: https://github.com/elastic/elastic-agent/issues/3832

dev-tools/packaging/templates/linux/preinstall.sh.tmpl

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,16 @@ if test -L "$symlink"; then
4040
else
4141
echo "didn't find $enc_path"
4242
fi
43+
44+
old_run_path="$old_agent_dir/run"
45+
new_run_path="$new_agent_dir/run"
46+
if [ -d "$old_run_path" ]; then
47+
echo "found $old_run_path, copy to $new_agent_dir"
48+
mkdir -p "$new_run_path"
49+
cp -rfp "$old_run_path/." "$new_run_path/"
50+
else
51+
echo "didn't find $old_run_path"
52+
fi
4353
fi
4454
else
4555
echo "no previous installation found"

pkg/testing/fixture.go

Lines changed: 51 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,11 @@ func (f *Fixture) Client() client.Client {
185185
return f.c
186186
}
187187

188+
// Version returns the Elastic Agent version.
189+
func (f *Fixture) Version() string {
190+
return f.version
191+
}
192+
188193
// Prepare prepares the Elastic Agent for usage.
189194
//
190195
// This must be called before `Configure`, `Run`, or `Install` can be called.
@@ -1012,7 +1017,7 @@ func (f *Fixture) prepareComponents(workDir string, components ...UsableComponen
10121017

10131018
// now remove all that should not be kept; removal is only
10141019
// done by removing the spec file, no need to delete the binary
1015-
componentsDir, err := FindComponentsDir(workDir)
1020+
componentsDir, err := FindComponentsDir(workDir, "")
10161021
if err != nil {
10171022
return err
10181023
}
@@ -1249,28 +1254,68 @@ func getCacheDir(caller string, name string) (string, error) {
12491254
return cacheDir, nil
12501255
}
12511256

1252-
// FindComponentsDir identifies the directory that holds the components.
1253-
func FindComponentsDir(dir string) (string, error) {
1257+
// findAgentDataVersionDir identifies the directory that holds the agent data of the given version.
1258+
func findAgentDataVersionDir(dir, version string) (string, error) {
12541259
dataDir := filepath.Join(dir, "data")
12551260
agentVersions, err := os.ReadDir(dataDir)
12561261
if err != nil {
12571262
return "", fmt.Errorf("failed to read contents of the data directory %s: %w", dataDir, err)
12581263
}
12591264
var versionDir string
12601265
for _, fi := range agentVersions {
1261-
if strings.HasPrefix(fi.Name(), "elastic-agent-") && fi.IsDir() {
1262-
versionDir = fi.Name()
1266+
filename := fi.Name()
1267+
if strings.HasPrefix(filename, "elastic-agent-") && fi.IsDir() {
1268+
// Below we exclude the hash suffix (7 characters) of the directory to check the version
1269+
if version != "" && filename[:len(filename)-7] != "elastic-agent-"+version {
1270+
// version specified but version mismatch. in case of upgrade we have multiple
1271+
// directories, we don't want first found
1272+
continue
1273+
}
1274+
versionDir = filename
12631275
break
12641276
}
12651277
}
1266-
componentsDir := filepath.Join(dataDir, versionDir, "components")
1278+
if versionDir == "" {
1279+
return "", fmt.Errorf("failed to find versioned directory for version %q", version)
1280+
}
1281+
return filepath.Join(dataDir, versionDir), nil
1282+
}
1283+
1284+
// FindComponentsDir identifies the directory that holds the components.
1285+
func FindComponentsDir(dir, version string) (string, error) {
1286+
versionDir, err := findAgentDataVersionDir(dir, version)
1287+
if err != nil {
1288+
return "", err
1289+
}
1290+
componentsDir := filepath.Join(versionDir, "components")
12671291
fi, err := os.Stat(componentsDir)
12681292
if (err != nil && !os.IsExist(err)) || !fi.IsDir() {
12691293
return "", fmt.Errorf("failed to find components directory at %s: %w", componentsDir, err)
12701294
}
12711295
return componentsDir, nil
12721296
}
12731297

1298+
// FindRunDir identifies the directory that holds the run folder.
1299+
func FindRunDir(fixture *Fixture) (string, error) {
1300+
agentWorkDir := fixture.WorkDir()
1301+
if pf := fixture.PackageFormat(); pf == "deb" || pf == "rpm" {
1302+
// these are hardcoded paths in packages.yml
1303+
agentWorkDir = "/var/lib/elastic-agent"
1304+
}
1305+
1306+
version := fixture.Version()
1307+
versionDir, err := findAgentDataVersionDir(agentWorkDir, version)
1308+
if err != nil {
1309+
return "", err
1310+
}
1311+
runDir := filepath.Join(versionDir, "run")
1312+
fi, err := os.Stat(runDir)
1313+
if (err != nil && !os.IsExist(err)) || !fi.IsDir() {
1314+
return "", fmt.Errorf("failed to find run directory at %s: %w", runDir, err)
1315+
}
1316+
return runDir, nil
1317+
}
1318+
12741319
// writeSpecFile writes the specification to a specification file at the defined destination.
12751320
func writeSpecFile(dest string, spec *component.Spec) error {
12761321
data, err := yaml.Marshal(spec)

testing/integration/linux_deb_test.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@ package integration
99
import (
1010
"context"
1111
"fmt"
12+
"os"
1213
"os/exec"
14+
"path/filepath"
1315
"strings"
1416
"testing"
1517
"time"
@@ -38,6 +40,10 @@ func TestDebLogIngestFleetManaged(t *testing.T) {
3840
Type: define.Linux,
3941
Distro: "ubuntu",
4042
},
43+
{
44+
Type: define.Linux,
45+
Distro: "debian",
46+
},
4147
},
4248
Local: false,
4349
Sudo: true,
@@ -106,6 +112,10 @@ func TestDebFleetUpgrade(t *testing.T) {
106112
Type: define.Linux,
107113
Distro: "ubuntu",
108114
},
115+
{
116+
Type: define.Linux,
117+
Distro: "debian",
118+
},
109119
},
110120
Local: false,
111121
Sudo: true,
@@ -169,6 +179,15 @@ func TestDebFleetUpgrade(t *testing.T) {
169179

170180
check.ConnectedToFleet(ctx, t, startFixture, 5*time.Minute)
171181

182+
const migrationMarkerFile = "migration_marker.file"
183+
runDir, err := atesting.FindRunDir(startFixture)
184+
require.NoError(t, err, "failed at getting run dir")
185+
186+
runMigrationMarker := filepath.Join(runDir, migrationMarkerFile)
187+
f, err := os.Create(runMigrationMarker)
188+
require.NoErrorf(t, err, "failed to create %q file", runMigrationMarker)
189+
_ = f.Close()
190+
172191
// 3. Upgrade deb to the build version
173192
srcPackage, err := endFixture.SrcPackage(ctx)
174193
require.NoError(t, err)
@@ -177,6 +196,12 @@ func TestDebFleetUpgrade(t *testing.T) {
177196
out, err := cmd.CombinedOutput() // #nosec G204 -- Need to pass in name of package
178197
require.NoError(t, err, string(out))
179198

199+
newRunDir, err := atesting.FindRunDir(endFixture)
200+
require.NoError(t, err, "failed at getting run dir")
201+
require.NotEqual(t, runDir, newRunDir, "the run dirs from upgrade should not match")
202+
newRunMigrationMarker := filepath.Join(newRunDir, migrationMarkerFile)
203+
require.FileExistsf(t, newRunMigrationMarker, "%q is missing", newRunMigrationMarker)
204+
180205
// 4. Wait for version in Fleet to match
181206
// Fleet will not include the `-SNAPSHOT` in the `GetAgentVersion` result
182207
noSnapshotVersion := strings.TrimSuffix(define.Version(), "-SNAPSHOT")

testing/integration/linux_rpm_test.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@ package integration
99
import (
1010
"context"
1111
"fmt"
12+
"os"
1213
"os/exec"
14+
"path/filepath"
1315
"strings"
1416
"testing"
1517
"time"
@@ -170,12 +172,27 @@ func TestRpmFleetUpgrade(t *testing.T) {
170172

171173
check.ConnectedToFleet(ctx, t, startFixture, 5*time.Minute)
172174

175+
const migrationMarkerFile = "migration_marker.file"
176+
runDir, err := atesting.FindRunDir(startFixture)
177+
require.NoError(t, err, "failed at getting run dir")
178+
179+
runMigrationMarker := filepath.Join(runDir, migrationMarkerFile)
180+
f, err := os.Create(runMigrationMarker)
181+
require.NoErrorf(t, err, "failed to create %q file", runMigrationMarker)
182+
_ = f.Close()
183+
173184
// 3. Upgrade rpm to the build version
174185
srcPackage, err := endFixture.SrcPackage(ctx)
175186
require.NoError(t, err)
176187
out, err := exec.CommandContext(ctx, "sudo", "rpm", "-U", "-v", srcPackage).CombinedOutput() // #nosec G204 -- Need to pass in name of package
177188
require.NoError(t, err, string(out))
178189

190+
newRunDir, err := atesting.FindRunDir(endFixture)
191+
require.NoError(t, err, "failed at getting run dir")
192+
require.NotEqual(t, runDir, newRunDir, "the run dirs from upgrade should not match")
193+
newRunMigrationMarker := filepath.Join(newRunDir, migrationMarkerFile)
194+
require.FileExistsf(t, newRunMigrationMarker, "%q is missing", newRunMigrationMarker)
195+
179196
// 4. Wait for version in Fleet to match
180197
// Fleet will not include the `-SNAPSHOT` in the `GetAgentVersion` result
181198
noSnapshotVersion := strings.TrimSuffix(define.Version(), "-SNAPSHOT")

testing/integration/otel_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -562,7 +562,7 @@ func TestOtelAPMIngestion(t *testing.T) {
562562
err = fixture.EnsurePrepared(ctx)
563563
require.NoError(t, err)
564564

565-
componentsDir, err := aTesting.FindComponentsDir(agentWorkDir)
565+
componentsDir, err := aTesting.FindComponentsDir(agentWorkDir, "")
566566
require.NoError(t, err)
567567

568568
// start apm default config just configure ES output

testing/integration/restrict_upgrade_deb_test.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@ func TestRestrictUpgradeDeb(t *testing.T) {
2828
Type: define.Linux,
2929
Distro: "ubuntu",
3030
},
31+
{
32+
Type: define.Linux,
33+
Distro: "debian",
34+
},
3135
},
3236
})
3337
t.Run("when agent is deployed via deb, a user should not be able to upgrade the agent using the cli", func(t *testing.T) {

0 commit comments

Comments
 (0)