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

Commit

Permalink
Add campaign decline and postpone commands
Browse files Browse the repository at this point in the history
Signed-off-by: Laurent Bonnans <laurent.bonnans@here.com>
  • Loading branch information
lbonn committed Jun 4, 2019
1 parent b59ed45 commit 8f449dc
Show file tree
Hide file tree
Showing 11 changed files with 143 additions and 35 deletions.
8 changes: 8 additions & 0 deletions actions.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,14 @@ These are the primary actions that a user of libaktualizr can perform through th
- [x] Send campaign acceptance report
- [x] Send an event report (see below)
- [x] Send CampaignAcceptComplete event
- [x] Decline a campaign
- [x] Send campaign decline report
- [x] Send an event report (see below)
- [x] Send CampaignDeclineComplete event
- [x] Postpone a campaign
- [x] Send campaign postpone report
- [x] Send an event report (see below)
- [x] Send CampaignPostponeComplete event
- [x] Fetch metadata from server
- [x] Generate and send manifest (see below)
- [x] Fetch metadata from the director (uptane_test.cc, uptane_vector_tests.cc)
Expand Down
9 changes: 5 additions & 4 deletions src/aktualizr_primary/main.cc
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ bpo::variables_map parse_options(int argc, char *argv[]) {
("version,v", "Current aktualizr version")
("config,c", bpo::value<std::vector<boost::filesystem::path> >()->composing(), "configuration file or directory")
("loglevel", bpo::value<int>(), "set log level 0-5 (trace, debug, info, warning, error, fatal)")
("run-mode", bpo::value<std::string>(), "run mode of aktualizr: full, once, campaign_check, campaign_accept, check, download, or install")
("run-mode", bpo::value<std::string>(), "run mode of aktualizr: full, once, campaign_check, campaign_accept, campaign_decline, campaign_pospone, check, download, or install")
("tls-server", bpo::value<std::string>(), "url of device gateway")
("repo-server", bpo::value<std::string>(), "url of the uptane repo repository")
("director-server", bpo::value<std::string>(), "url of the uptane director repository")
Expand Down Expand Up @@ -136,11 +136,12 @@ int main(int argc, char *argv[]) {
// launch the first event
if (run_mode == "campaign_check") {
aktualizr.CampaignCheck().get();
} else if (run_mode == "campaign_accept") {
} else if (run_mode == "campaign_accept" || run_mode == "campaign_decline" || run_mode == "campaign_postpone") {
if (commandline_map.count("campaign-id") == 0) {
throw std::runtime_error("Accepting a campaign requires a campaign ID");
throw std::runtime_error(run_mode + " requires a campaign ID");
}
aktualizr.CampaignAccept(commandline_map["campaign-id"].as<std::string>()).get();
aktualizr.CampaignControl(commandline_map["campaign-id"].as<std::string>(), campaign::cmdFromName(run_mode))
.get();
} else if (run_mode == "check") {
aktualizr.SendDeviceData().get();
aktualizr.CheckUpdates().get();
Expand Down
12 changes: 12 additions & 0 deletions src/libaktualizr/campaign/campaign.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,18 @@ class CampaignParseError : std::exception {
const char *what() const noexcept override { return "Could not parse Campaign metadata"; }
};

enum class Cmd {
Accept,
Decline,
Postpone,
};

static inline Cmd cmdFromName(const std::string &name) {
return std::map<std::string, Cmd>{
{"campaign_accept", Cmd::Accept}, {"campaign_decline", Cmd::Decline}, {"campaign_postpone", Cmd::Postpone}}
.at(name);
}

// Out of uptane concept: update campaign for a device
class Campaign {
public:
Expand Down
18 changes: 16 additions & 2 deletions src/libaktualizr/primary/aktualizr.cc
Original file line number Diff line number Diff line change
Expand Up @@ -96,8 +96,22 @@ std::future<result::CampaignCheck> Aktualizr::CampaignCheck() {
return api_queue_.enqueue(task);
}

std::future<void> Aktualizr::CampaignAccept(const std::string &campaign_id) {
std::function<void()> task([this, &campaign_id] { uptane_client_->campaignAccept(campaign_id); });
std::future<void> Aktualizr::CampaignControl(const std::string &campaign_id, campaign::Cmd cmd) {
std::function<void()> task([this, &campaign_id, cmd] {
switch (cmd) {
case campaign::Cmd::Accept:
uptane_client_->campaignAccept(campaign_id);
break;
case campaign::Cmd::Decline:
uptane_client_->campaignDecline(campaign_id);
break;
case campaign::Cmd::Postpone:
uptane_client_->campaignPostpone(campaign_id);
break;
default:
break;
}
});
return api_queue_.enqueue(task);
}

Expand Down
13 changes: 8 additions & 5 deletions src/libaktualizr/primary/aktualizr.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,13 +48,16 @@ class Aktualizr {
std::future<result::CampaignCheck> CampaignCheck();

/**
* Accept a campaign for the current device.
* Campaigns are a concept outside of Uptane, and allow for user approval of
* updates before the contents of the update are known.
* Act on campaign: accept, decline or postpone.
* Accepted campaign will be removed from the campaign list but no guarantee
* is made for declined or postponed items. Applications are responsible for
* tracking their state but this method will notify the server for device
* state monitoring purposes.
* @param campaign_id Campaign ID as provided by CampaignCheck.
* @param cmd action to apply on the campaign: accept, decline or postpone
* @return Empty std::future object
*/
std::future<void> CampaignAccept(const std::string& campaign_id);
std::future<void> CampaignControl(const std::string& campaign_id, campaign::Cmd cmd);

/**
* Send local device data to the server.
Expand Down Expand Up @@ -169,7 +172,7 @@ class Aktualizr {
FRIEND_TEST(Aktualizr, DownloadFailures);
FRIEND_TEST(Aktualizr, InstallWithUpdates);
FRIEND_TEST(Aktualizr, ReportDownloadProgress);
FRIEND_TEST(Aktualizr, CampaignCheckAndAccept);
FRIEND_TEST(Aktualizr, CampaignCheckAndControl);
FRIEND_TEST(Aktualizr, FullNoCorrelationId);
FRIEND_TEST(Aktualizr, ManifestCustom);
FRIEND_TEST(Aktualizr, APICheck);
Expand Down
77 changes: 53 additions & 24 deletions src/libaktualizr/primary/aktualizr_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1546,7 +1546,8 @@ class HttpFakeCampaign : public HttpFake {
(void)url;
for (auto it = data.begin(); it != data.end(); it++) {
auto ev = *it;
if (ev["eventType"]["id"] == "campaign_accepted") {
auto id = ev["eventType"]["id"];
if (id == "campaign_accepted" || id == "campaign_declined" || id == "campaign_postponed") {
seen_events.push_back(ev);
}
}
Expand All @@ -1556,52 +1557,80 @@ class HttpFakeCampaign : public HttpFake {
std::vector<Json::Value> seen_events;
};

bool campaignaccept_seen = false;
void CampaignCheck_events(const std::shared_ptr<event::BaseEvent>& event) {
std::cout << event->variant << "\n";
if (event->variant == "CampaignCheckComplete") {
auto concrete_event = std::static_pointer_cast<event::CampaignCheckComplete>(event);
EXPECT_EQ(concrete_event->result.campaigns.size(), 1);
EXPECT_EQ(concrete_event->result.campaigns[0].name, "campaign1");
EXPECT_EQ(concrete_event->result.campaigns[0].id, "c2eb7e8d-8aa0-429d-883f-5ed8fdb2a493");
EXPECT_EQ(concrete_event->result.campaigns[0].size, 62470);
EXPECT_EQ(concrete_event->result.campaigns[0].autoAccept, true);
EXPECT_EQ(concrete_event->result.campaigns[0].description, "this is my message to show on the device");
} else if (event->variant == "CampaignAcceptComplete") {
campaignaccept_seen = true;
class CampaignEvents {
public:
bool campaignaccept_seen{false};
bool campaigndecline_seen{false};
bool campaignpostpone_seen{false};

void handler(const std::shared_ptr<event::BaseEvent>& event) {
std::cout << event->variant << "\n";
if (event->variant == "CampaignCheckComplete") {
auto concrete_event = std::static_pointer_cast<event::CampaignCheckComplete>(event);
EXPECT_EQ(concrete_event->result.campaigns.size(), 1);
EXPECT_EQ(concrete_event->result.campaigns[0].name, "campaign1");
EXPECT_EQ(concrete_event->result.campaigns[0].id, "c2eb7e8d-8aa0-429d-883f-5ed8fdb2a493");
EXPECT_EQ(concrete_event->result.campaigns[0].size, 62470);
EXPECT_EQ(concrete_event->result.campaigns[0].autoAccept, true);
EXPECT_EQ(concrete_event->result.campaigns[0].description, "this is my message to show on the device");
} else if (event->variant == "CampaignAcceptComplete") {
campaignaccept_seen = true;
} else if (event->variant == "CampaignDeclineComplete") {
campaigndecline_seen = true;
} else if (event->variant == "CampaignPostponeComplete") {
campaignpostpone_seen = true;
}
}
}
};

/* Check for campaigns with manual control.
* Accept a campaign.
* Send CampaignCheckComplete event with campaign data.
* Fetch campaigns from the server.
*
* Accept a campaign.
* Send campaign acceptance report.
* Send CampaignAcceptComplete event.
* Send CampaignCheckComplete event with campaign data.
*
* Decline a campaign.
* Send campaign decline report.
* Send CampaignDeclineComplete event.
*
* Postpone a campaign.
* Send campaign postpone report.
* Send CampaignPostponeComplete event.
*/
TEST(Aktualizr, CampaignCheckAndAccept) {
TEST(Aktualizr, CampaignCheckAndControl) {
TemporaryDirectory temp_dir;
auto http = std::make_shared<HttpFakeCampaign>(temp_dir.Path());
Config conf = UptaneTestCommon::makeTestConfig(temp_dir, http->tls_server);

CampaignEvents campaign_events;

{
auto storage = INvStorage::newStorage(conf.storage);
Aktualizr aktualizr(conf, storage, http);
std::function<void(std::shared_ptr<event::BaseEvent> event)> f_cb = CampaignCheck_events;
aktualizr.SetSignalHandler(f_cb);
aktualizr.SetSignalHandler(std::bind(&CampaignEvents::handler, &campaign_events, std::placeholders::_1));
aktualizr.Initialize();

// check for campaign
auto result = aktualizr.CampaignCheck().get();
EXPECT_EQ(result.campaigns.size(), 1);

// accept the campaign
aktualizr.CampaignAccept("c2eb7e8d-8aa0-429d-883f-5ed8fdb2a493").get();
aktualizr.CampaignControl("c2eb7e8d-8aa0-429d-883f-5ed8fdb2a493", campaign::Cmd::Accept).get();

aktualizr.CampaignControl("c2eb7e8d-8aa0-429d-883f-5ed8fdb2a493", campaign::Cmd::Decline).get();

aktualizr.CampaignControl("c2eb7e8d-8aa0-429d-883f-5ed8fdb2a493", campaign::Cmd::Postpone).get();
}

ASSERT_EQ(http->seen_events.size(), 1);
ASSERT_EQ(http->seen_events[0]["event"]["campaignId"], "c2eb7e8d-8aa0-429d-883f-5ed8fdb2a493");
ASSERT_TRUE(campaignaccept_seen);
ASSERT_EQ(http->seen_events.size(), 3);
for (const auto& ev : http->seen_events) {
EXPECT_EQ(ev["event"]["campaignId"], "c2eb7e8d-8aa0-429d-883f-5ed8fdb2a493");
}
EXPECT_TRUE(campaign_events.campaignaccept_seen);
EXPECT_TRUE(campaign_events.campaigndecline_seen);
EXPECT_TRUE(campaign_events.campaignpostpone_seen);
}

class HttpFakeNoCorrelationId : public HttpFake {
Expand Down
10 changes: 10 additions & 0 deletions src/libaktualizr/primary/events.h
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,16 @@ class CampaignAcceptComplete : public BaseEvent {
CampaignAcceptComplete() { variant = "CampaignAcceptComplete"; }
};

class CampaignDeclineComplete : public BaseEvent {
public:
CampaignDeclineComplete() { variant = "CampaignDeclineComplete"; }
};

class CampaignPostponeComplete : public BaseEvent {
public:
CampaignPostponeComplete() { variant = "CampaignPostponeComplete"; }
};

using Channel = boost::signals2::signal<void(std::shared_ptr<event::BaseEvent>)>;

} // namespace event
Expand Down
9 changes: 9 additions & 0 deletions src/libaktualizr/primary/reportqueue.cc
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,15 @@ CampaignAcceptedReport::CampaignAcceptedReport(const std::string& campaign_id) :
custom["campaignId"] = campaign_id;
}

CampaignDeclinedReport::CampaignDeclinedReport(const std::string& campaign_id) : ReportEvent("campaign_declined", 0) {
custom["campaignId"] = campaign_id;
}

CampaignPostponedReport::CampaignPostponedReport(const std::string& campaign_id)
: ReportEvent("campaign_postponed", 0) {
custom["campaignId"] = campaign_id;
}

DevicePausedReport::DevicePausedReport(const std::string& correlation_id) : ReportEvent("DevicePaused", 0) {
setCorrelationId(correlation_id);
}
Expand Down
10 changes: 10 additions & 0 deletions src/libaktualizr/primary/reportqueue.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,16 @@ class CampaignAcceptedReport : public ReportEvent {
CampaignAcceptedReport(const std::string& campaign_id);
};

class CampaignDeclinedReport : public ReportEvent {
public:
CampaignDeclinedReport(const std::string& campaign_id);
};

class CampaignPostponedReport : public ReportEvent {
public:
CampaignPostponedReport(const std::string& campaign_id);
};

class DevicePausedReport : public ReportEvent {
public:
DevicePausedReport(const std::string& correlation_id);
Expand Down
10 changes: 10 additions & 0 deletions src/libaktualizr/primary/sotauptaneclient.cc
Original file line number Diff line number Diff line change
Expand Up @@ -856,6 +856,16 @@ void SotaUptaneClient::campaignAccept(const std::string &campaign_id) {
report_queue->enqueue(std_::make_unique<CampaignAcceptedReport>(campaign_id));
}

void SotaUptaneClient::campaignDecline(const std::string &campaign_id) {
sendEvent<event::CampaignDeclineComplete>();
report_queue->enqueue(std_::make_unique<CampaignDeclinedReport>(campaign_id));
}

void SotaUptaneClient::campaignPostpone(const std::string &campaign_id) {
sendEvent<event::CampaignPostponeComplete>();
report_queue->enqueue(std_::make_unique<CampaignPostponedReport>(campaign_id));
}

bool SotaUptaneClient::isInstallCompletionRequired() {
bool force_install_completion = (hasPendingUpdates() && config.uptane.force_install_completion);
return force_install_completion;
Expand Down
2 changes: 2 additions & 0 deletions src/libaktualizr/primary/sotauptaneclient.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ class SotaUptaneClient {
result::Install uptaneInstall(const std::vector<Uptane::Target> &updates);
result::CampaignCheck campaignCheck();
void campaignAccept(const std::string &campaign_id);
void campaignDecline(const std::string &campaign_id);
void campaignPostpone(const std::string &campaign_id);
bool hasPendingUpdates();
bool isInstallCompletionRequired();
void completeInstall();
Expand Down

0 comments on commit 8f449dc

Please sign in to comment.