Skip to content
This repository has been archived by the owner on May 21, 2024. It is now read-only.

Fix issue with never-ending install retries #1192

Merged
merged 3 commits into from
Apr 26, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/libaktualizr/primary/aktualizr.h
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,7 @@ class Aktualizr {
FRIEND_TEST(Aktualizr, PauseResumeQueue);
FRIEND_TEST(Aktualizr, AddSecondary);
FRIEND_TEST(Aktualizr, EmptyTargets);
FRIEND_TEST(Aktualizr, EmptyTargetsAfterInstall);
FRIEND_TEST(Delegation, Basic);
FRIEND_TEST(Delegation, RevokeAfterCheckUpdates);
FRIEND_TEST(Delegation, RevokeAfterInstall);
Expand Down
61 changes: 61 additions & 0 deletions src/libaktualizr/primary/empty_targets_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
#include "test_utils.h"
#include "uptane_test_common.h"

#include "utilities/fault_injection.h"

boost::filesystem::path aktualizr_repo_path;

class HttpRejectEmptyCorrId : public HttpFake {
Expand Down Expand Up @@ -96,6 +98,65 @@ TEST(Aktualizr, EmptyTargets) {
}
}

#ifdef FIU_ENABLE

/* Check that Aktualizr switches back to empty targets after completing an
* installation attempt (OTA-2587) */
TEST(Aktualizr, EmptyTargetsAfterInstall) {
TemporaryDirectory temp_dir;
TemporaryDirectory meta_dir;
auto http = std::make_shared<HttpRejectEmptyCorrId>(temp_dir.Path(), meta_dir.Path() / "repo");
Config conf = UptaneTestCommon::makeTestConfig(temp_dir, http->tls_server);
logger_set_threshold(boost::log::trivial::trace);

Process akt_repo(aktualizr_repo_path.string());
akt_repo.run({"generate", "--path", meta_dir.PathString(), "--correlationid", "abc123"});
akt_repo.run({"image", "--path", meta_dir.PathString(), "--filename", "tests/test_data/firmware.txt", "--targetname",
"firmware.txt"});
akt_repo.run({"addtarget", "--path", meta_dir.PathString(), "--targetname", "firmware.txt", "--hwid", "primary_hw",
"--serial", "CA:FE:A6:D2:84:9D"});
akt_repo.run({"signtargets", "--path", meta_dir.PathString(), "--correlationid", "abc123"});
// Work around inconsistent directory naming.
Utils::copyDir(meta_dir.Path() / "repo/image", meta_dir.Path() / "repo/repo");

// failing install
auto storage = INvStorage::newStorage(conf.storage);
{
Aktualizr aktualizr(conf, storage, http);
aktualizr.Initialize();

result::UpdateCheck update_result = aktualizr.CheckUpdates().get();
EXPECT_EQ(update_result.status, result::UpdateStatus::kUpdatesAvailable);

result::Download download_result = aktualizr.Download(update_result.updates).get();
EXPECT_EQ(download_result.status, result::DownloadStatus::kSuccess);

update_result = aktualizr.CheckUpdates().get();
fiu_init(0);
fault_injection_enable("fake_package_install", 1, "", 0);
result::Install install_result = aktualizr.Install(update_result.updates).get();
EXPECT_EQ(install_result.ecu_reports.size(), 1);
EXPECT_EQ(install_result.ecu_reports[0].install_res.result_code.num_code,
data::ResultCode::Numeric::kInstallFailed);
fault_injection_disable("fake_package_install");
}

// Backend reacts to failure: no need to install the target anymore
akt_repo.run({"emptytargets", "--path", meta_dir.PathString()});
akt_repo.run({"signtargets", "--path", meta_dir.PathString(), "--correlationid", "abc123"});

// check that no update is available
{
Aktualizr aktualizr(conf, storage, http);
aktualizr.Initialize();

result::UpdateCheck update_result = aktualizr.CheckUpdates().get();
EXPECT_EQ(update_result.status, result::UpdateStatus::kNoUpdatesAvailable);
}
}

#endif

#ifndef __NO_MAIN__
int main(int argc, char **argv) {
::testing::InitGoogleTest(&argc, argv);
Expand Down
5 changes: 5 additions & 0 deletions src/libaktualizr/primary/sotauptaneclient.cc
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,7 @@ void SotaUptaneClient::finalizeAfterReboot() {

computeDeviceInstallationResult(nullptr, correlation_id);
putManifestSimple();
director_repo.dropTargets(*storage); // fix for OTA-2587, listen to backend again after end of install
} else {
// nothing found on primary
LOG_ERROR << "Expected reboot after update on primary but no update found";
Expand Down Expand Up @@ -828,6 +829,10 @@ result::Install SotaUptaneClient::uptaneInstall(const std::vector<Uptane::Target
computeDeviceInstallationResult(&result.dev_report, correlation_id);
sendEvent<event::AllInstallsComplete>(result);

if (result.dev_report.result_code != data::ResultCode::Numeric::kNeedCompletion) {
director_repo.dropTargets(*storage); // fix for OTA-2587, listen to backend again after end of install
}

return result;
}

Expand Down
14 changes: 14 additions & 0 deletions src/libaktualizr/uptane/directorrepository.cc
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,15 @@ namespace Uptane {
void DirectorRepository::resetMeta() {
resetRoot();
targets = Targets();
latest_targets = Targets();
}

bool DirectorRepository::targetsExpired() const { return latest_targets.isExpired(TimeStamp::Now()); }

bool DirectorRepository::usePreviousTargets() const {
// Don't store the new targets if they are empty and we've previously received
// a non-empty list.
return !targets.targets.empty() && latest_targets.targets.empty();
}

bool DirectorRepository::verifyTargets(const std::string& targets_raw) {
Expand Down Expand Up @@ -150,4 +159,9 @@ bool DirectorRepository::updateMeta(INvStorage& storage, Fetcher& fetcher) {
return true;
}

void DirectorRepository::dropTargets(INvStorage& storage) {
storage.clearNonRootMeta(RepositoryType::Director());
resetMeta();
}

} // namespace Uptane
7 changes: 3 additions & 4 deletions src/libaktualizr/uptane/directorrepository.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,10 @@ class DirectorRepository : public RepositoryCommon {
bool verifyTargets(const std::string& targets_raw);
const std::vector<Target>& getTargets() const { return targets.targets; }
const std::string& getCorrelationId() const { return targets.correlation_id(); }
bool targetsExpired() const { return latest_targets.isExpired(TimeStamp::Now()); }
// Don't store the new targets if they are empty and we've previously received
// a non-empty list.
bool usePreviousTargets() const { return !targets.targets.empty() && latest_targets.targets.empty(); }
bool targetsExpired() const;
bool usePreviousTargets() const;
bool checkMetaOffline(INvStorage& storage);
void dropTargets(INvStorage& storage);

Exception getLastException() const { return last_exception; }
bool updateMeta(INvStorage& storage, Fetcher& fetcher);
Expand Down
6 changes: 6 additions & 0 deletions src/libaktualizr/uptane/tuf.h
Original file line number Diff line number Diff line change
Expand Up @@ -432,6 +432,12 @@ class Targets : public MetaWithKeys {
return version_ == rhs.version() && expiry_ == rhs.expiry() && targets == rhs.targets;
}
const std::string &correlation_id() const { return correlation_id_; }
void clear() {
targets.clear();
delegated_role_names_.clear();
paths_for_role_.clear();
terminating_role_.clear();
}

std::vector<Uptane::Target> targets;
std::vector<std::string> delegated_role_names_;
Expand Down