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

OTA-2320: Add an option to aktualizr-info to print delegations metadata #1138

Merged
merged 1 commit into from
Mar 15, 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 actions.md
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,7 @@ These tools all link with libaktualizr, although they do not necessary use the A
- [x] Print primary ECU keys (aktualizr_info_test.cc)
- [x] Print primary ECU current and pending versions (aktualizr_info_test.cc)
- [x] Print device name only for scripting purposes (aktualizr_info_test.cc)
- [x] Print delegations (aktualizr_info_test.cc)

### aktualizr-repo

Expand Down
84 changes: 79 additions & 5 deletions src/aktualizr_info/aktualizr_info_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -37,30 +37,33 @@ class AktualizrInfoTest : public ::testing::Test {

virtual void TearDown() {}

// TODO: replace it with TestUtil::Process once the later is merged into master
void SpawnProcess(const std::vector<std::string> args = std::vector<std::string>{}) {
std::future<std::string> output;
std::future<std::string> err_output;
std::future<int> child_process_exit_code;
boost::asio::io_service io_service;
int child_process_exit_code = -1;

executable_args = default_executable_args;
executable_args.insert(std::end(executable_args), std::begin(args), std::end(args));
aktualizr_info_output.clear();

try {
boost::process::child aktualizr_info_child_process(
boost::process::exe = executable_to_run, boost::process::args = executable_args,
boost::process::std_out > output, boost::process::std_err > err_output, io_service);
boost::process::std_out > output, boost::process::std_err > err_output,
boost::process::on_exit = child_process_exit_code, io_service);

io_service.run();

// To get the child process exit code we need to wait even in the async case (specifics of boost::process::child)
ASSERT_TRUE(aktualizr_info_child_process.wait_for(std::chrono::seconds(20)));
child_process_exit_code = aktualizr_info_child_process.exit_code();

} catch (const std::exception& exc) {
FAIL() << "Failed to spawn process " << executable_to_run << " exited with an error: " << exc.what();
}

ASSERT_EQ(child_process_exit_code, 0)
ASSERT_EQ(child_process_exit_code.get(), 0)
<< "Process " << executable_to_run << " exited with an error: " << err_output.get();

aktualizr_info_output = output.get();
Expand All @@ -76,7 +79,8 @@ class AktualizrInfoTest : public ::testing::Test {
std::shared_ptr<INvStorage> db_storage_;

const std::string executable_to_run = "./aktualizr-info";
std::vector<std::string> executable_args = {"-c", test_conf_file_.string()};
std::vector<std::string> default_executable_args = {"-c", test_conf_file_.string()};
std::vector<std::string> executable_args;
std::string aktualizr_info_output;

std::string device_id;
Expand Down Expand Up @@ -484,6 +488,76 @@ TEST_F(AktualizrInfoTest, PrintDeviceNameOnly) {
EXPECT_EQ(aktualizr_info_output, device_id + "\n");
}

/**
* Verifies delegations metadata fetching and output
*
* * Checks actions:
*
* - [x] Print delegations
*/
TEST_F(AktualizrInfoTest, PrintDelegations) {
auto gen_and_store_delegations = [](std::shared_ptr<INvStorage>& db_storage,
std::vector<std::pair<Uptane::Role, std::string> >& delegation_records) {
unsigned indx = 0;
for (auto& delegation_rec : delegation_records) {
const std::string indx_str = std::to_string(indx);
const std::string delegation_role_val = "delegation_role_" + indx_str;

Json::Value delegation;
std::string delegation_val_str =
Utils::jsonToStr((delegation["delegation_value_key_" + indx_str] = "delegation_value_" + indx_str));

delegation_rec.first = Uptane::Role::Delegation(delegation_role_val);
delegation_rec.second = delegation_val_str;
db_storage->storeDelegation(delegation_val_str, Uptane::Role::Delegation(delegation_role_val));

++indx;
}
};

auto verify_delegations = [](const std::string& output_str,
std::vector<std::pair<Uptane::Role, std::string> >& delegation_records) {
for (auto& delegation_rec : delegation_records) {
ASSERT_NE(output_str.find(delegation_rec.first.ToString()), std::string::npos);
ASSERT_NE(output_str.find(delegation_rec.second), std::string::npos);
}
};

// aktualizer-info won't print anything if a director root metadata are not stored in the DB
db_storage_->storeRoot(Utils::jsonToStr(Json::Value()), Uptane::RepositoryType::Director(), Uptane::Version(1));

// case 0: no delegations in the DB
{
SpawnProcess(std::vector<std::string>({"--delegation"}));
ASSERT_FALSE(aktualizr_info_output.empty());
EXPECT_NE(aktualizr_info_output.find("Delegations are not present"), std::string::npos);
}

// case 1: there is one delegation metadata record in the DB
{
std::vector<std::pair<Uptane::Role, std::string> > delegation_records{1, {Uptane::Role::Delegation(""), ""}};
gen_and_store_delegations(db_storage_, delegation_records);

SpawnProcess(std::vector<std::string>({"--delegation"}));
ASSERT_FALSE(aktualizr_info_output.empty());

verify_delegations(aktualizr_info_output, delegation_records);
}

db_storage_->clearDelegations();

// case 2: there are more than one delegation metadata records in the DB
{
std::vector<std::pair<Uptane::Role, std::string> > delegation_records{3, {Uptane::Role::Delegation(""), ""}};
gen_and_store_delegations(db_storage_, delegation_records);

SpawnProcess(std::vector<std::string>({"--delegation"}));
ASSERT_FALSE(aktualizr_info_output.empty());

verify_delegations(aktualizr_info_output, delegation_records);
}
}

#ifndef __NO_MAIN__
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
Expand Down
25 changes: 25 additions & 0 deletions src/aktualizr_info/main.cc
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,25 @@

namespace po = boost::program_options;

static void loadAndPrintDelegations(const std::shared_ptr<INvStorage> &storage) {
std::vector<std::pair<Uptane::Role, std::string> > delegations;
bool delegations_fetch_res = storage->loadAllDelegations(delegations);

if (!delegations_fetch_res) {
std::cout << "Failed to load delegations" << std::endl;
return;
}

if (delegations.size() == 0) {
std::cout << "Delegations are not present" << std::endl;
}

std::cout << "Delegations:" << std::endl;
for (auto delegation : delegations) {
std::cout << delegation.first << ": " << delegation.second << std::endl;
}
}

int main(int argc, char **argv) {
po::options_description desc("aktualizr-info command line options");
// clang-format off
Expand All @@ -24,6 +43,7 @@ int main(int argc, char **argv) {
("ecu-keys", "Outputs UPTANE keys")
("images-root", "Outputs root.json from images repo")
("images-target", "Outputs targets.json from images repo")
("delegation", "Outputs metadata of image repo targets' delegations")
("director-root", "Outputs root.json from director repo")
("director-target", "Outputs targets.json from director repo")
("allow-migrate", "Opens database in read/write mode to make possible to migrate database if needed");
Expand Down Expand Up @@ -54,6 +74,7 @@ int main(int argc, char **argv) {
std::string director_targets;
std::string images_root;
std::string images_targets;

bool has_metadata = storage->loadLatestRoot(&director_root, Uptane::RepositoryType::Director());
storage->loadLatestRoot(&images_root, Uptane::RepositoryType::Image());
storage->loadNonRoot(&director_targets, Uptane::RepositoryType::Director(), Uptane::Role::Targets());
Expand Down Expand Up @@ -116,6 +137,10 @@ int main(int argc, char **argv) {
std::cout << images_targets << std::endl;
}

if (vm.count("delegation") != 0u) {
loadAndPrintDelegations(storage);
}

if (vm.count("director-root") != 0u) {
std::cout << "director root.json content:" << std::endl;
std::cout << director_root << std::endl;
Expand Down
1 change: 1 addition & 0 deletions src/libaktualizr/storage/invstorage.h
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ class INvStorage {
virtual void clearMetadata() = 0;
virtual void storeDelegation(const std::string& data, Uptane::Role role) = 0;
virtual bool loadDelegation(std::string* data, Uptane::Role role) = 0;
virtual bool loadAllDelegations(std::vector<std::pair<Uptane::Role, std::string>>& data) const = 0;
virtual void deleteDelegation(Uptane::Role role) = 0;
virtual void clearDelegations() = 0;

Expand Down
30 changes: 30 additions & 0 deletions src/libaktualizr/storage/sqlstorage.cc
Original file line number Diff line number Diff line change
Expand Up @@ -561,6 +561,36 @@ bool SQLStorage::loadDelegation(std::string* data, const Uptane::Role role) {
return true;
}

bool SQLStorage::loadAllDelegations(std::vector<std::pair<Uptane::Role, std::string>>& data) const {
bool result = false;

try {
SQLite3Guard db = dbConnection();

auto statement = db.prepareStatement("SELECT meta, role_name FROM delegations;");
auto statement_state = statement.step();

if (statement_state == SQLITE_DONE) {
LOG_TRACE << "Delegations metadata are not present";
return true;
} else if (statement_state != SQLITE_ROW) {
LOG_ERROR << "Can't get delegations metadata: " << db.errmsg();
return false;
}

do {
data.emplace_back(Uptane::Role::Delegation(statement.get_result_col_str(1).value()),
statement.get_result_col_blob(0).value());
} while ((statement_state = statement.step()) == SQLITE_ROW);

result = true;
} catch (const std::exception& exc) {
LOG_ERROR << "Failed to fetch records from `delegations` table: " << exc.what();
}

return result;
}

void SQLStorage::deleteDelegation(const Uptane::Role role) {
SQLite3Guard db = dbConnection();

Expand Down
1 change: 1 addition & 0 deletions src/libaktualizr/storage/sqlstorage.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ class SQLStorage : public SQLStorageBase, public INvStorage {
void clearMetadata() override;
void storeDelegation(const std::string& data, Uptane::Role role) override;
bool loadDelegation(std::string* data, Uptane::Role role) override;
bool loadAllDelegations(std::vector<std::pair<Uptane::Role, std::string>>& data) const override;
void deleteDelegation(Uptane::Role role) override;
void clearDelegations() override;

Expand Down