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

C API for UptaneCycle and campaigns #1263

Merged
merged 3 commits into from
Aug 2, 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
7 changes: 0 additions & 7 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -119,12 +119,6 @@ else(BUILD_OSTREE)
unset(LIBOSTREE_LIBRARIES CACHE)
endif(BUILD_OSTREE)

if(BUILD_DEB)
pkg_check_modules(LIBDPKG REQUIRED libdpkg)
else(BUILD_DEB)
unset(LIBDPKG_LIBRARIES CACHE)
endif(BUILD_DEB)

if(BUILD_DOCKERAPP)
add_definitions(-DBUILD_DOCKERAPP)
endif(BUILD_DOCKERAPP)
Expand Down Expand Up @@ -377,7 +371,6 @@ set (AKTUALIZR_EXTERNAL_LIBS
${SQLITE3_LIBRARIES}
${LibArchive_LIBRARIES}
${LIBP11_LIBRARIES}
${LIBDPKG_LIBRARIES}
${GLIB2_LIBRARIES}
${SYSTEMD_LIBRARY}
${ZLIB_LIBRARY})
Expand Down
1 change: 0 additions & 1 deletion README.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,6 @@ Some features also require additional packages:
* For PKCS#11 support, you will need `libp11-2 libp11-dev`.
* For systemd support for secondaries, you will need `libsystemd-dev`.
* For fault injection, you will need `fiu-utils libfiu-dev`.
* For Debian packagin support, you will need `libdpkg-dev`.

==== Mac support

Expand Down
2 changes: 0 additions & 2 deletions docker/Dockerfile.debian.testing
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ RUN apt-get update && apt-get -y install --no-install-suggests --no-install-reco
cmake \
curl \
doxygen \
dpkg-dev \
e2fslibs-dev \
g++ \
gcc \
Expand All @@ -34,7 +33,6 @@ RUN apt-get update && apt-get -y install --no-install-suggests --no-install-reco
libboost-test-dev \
libboost-thread-dev \
libcurl4-openssl-dev \
libdpkg-dev \
libengine-pkcs11-openssl \
libexpat1-dev \
libfuse-dev \
Expand Down
1 change: 0 additions & 1 deletion docker/Dockerfile.ubuntu.bionic
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ RUN apt-get update && apt-get -y install --no-install-suggests --no-install-reco
libboost-test-dev \
libboost-thread-dev \
libcurl4-openssl-dev \
libdpkg-dev \
libengine-pkcs11-openssl \
libexpat1-dev \
libffi-dev \
Expand Down
1 change: 0 additions & 1 deletion docker/Dockerfile.ubuntu.xenial
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ RUN apt-get update && apt-get -y install --no-install-suggests --no-install-reco
libboost-test-dev \
libboost-thread-dev \
libcurl4-openssl-dev \
libdpkg-dev \
libengine-pkcs11-openssl \
libexpat1-dev \
libffi-dev \
Expand Down
30 changes: 30 additions & 0 deletions include/libaktualizr-c.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#ifndef AKTUALIZR_LIBAKTUALIZRC_H
#define AKTUALIZR_LIBAKTUALIZRC_H

#ifdef __cplusplus
#include "primary/aktualizr.h"

using Campaign = campaign::Campaign;

extern "C" {
#else
typedef struct Aktualizr Aktualizr;
typedef struct Campaign Campaign;
#endif

Aktualizr *Aktualizr_create(const char *config_path);
int Aktualizr_initialize(Aktualizr *a);
int Aktualizr_uptane_cycle(Aktualizr *a);
void Aktualizr_destroy(Aktualizr *a);

Campaign *Aktualizr_campaign_check(Aktualizr *a);
int Aktualizr_campaign_accept(Aktualizr *a, Campaign *c);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a bit annoying that we have to pass an Aktualizr instance to all of these. Would be handy if Campaign contained a pointer. But that might need changes in the C++ object, don't know if we want that.

Copy link
Contributor Author

@eu-siemann eu-siemann Jul 30, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see no problem in this, tbh. That's pretty much idiomatic C and is equivalent to Aktualizr->CampaignAccept(Campaign *c). If we do just a single arg here, I would expect our C++ API to also change to Campaign->Accept(). I'm not sure if it makes it nicer, though.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok I think you're right.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On second thought, maybe it's not a bad thing to make those calls members of Campaign object. This way, we would prevent passing a campaign_id that belongs to another Aktualizr instance (a hypothetical situation, but still). WDYT, @lbonn @patrickvacek @mike-sul ?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If it doesn't require changes to the C++ code, then that seems like the way to go. Even if it does, that seems to me to be a slightly better way to go.

int Aktualizr_campaign_postpone(Aktualizr *a, Campaign *c);
int Aktualizr_campaign_decline(Aktualizr *a, Campaign *c);
void Aktualizr_campaign_free(Campaign *c);

#ifdef __cplusplus
}
#endif

