Skip to content

Commit bc0f82f

Browse files
mergify[bot]Kaan Yalti
andauthored
[8.18] (backport #9349) Enhancement/5235 correctly wrap errors from copyActionDir and copyRunDirectory (#9933)
* Enhancement/5235 correctly wrap errors from copyActionDir and copyRunDirectory (#9349) * enhancement(5235): added copyActionStore package var * enhancement(5235): added copyRunDirectory package var * enhancement(5235): wrapping errors in copyRunDirectory enhancement(5235): wrapping mkdriall error in copyrundir function * enhancement(5235): added package var to abstract third party package function copy.Copy * enhancement(5235): using copyActionStoreFunc and copyRunDirectoryFunc * enhancement(5235): wrapping errors in upgrade function * enhancement(5235): added mkdirall wrapper in copyRunDir enhancement(5235): added common package import * enhancement(5235): using writefile wrapper in copyActionStore * enhancement(5235): using readFile wrapper in copyActionStore * enhancement(5235): added copyActionStore and copyRunDirectory tests in upgrade_test enhancement(5235): updated the copyRunDirectory test to mock stdlib functions * enhancement(5235): added TestUpgradeDirectoryCopyErrors test in upgrade_test enhancement(5235): added test imports in upgrade_test * enhancement(5235): added comment in step_unpack * enhancement(5235): added types in upgrade.go to abstract away functions for testability. abstracted copyActionStore and copyRunDirectory. Updated tests * enhancement(5235): updated upgrade tests, added tests cases for copyActionStore and copyRunDir error handling, removed unnecessary test, refactored copyActionStore and copyRunDirectory tests * enhancement(5235): moved where mkdriAllFunc type is declared * enhancement(5235): remove unnecessary change * enhancement(5235): added action store path to error message * enhancement(5235): remove unused commented code * enhancement(5235): fix typo in test log name (cherry picked from commit 96e0476) # Conflicts: # internal/pkg/agent/application/upgrade/upgrade.go * resolved merge conflicts --------- Co-authored-by: Kaan Yalti <kaan.yalti@elastic.co>
1 parent 16a7957 commit bc0f82f

File tree

3 files changed

+291
-50
lines changed

3 files changed

+291
-50
lines changed

internal/pkg/agent/application/upgrade/step_unpack.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@ type UnpackResult struct {
3434
}
3535

3636
type copyFunc func(dst io.Writer, src io.Reader) (written int64, err error)
37-
type mkdirAllFunc func(name string, perm fs.FileMode) error
3837
type openFileFunc func(name string, flag int, perm fs.FileMode) (*os.File, error)
3938
type unarchiveFunc func(log *logger.Logger, archivePath, dataDir string, copy copyFunc, mkdirAll mkdirAllFunc, openFile openFileFunc) (UnpackResult, error)
4039

internal/pkg/agent/application/upgrade/upgrade.go

Lines changed: 59 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,16 @@ type unpackHandler interface {
6767
getPackageMetadata(archivePath string) (packageMetadata, error)
6868
}
6969

70+
// Types used to abstract copyActionStore, copyRunDirectory and github.com/otiai10/copy.Copy
71+
type copyActionStoreFunc func(log *logger.Logger, newHome string) error
72+
type copyRunDirectoryFunc func(log *logger.Logger, oldRunPath, newRunPath string) error
73+
type fileDirCopyFunc func(from, to string, opts ...copy.Options) error
74+
75+
// Types used to abstract stdlib functions
76+
type mkdirAllFunc func(name string, perm fs.FileMode) error
77+
type readFileFunc func(name string) ([]byte, error)
78+
type writeFileFunc func(name string, data []byte, perm fs.FileMode) error
79+
7080
// Upgrader performs an upgrade
7181
type Upgrader struct {
7282
log *logger.Logger
@@ -80,7 +90,8 @@ type Upgrader struct {
8090
artifactDownloader artifactDownloadHandler
8191
unpacker unpackHandler
8292
isDiskSpaceErrorFunc func(err error) bool
83-
extractAgentVersion func(metadata packageMetadata, upgradeVersion string) agentVersion
93+
copyActionStore copyActionStoreFunc
94+
copyRunDirectory copyRunDirectoryFunc
8495
}
8596

8697
// IsUpgradeable when agent is installed and running as a service or flag was provided.
@@ -101,6 +112,8 @@ func NewUpgrader(log *logger.Logger, settings *artifact.Config, agentInfo info.A
101112
artifactDownloader: newArtifactDownloader(settings, log),
102113
unpacker: newUnpacker(log),
103114
isDiskSpaceErrorFunc: upgradeErrors.IsDiskSpaceError,
115+
copyActionStore: copyActionStoreProvider(os.ReadFile, os.WriteFile),
116+
copyRunDirectory: copyRunDirectoryProvider(os.MkdirAll, copy.Copy),
104117
}, nil
105118
}
106119

@@ -278,15 +291,15 @@ func (u *Upgrader) Upgrade(ctx context.Context, version string, sourceURI string
278291

279292
newHome := filepath.Join(paths.Top(), unpackRes.VersionedHome)
280293

281-
if err := copyActionStore(u.log, newHome); err != nil {
282-
return nil, errors.New(err, "failed to copy action store")
294+
if err := u.copyActionStore(u.log, newHome); err != nil {
295+
return nil, fmt.Errorf("failed to copy action store: %w", err)
283296
}
284297

285298
newRunPath := filepath.Join(newHome, "run")
286299
oldRunPath := filepath.Join(paths.Home(), "run")
287300

288-
if err := copyRunDirectory(u.log, oldRunPath, newRunPath); err != nil {
289-
return nil, errors.New(err, "failed to copy run directory")
301+
if err := u.copyRunDirectory(u.log, oldRunPath, newRunPath); err != nil {
302+
return nil, fmt.Errorf("failed to copy run directory: %w", err)
290303
}
291304

292305
det.SetState(details.StateReplacing)
@@ -503,50 +516,55 @@ func rollbackInstall(ctx context.Context, log *logger.Logger, topDirPath, versio
503516
return nil
504517
}
505518

506-
func copyActionStore(log *logger.Logger, newHome string) error {
507-
// copies legacy action_store.yml, state.yml and state.enc encrypted file if exists
508-
storePaths := []string{paths.AgentActionStoreFile(), paths.AgentStateStoreYmlFile(), paths.AgentStateStoreFile()}
509-
log.Infow("Copying action store", "new_home_path", newHome)
519+
func copyActionStoreProvider(readFile readFileFunc, writeFile writeFileFunc) copyActionStoreFunc {
520+
return func(log *logger.Logger, newHome string) error {
521+
// copies legacy action_store.yml, state.yml and state.enc encrypted file if exists
522+
storePaths := []string{paths.AgentActionStoreFile(), paths.AgentStateStoreYmlFile(), paths.AgentStateStoreFile()}
523+
log.Infow("Copying action store", "new_home_path", newHome)
524+
525+
for _, currentActionStorePath := range storePaths {
526+
newActionStorePath := filepath.Join(newHome, filepath.Base(currentActionStorePath))
527+
log.Infow("Copying action store path", "from", currentActionStorePath, "to", newActionStorePath)
528+
// using readfile instead of os.ReadFile for testability
529+
currentActionStore, err := readFile(currentActionStorePath)
530+
if os.IsNotExist(err) {
531+
// nothing to copy
532+
continue
533+
}
534+
if err != nil {
535+
return err
536+
}
510537

511-
for _, currentActionStorePath := range storePaths {
512-
newActionStorePath := filepath.Join(newHome, filepath.Base(currentActionStorePath))
513-
log.Infow("Copying action store path", "from", currentActionStorePath, "to", newActionStorePath)
514-
currentActionStore, err := os.ReadFile(currentActionStorePath)
515-
if os.IsNotExist(err) {
516-
// nothing to copy
517-
continue
518-
}
519-
if err != nil {
520-
return err
538+
// using writeFile instead of os.WriteFile for testability
539+
if err := writeFile(newActionStorePath, currentActionStore, 0o600); err != nil {
540+
return fmt.Errorf("failed to write action store at %q: %w", newActionStorePath, err)
541+
}
521542
}
522543

523-
if err := os.WriteFile(newActionStorePath, currentActionStore, 0o600); err != nil {
524-
return err
525-
}
544+
return nil
526545
}
527-
528-
return nil
529546
}
530547

531-
func copyRunDirectory(log *logger.Logger, oldRunPath, newRunPath string) error {
548+
func copyRunDirectoryProvider(mkdirAll mkdirAllFunc, fileDirCopy fileDirCopyFunc) copyRunDirectoryFunc {
549+
return func(log *logger.Logger, oldRunPath, newRunPath string) error {
550+
log.Infow("Copying run directory", "new_run_path", newRunPath, "old_run_path", oldRunPath)
532551

533-
log.Infow("Copying run directory", "new_run_path", newRunPath, "old_run_path", oldRunPath)
552+
if err := mkdirAll(newRunPath, runDirMod); err != nil {
553+
return fmt.Errorf("failed to create run directory: %w", err)
554+
}
534555

535-
if err := os.MkdirAll(newRunPath, runDirMod); err != nil {
536-
return errors.New(err, "failed to create run directory")
537-
}
556+
err := copyDir(log, oldRunPath, newRunPath, true, fileDirCopy)
557+
if os.IsNotExist(err) {
558+
// nothing to copy, operation ok
559+
log.Infow("Run directory not present", "old_run_path", oldRunPath)
560+
return nil
561+
}
562+
if err != nil {
563+
return fmt.Errorf("failed to copy %q to %q: %w", oldRunPath, newRunPath, err)
564+
}
538565

539-
err := copyDir(log, oldRunPath, newRunPath, true)
540-
if os.IsNotExist(err) {
541-
// nothing to copy, operation ok
542-
log.Infow("Run directory not present", "old_run_path", oldRunPath)
543566
return nil
544567
}
545-
if err != nil {
546-
return errors.New(err, "failed to copy %q to %q", oldRunPath, newRunPath)
547-
}
548-
549-
return nil
550568
}
551569

552570
// shutdownCallback returns a callback function to be executing during shutdown once all processes are closed.
@@ -574,7 +592,7 @@ func shutdownCallback(l *logger.Logger, homePath, prevVersion, newVersion, newHo
574592
newRelPath = strings.ReplaceAll(newRelPath, oldHome, newHome)
575593
newDir := filepath.Join(newHome, newRelPath)
576594
l.Debugf("copying %q -> %q", processDir, newDir)
577-
if err := copyDir(l, processDir, newDir, true); err != nil {
595+
if err := copyDir(l, processDir, newDir, true, copy.Copy); err != nil {
578596
return err
579597
}
580598
}
@@ -620,7 +638,7 @@ func readDirs(dir string) ([]string, error) {
620638
return dirs, nil
621639
}
622640

623-
func copyDir(l *logger.Logger, from, to string, ignoreErrs bool) error {
641+
func copyDir(l *logger.Logger, from, to string, ignoreErrs bool, fileDirCopy fileDirCopyFunc) error {
624642
var onErr func(src, dst string, err error) error
625643

626644
if ignoreErrs {
@@ -646,7 +664,7 @@ func copyDir(l *logger.Logger, from, to string, ignoreErrs bool) error {
646664
copyConcurrency = runtime.NumCPU() * 4
647665
}
648666

649-
return copy.Copy(from, to, copy.Options{
667+
return fileDirCopy(from, to, copy.Options{
650668
OnSymlink: func(_ string) copy.SymlinkAction {
651669
return copy.Shallow
652670
},

0 commit comments

Comments
 (0)