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

Commit

Permalink
OTA-2320: Add an option to aktualizr-info to print delegations metadata
Browse files Browse the repository at this point in the history
Signed-off-by: Mike Sul <[email protected]>
  • Loading branch information
Mike Sul committed Mar 14, 2019
1 parent ffbed75 commit 8259aeb
Show file tree
Hide file tree
Showing 6 changed files with 141 additions and 5 deletions.
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
83 changes: 78 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,75 @@ 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,
INvStorage::DelegationArray& delegation_records) {
unsigned indx = 0;
for (INvStorage::DelegationRecord& 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));

std::get<0>(delegation_rec) = delegation_val_str;
std::get<1>(delegation_rec) = delegation_role_val;
db_storage->storeDelegation(delegation_val_str, Uptane::Role::Delegation(delegation_role_val));

++indx;
}
};

auto verify_delegations = [](const std::string& output_str, INvStorage::DelegationArray& delegation_records) {
for (INvStorage::DelegationRecord& delegation_rec : delegation_records) {
ASSERT_NE(output_str.find(std::get<1>(delegation_rec)), std::string::npos);
ASSERT_NE(output_str.find(std::get<1>(delegation_rec)), 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
{
INvStorage::DelegationArray delegation_records{1};
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
{
INvStorage::DelegationArray delegation_records{3};
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
26 changes: 26 additions & 0 deletions src/aktualizr_info/main.cc
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,28 @@

namespace po = boost::program_options;

static void loadAndPrintDelegations(const std::shared_ptr<INvStorage> &storage) {
INvStorage::DelegationArray 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 << std::get<1>(delegation) << ": " << std::get<0>(delegation) << std::endl;
}
}

int main(int argc, char **argv) {
po::options_description desc("aktualizr-info command line options");
const std::string delegation_opt_name = "delegation";
// clang-format off
desc.add_options()
("help,h", "print usage")
Expand All @@ -24,6 +44,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_opt_name.c_str(), "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 +75,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 +138,10 @@ int main(int argc, char **argv) {
std::cout << images_targets << std::endl;
}

if (vm.count(delegation_opt_name) != 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
5 changes: 5 additions & 0 deletions src/libaktualizr/storage/invstorage.h
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,10 @@ enum class InstalledVersionUpdateMode { kNone, kCurrent, kPending };
// Functions loading/storing multiple pieces of data are supposed to do so atomically as far as implementation makes it
// possible
class INvStorage {
public:
using DelegationRecord = std::tuple<std::string, std::string>;
using DelegationArray = std::vector<DelegationRecord>;

public:
explicit INvStorage(StorageConfig config) : config_(std::move(config)) {}
virtual ~INvStorage() = default;
Expand Down Expand Up @@ -138,6 +142,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(DelegationArray& 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(DelegationArray& 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(
DelegationRecord({statement.get_result_col_blob(0).value(), statement.get_result_col_str(1).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(DelegationArray& data) const override;
void deleteDelegation(Uptane::Role role) override;
void clearDelegations() override;

Expand Down

0 comments on commit 8259aeb

Please sign in to comment.