#endif //AKTUALIZR_LIBAKTUALIZR_H
1 change: 1 addition & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ if(BUILD_WITH_CODE_COVERAGE)
endif()

add_subdirectory("libaktualizr")
add_subdirectory("libaktualizr-c")
add_subdirectory("virtual_secondary")
add_subdirectory("sota_tools")
add_subdirectory("aktualizr_primary")
Expand Down
10 changes: 10 additions & 0 deletions src/libaktualizr-c/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
SET(TARGET_NAME aktualizr-c)
SET(SOURCES libaktualizr-c.cc)

add_library(${TARGET_NAME} SHARED ${SOURCES})
target_include_directories(${TARGET_NAME} PUBLIC ${PROJECT_SOURCE_DIR}/include)
target_link_libraries(${TARGET_NAME} PRIVATE aktualizr_static_lib ${AKTUALIZR_EXTERNAL_LIBS})

aktualizr_source_file_checks(${SOURCES})

add_subdirectory(test)
77 changes: 77 additions & 0 deletions src/libaktualizr-c/libaktualizr-c.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
#include "libaktualizr-c.h"

Aktualizr *Aktualizr_create(const char *config_path) {
Aktualizr *a;
try {
Config cfg(config_path);
a = new Aktualizr(cfg);
} catch (const std::exception &e) {
std::cerr << "Aktualizr_create exception: " << e.what() << std::endl;
return nullptr;
}
return a;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe, there will be a need/requirement to return some status/error code to am app using the C version of libaktualizr, otherwise the only way to find out what went wrong is by parsing stderr.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mike-sul Absolutely. But first, we'll need to make sure that exceptions thrown by libaktualizr are consistent and meaningful. I plan to work on that next.

}

int Aktualizr_initialize(Aktualizr *a) {
try {
a->Initialize();
} catch (const std::exception &e) {
std::cerr << "Aktualizr_initialize exception: " << e.what() << std::endl;
return -1;
}
return 0;
}

int Aktualizr_uptane_cycle(Aktualizr *a) {
try {
a->UptaneCycle();
} catch (const std::exception &e) {
std::cerr << "Uptane cycle exception: " << e.what() << std::endl;
return -1;
}
return 0;
}

void Aktualizr_destroy(Aktualizr *a) { delete a; }

Campaign *Aktualizr_campaign_check(Aktualizr *a) {
try {
auto r = a->CampaignCheck().get();
if (!r.campaigns.empty()) {
// We don't support multiple campaigns at the moment
return new Campaign(r.campaigns[0]);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it fair to assume there will never be multiple campaigns? It would indeed be confusing if there were, but a comment to state the assumption might be worthwhile.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not supported at the moment, so I think it's worth keeping it simple here. I'll add a comment.

}
} catch (const std::exception &e) {
std::cerr << "Campaign check exception: " << e.what() << std::endl;
return nullptr;
}
return nullptr;
}
int Aktualizr_campaign_accept(Aktualizr *a, Campaign *c) {
try {
a->CampaignControl(c->id, campaign::Cmd::Accept).get();
} catch (const std::exception &e) {
std::cerr << "Campaign accept exception: " << e.what() << std::endl;
return -1;
}
return 0;
}
int Aktualizr_campaign_postpone(Aktualizr *a, Campaign *c) {
try {
a->CampaignControl(c->id, campaign::Cmd::Postpone).get();
} catch (const std::exception &e) {
std::cerr << "Campaign postpone exception: " << e.what() << std::endl;
return -1;
}
return 0;
}
int Aktualizr_campaign_decline(Aktualizr *a, Campaign *c) {
try {
a->CampaignControl(c->id, campaign::Cmd::Decline).get();
} catch (const std::exception &e) {
std::cerr << "Campaign decline exception: " << e.what() << std::endl;
return -1;
}
return 0;
}
void Aktualizr_campaign_free(Campaign *c) { delete c; }
8 changes: 8 additions & 0 deletions src/libaktualizr-c/test/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
SET(TARGET_NAME api-test)
SET(SOURCES api-test.c)

