@@ -9,15 +9,19 @@ import (
99 "errors"
1010 "fmt"
1111 "os"
12+ "path/filepath"
1213 "time"
1314
1415 "github.com/elastic/elastic-agent/internal/pkg/agent/application/filelock"
1516 "github.com/elastic/elastic-agent/internal/pkg/agent/application/paths"
1617 "github.com/elastic/elastic-agent/internal/pkg/agent/application/reexec"
18+ "github.com/elastic/elastic-agent/internal/pkg/agent/application/upgrade/details"
1719 "github.com/elastic/elastic-agent/internal/pkg/fleetapi"
20+ "github.com/elastic/elastic-agent/internal/pkg/release"
1821 v1 "github.com/elastic/elastic-agent/pkg/api/v1"
1922 "github.com/elastic/elastic-agent/pkg/core/logger"
2023 "github.com/elastic/elastic-agent/pkg/version"
24+ agtversion "github.com/elastic/elastic-agent/version"
2125)
2226
2327func (u * Upgrader ) rollbackToPreviousVersion (ctx context.Context , topDir string , now time.Time , version string , action * fleetapi.ActionUpgrade ) (reexec.ShutdownCallbackFn , error ) {
@@ -37,7 +41,7 @@ func (u *Upgrader) rollbackToPreviousVersion(ctx context.Context, topDir string,
3741
3842 if errors .Is (err , os .ErrNotExist ) {
3943 // there is no upgrade marker, we need to extract available rollbacks from agent installs
40- watcherExecutable , versionedHomeToRollbackTo , err = rollbackUsingAgentInstalls ()
44+ watcherExecutable , versionedHomeToRollbackTo , err = rollbackUsingAgentInstalls (ctx , u . log , u . watcherHelper , u . installDescriptorSource , topDir , now , version , u . markUpgrade )
4145 } else {
4246 watcherExecutable , versionedHomeToRollbackTo , err = rollbackUsingUpgradeMarker (ctx , u .log , u .watcherHelper , topDir , now , version )
4347 }
@@ -56,10 +60,69 @@ func (u *Upgrader) rollbackToPreviousVersion(ctx context.Context, topDir string,
5660 return nil , nil
5761}
5862
59- func rollbackUsingAgentInstalls () (string , string , error ) {
63+ func rollbackUsingAgentInstalls (ctx context. Context , log * logger. Logger , watcherHelper WatcherHelper , source installDescriptorSource , topDir string , now time. Time , rollbackVersion string , markUpgrade markUpgradeFunc ) (string , string , error ) {
6064 //FIXME implement
6165 //panic("Not implemented")
62- return "" , "" , errors .Join (errors .New ("not implemented" ), os .ErrNotExist )
66+ //return "", "", errors.Join(errors.New("not implemented"), os.ErrNotExist)
67+
68+ // read the available installs
69+ installDescriptor , err := source .GetInstallDesc ()
70+ if err != nil {
71+ return "" , "" , fmt .Errorf ("retrieving agent installs: %w" , err )
72+ }
73+ // check for the version we want to rollback to
74+ found := false
75+ var targetInstall v1.AgentInstallDesc
76+ for _ , i := range installDescriptor .AgentInstalls {
77+ if i .TTL == nil {
78+ // valid rollbacks should have a TTL associated
79+ continue
80+ }
81+ if i .Version == rollbackVersion && now .Before (* i .TTL ) {
82+ // found a valid target
83+ found = true
84+ targetInstall = i
85+ break
86+ }
87+ }
88+
89+ if ! found {
90+ return "" , "" , fmt .Errorf ("version %q not listed among the available rollbacks: %w" , rollbackVersion , ErrNoRollbacksAvailable )
91+ }
92+
93+ prevAgentParsedVersion , err := version .ParseVersion (targetInstall .Version )
94+ if err != nil {
95+ return "" , "" , fmt .Errorf ("parsing version of target install %+v: %w" , targetInstall , err )
96+ }
97+
98+ // write out a fake upgrade marker to make the upgrade details state happy
99+ relCurVersionedHome , err := filepath .Rel (paths .Top (), paths .Home ())
100+ if err != nil {
101+ return "" , "" , fmt .Errorf ("getting current install home path %q relative to top %q: %w" , paths .Home (), paths .Top (), err )
102+ }
103+ curAgentInstall := agentInstall {
104+ parsedVersion : agtversion .GetParsedAgentPackageVersion (),
105+ version : release .VersionWithSnapshot (),
106+ hash : release .Commit (),
107+ versionedHome : relCurVersionedHome ,
108+ }
109+
110+ prevAgentInstall := agentInstall {
111+ parsedVersion : prevAgentParsedVersion ,
112+ version : targetInstall .Version ,
113+ hash : targetInstall .Hash ,
114+ versionedHome : targetInstall .VersionedHome ,
115+ }
116+
117+ upgradeDetails := details .NewDetails (release .VersionWithSnapshot (), details .StateRequested , "" /*action.ID*/ )
118+ err = markUpgrade (log , paths .DataFrom (topDir ), now , curAgentInstall , prevAgentInstall , nil /*action*/ , upgradeDetails , nil )
119+ if err != nil {
120+ return "" , "" , fmt .Errorf ("creating upgrade marker: %w" , err )
121+ }
122+
123+ // return watcher executable and versionedHome to rollback to
124+ watcherExecutable := watcherHelper .SelectWatcherExecutable (topDir , prevAgentInstall , curAgentInstall )
125+ return watcherExecutable , targetInstall .VersionedHome , nil
63126}
64127
65128func rollbackUsingUpgradeMarker (ctx context.Context , log * logger.Logger , watcherHelper WatcherHelper , topDir string , now time.Time , version string ) (string , string , error ) {
0 commit comments