add_executable(${TARGET_NAME} EXCLUDE_FROM_ALL ${SOURCES})
add_dependencies(build_tests ${TARGET_NAME})
target_link_libraries(${TARGET_NAME} aktualizr-c)

aktualizr_source_file_checks(${SOURCES})
44 changes: 44 additions & 0 deletions src/libaktualizr-c/test/api-test.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
#include <stdio.h>
#include <stdlib.h>

#include "libaktualizr-c.h"

int main(int argc, char **argv) {
Aktualizr *a;
Campaign *c;
int err;

if (argc != 2) {
fprintf(stderr, "Missing config file\nUsage:\n\t%s CONFIG_FILE\n", argv[0]);
return EXIT_FAILURE;
}

a = Aktualizr_create(argv[1]);
if (!a) {
return EXIT_FAILURE;
}

err = Aktualizr_initialize(a);
if (err) {
return EXIT_FAILURE;
}

c = Aktualizr_campaign_check(a);
if (c) {
printf("Accepting running campaign\n");
err = Aktualizr_campaign_accept(a, c);
Aktualizr_campaign_free(c);
if (err) {
return EXIT_FAILURE;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will the aktualizr instance be properly tear-downed and freed in this case as well as in case of line #23 ? Or it's not important taking into account that the process is going to die anyway ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It won't, I forgot how to write proper C ;) But I'm rewriting this piece anyway

}
}

err = Aktualizr_uptane_cycle(a);
if (err) {
return EXIT_FAILURE;
}

Aktualizr_destroy(a);

return EXIT_SUCCESS;
}
3 changes: 0 additions & 3 deletions src/libaktualizr/package_manager/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,6 @@ add_aktualizr_test(NAME packagemanagerfake SOURCES packagemanagerfake_test.cc)
# Debian backend
if(BUILD_DEB)
set_property(SOURCE packagemanagerfactory.cc packagemanagerfactory_test.cc PROPERTY COMPILE_DEFINITIONS BUILD_DEB)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We probably don't need to set this BUILD_DEB definition here anymore, right? In fact, is BUILD_DEB meaningful at all anymore? In CI it's built by default, and if it brings in no dependencies, there's hardly a reason not to just have it always on.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a fair point, though we'd ship a code path that calls dpkg on yocto systems where it doesn't make sense. I don't know if the cost of keeping it (low, I think) warrants larger executables and potential bug surface.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably true. Perhaps we should disable by default on CI and only enable it as necessary?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Our approach on CI has been to enable all flags, so that everything can be tested at once. The things that are not covered tend to not compile after refactors.

Also, some unrelated useful tests use the Debian mode. For example memory_test. We'll probably migrate them when we can though.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fair enough. I have no objection.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@patrickvacek, @lbonn Sorry, I'm a bit confused, what's your conclusion on that?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think just keep it as is?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cool, that's what I thought, just wanted to be sure.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, sorry for the distraction!

if (${LIBDPKG_VERSION} VERSION_GREATER "1.19.3")
set_property(SOURCE debianmanager.cc PROPERTY COMPILE_DEFINITIONS LIBDPKG_V011903)
endif()
target_sources(package_manager PRIVATE debianmanager.cc)
add_executable(t_packagemanager_deb EXCLUDE_FROM_ALL debianmanager_test.cc)
add_dependencies(build_tests t_packagemanager_deb)
Expand Down
30 changes: 2 additions & 28 deletions src/libaktualizr/package_manager/debianmanager.cc
Original file line number Diff line number Diff line change
@@ -1,37 +1,11 @@
#include "package_manager/debianmanager.h"

#define LIBDPKG_VOLATILE_API 1
#include <dpkg/dpkg-db.h>
#include <dpkg/dpkg.h>
#include <dpkg/pkg-array.h>
#include <dpkg/pkg-show.h>
#include <stdio.h>
#include <unistd.h>

Json::Value DebianManager::getInstalledPackages() const {
Json::Value packages(Json::arrayValue);
struct pkg_array array {};
dpkg_program_init("a.out");
modstatdb_open(msdbrw_available_readonly);

#ifdef LIBDPKG_V011903
pkg_array_init_from_hash(&array);
#else
pkg_array_init_from_db(&array);
#endif
pkg_array_sort(&array, pkg_sorter_by_nonambig_name_arch);
for (int i = 0; i < array.n_pkgs; ++i) {
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
struct pkginfo *pkg = array.pkgs[i];
if (pkg->status == PKG_STAT_INSTALLED) {
Json::Value package;
package["name"] = pkg_name(pkg, pnaw_nonambig);
package["version"] = versiondescribe(&pkg->installed.version, vdew_nonambig);
packages.append(package);
}
}
dpkg_program_done();
return packages;
// Currently not implemented
return Json::Value(Json::arrayValue);
}

data::InstallationResult DebianManager::install(const Uptane::Target &target) const {
Expand Down
4 changes: 3 additions & 1 deletion src/libaktualizr/primary/aktualizr.h
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,9 @@ class Aktualizr {
*/
boost::signals2::connection SetSignalHandler(const std::function<void(std::shared_ptr<event::BaseEvent>)>& handler);

private:
Config config_;

protected:
Aktualizr(Config& config, std::shared_ptr<INvStorage> storage_in, std::shared_ptr<HttpInterface> http_in);

Expand All @@ -166,7 +169,6 @@ class Aktualizr {
private:
static void systemSetup();

Config& config_;
std::shared_ptr<INvStorage> storage_;
std::shared_ptr<event::Channel> sig_;
api::CommandQueue api_queue_;
Expand Down
3 changes: 1 addition & 2 deletions src/load_tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,7 @@ if (BUILD_LOAD_TESTS)
${LIBOSTREE_LIBRARIES}
${LIBP11_LIBRARIES}
${SQLITE3_LIBRARIES}
${SYSTEMD_LIBRARY}
${LIBDPKG_LIBRARIES})
${SYSTEMD_LIBRARY})

install(TARGETS ota-load-tests
COMPONENT aktualizr
Expand Down
13 changes: 0 additions & 13 deletions thirdparty.spdx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ Relationship: SPDXRef-DOCUMENT DESCRIBES SPDXRef-sqlite3
Relationship: SPDXRef-DOCUMENT DESCRIBES SPDXRef-asn1c
Relationship: SPDXRef-DOCUMENT DESCRIBES SPDXRef-libp11
Relationship: SPDXRef-DOCUMENT DESCRIBES SPDXRef-systemd
Relationship: SPDXRef-DOCUMENT DESCRIBES SPDXRef-dpkg


PackageName: googletest
Expand Down Expand Up @@ -209,18 +208,6 @@ FilesAnalyzed: false
PackageComment: <text>Dynamically linked.</text>


PackageName: dpkg
SPDXID: SPDXRef-dpkg
PackageDownloadLocation: http://http.debian.net/debian/pool/main/d/dpkg/dpkg_1.19.0.5.tar.xz
PackageHomePage: https://packages.debian.org/source/sid/dpkg
PackageLicenseConcluded: GPL-2.0-or-later
PackageLicenseDeclared: GPL-2.0-or-later
PackageLicenseInfoFromFiles: GPL-2.0-or-later
PackageCopyrightText: <text>NONE</text>
FilesAnalyzed: false
PackageComment: <text>Dynamically linked.</text>


PackageName: systemd
SPDXID: SPDXRef-systemd
PackageDownloadLocation: https://github.com/systemd/systemd/archive/v238.tar.gz
Expand Down