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

Commit

Permalink
OTA-2536: Preconfigure IpUptaneSecondary with IP address
Browse files Browse the repository at this point in the history
Signed-off-by: Mike Sul <[email protected]>
  • Loading branch information
Mike Sul committed Apr 17, 2019
1 parent 99bfcf9 commit 87325ea
Show file tree
Hide file tree
Showing 19 changed files with 391 additions and 47 deletions.
12 changes: 9 additions & 3 deletions src/aktualizr_primary/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
add_executable(aktualizr main.cc)
target_link_libraries(aktualizr aktualizr_static_lib ${AKTUALIZR_EXTERNAL_LIBS})
set(TARGET aktualizr)
set(SOURCES main.cc secondary_config.h secondary_config.cc secondary.h secondary.cc)

aktualizr_source_file_checks(main.cc)
add_executable(${TARGET} ${SOURCES})
target_link_libraries(${TARGET} aktualizr_static_lib aktualizr-posix ${AKTUALIZR_EXTERNAL_LIBS})
target_include_directories(${TARGET} PUBLIC
${PROJECT_SOURCE_DIR}/src/libaktualizr-posix
${PROJECT_SOURCE_DIR}/third_party)

aktualizr_source_file_checks(${SOURCES})

install(TARGETS aktualizr RUNTIME DESTINATION bin COMPONENT aktualizr)

Expand Down
7 changes: 7 additions & 0 deletions src/aktualizr_primary/main.cc
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include "config/config.h"
#include "logging/logging.h"
#include "primary/aktualizr.h"
#include "secondary.h"
#include "utilities/utils.h"

namespace bpo = boost::program_options;
Expand Down Expand Up @@ -42,6 +43,7 @@ bpo::variables_map parse_options(int argc, char *argv[]) {
("primary-ecu-serial", bpo::value<std::string>(), "serial number of primary ecu")
("primary-ecu-hardware-id", bpo::value<std::string>(), "hardware ID of primary ecu")
("secondary-configs-dir", bpo::value<boost::filesystem::path>(), "directory containing secondary ECU configuration files")
("secondary-config-file", bpo::value<boost::filesystem::path>(), "secondary ECUs configuration file")
("campaign-id", bpo::value<std::string>(), "id of the campaign to act on");
// clang-format on

Expand Down Expand Up @@ -120,6 +122,11 @@ int main(int argc, char *argv[]) {
boost::signals2::scoped_connection conn;

conn = aktualizr.SetSignalHandler(f_cb);

if (!config.uptane.secondary_config_file.empty()) {
Primary::initSecondaries(aktualizr, config.uptane.secondary_config_file);
}

aktualizr.Initialize();

std::string run_mode;
Expand Down
51 changes: 51 additions & 0 deletions src/aktualizr_primary/secondary.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
#include <unordered_map>

#include "secondary.h"
#include "secondary_config.h"

#include "ipuptanesecondary.h"

namespace Primary {

using SecondaryFactoryRegistry =
std::unordered_map<std::string, std::function<std::shared_ptr<Uptane::SecondaryInterface>(const SecondaryConfig&)>>;

static SecondaryFactoryRegistry sec_factory_regisrty = {
{IPSecondaryConfig::Type,
[](const SecondaryConfig& config) {
auto ip_sec_cgf = dynamic_cast<const IPSecondaryConfig&>(config);
return Uptane::IpUptaneSecondary::create(ip_sec_cgf.ip, ip_sec_cgf.port);
}},
// {
// Add another secondary factory here
// }
};

static std::shared_ptr<Uptane::SecondaryInterface> createSecondary(const SecondaryConfig& config) {
return (sec_factory_regisrty.at(config.type()))(config);
}

void initSecondaries(Aktualizr& aktualizr, const boost::filesystem::path& config_file) {
if (!boost::filesystem::exists(config_file)) {
throw std::invalid_argument("Secondary ECUs config file does not exist: " + config_file.string());
}

auto secondary_configs = SecondaryConfigParser::parse_config_file(config_file);

for (auto& config : secondary_configs) {
try {
LOG_INFO << "Creating Secondary of type: " << config->type() << "...\n";
std::shared_ptr<Uptane::SecondaryInterface> secondary = createSecondary(*config);

LOG_INFO << "Adding Secondary to Aktualizr."
<< "HW_ID: " << secondary->getHwId() << " Serial: " << secondary->getSerial() << "\n";
aktualizr.AddSecondary(secondary);

} catch (const std::exception& exc) {
LOG_ERROR << "Failed to initialize a secondary: " << exc.what();
LOG_ERROR << "Continue with initialization of the remaining secondaries, if any left.\n";
// otherwise rethrow the exception
}
}
}
} // namespace Primary
14 changes: 14 additions & 0 deletions src/aktualizr_primary/secondary.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#ifndef SECONDARY_H_
#define SECONDARY_H_

#include <boost/filesystem.hpp>

#include "primary/aktualizr.h"

namespace Primary {

void initSecondaries(Aktualizr& aktualizr, const boost::filesystem::path& config_file);

} // namespace Primary

#endif // SECONDARY_H_
89 changes: 89 additions & 0 deletions src/aktualizr_primary/secondary_config.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
#include <fstream>
#include <iostream>
#include <unordered_map>

#include "logging/logging.h"
#include "secondary_config.h"

namespace Primary {

SecondaryConfigParser::Configs SecondaryConfigParser::parse_config_file(const boost::filesystem::path& config_file) {
if (!boost::filesystem::exists(config_file)) {
throw std::invalid_argument("Specified config file doesn't exist: " + config_file.string());
}

auto cfg_file_ext = boost::filesystem::extension(config_file);
std::shared_ptr<SecondaryConfigParser> cfg_parser;

if (cfg_file_ext == ".json") {
cfg_parser = std::make_shared<JsonConfigParser>(config_file);
} else { // add your format of configuration file + implement SecondaryConfigParser specialization
throw std::invalid_argument("Unsupported type of config format: " + cfg_file_ext);
}

return cfg_parser->parse();
}

/*
config file example
{
"ip": [
{"addr": "127.0.0.1:9031"},
{"addr": "127.0.0.1:9032"}
],
"socketcan": [
{"key": "value", "key1": "value1"},
{"key": "value", "key1": "value1"}
]
}
*/

JsonConfigParser::JsonConfigParser(const boost::filesystem::path& config_file) {
assert(boost::filesystem::exists(config_file));
std::ifstream json_file_stream(config_file.string());
Json::Reader json_reader;

if (!json_reader.parse(json_file_stream, root_, false)) {
throw std::invalid_argument("Failed to parse secondary config file: " + config_file.string() + ": " +
json_reader.getFormattedErrorMessages());
}
}

SecondaryConfigParser::Configs JsonConfigParser::parse() {
Configs res_sec_cfg;

for (Json::ValueIterator it = root_.begin(); it != root_.end(); ++it) {
std::string secondary_type = it.key().asString();

if (sec_cfg_factory_regisrty_.find(secondary_type) == sec_cfg_factory_regisrty_.end()) {
LOG_ERROR << "Unsupported type of sescondary config was found: `" << secondary_type
<< "`. Ingoring it and continue with parsing of other secondary configs";
} else {
(sec_cfg_factory_regisrty_.at(secondary_type))(res_sec_cfg, *it);
}
}

return res_sec_cfg;
}

static std::pair<std::string, uint16_t> getIPAndPort(const std::string& addr) {
auto del_pos = addr.find_first_of(':');
if (del_pos == std::string::npos) {
throw std::invalid_argument("Incorrect address string, couldn't find port delimeter: " + addr);
}
std::string ip = addr.substr(0, del_pos);
uint16_t port = static_cast<uint16_t>(std::stoul(addr.substr(del_pos + 1)));

return std::make_pair(ip, port);
}

void JsonConfigParser::createIPSecondaryConfig(Configs& configs, Json::Value& ip_sec_cfgs) {
for (const auto& ip_sec_cfg : ip_sec_cfgs) {
auto addr = getIPAndPort(ip_sec_cfg[IPSecondaryConfig::AddrField].asString());
configs.emplace_back(std::make_shared<IPSecondaryConfig>(addr.first, addr.second));
}
}

} // namespace Primary
67 changes: 67 additions & 0 deletions src/aktualizr_primary/secondary_config.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
#ifndef SECONDARY_CONFIG_H_
#define SECONDARY_CONFIG_H_

#include <json/json.h>
#include <boost/filesystem.hpp>
#include <unordered_map>

namespace Primary {

class SecondaryConfig {
public:
SecondaryConfig(const char* type) : type_(type) {}
virtual const char* type() const { return type_; }
virtual ~SecondaryConfig() = default;

private:
const char* const type_;
};

class IPSecondaryConfig : public SecondaryConfig {
public:
static constexpr const char* Type{"ip"};
static constexpr const char* AddrField{"addr"};

IPSecondaryConfig(std::string addr_ip, uint16_t addr_port)
: SecondaryConfig(Type), ip(std::move(addr_ip)), port(addr_port) {}

public:
const std::string ip;
const uint16_t port;
};

class SecondaryConfigParser {
public:
using Configs = std::vector<std::shared_ptr<SecondaryConfig>>;

static Configs parse_config_file(const boost::filesystem::path& config_file);
virtual ~SecondaryConfigParser() = default;

// TODO implement iterator instead of parse
virtual Configs parse() = 0;
};

class JsonConfigParser : public SecondaryConfigParser {
public:
JsonConfigParser(const boost::filesystem::path& config_file);

Configs parse() override;

private:
static void createIPSecondaryConfig(Configs& configs, Json::Value& ip_sec_cfgs);
// add here a factory method for another type of secondary config

private:
using SecondaryConfigFactoryRegistry = std::unordered_map<std::string, std::function<void(Configs&, Json::Value&)>>;

SecondaryConfigFactoryRegistry sec_cfg_factory_regisrty_ = {
{IPSecondaryConfig::Type, createIPSecondaryConfig}
// add here factory method for another type of secondary config
};

Json::Value root_;
};

} // namespace Primary

#endif // SECONDARY_CONFIG_H_
24 changes: 14 additions & 10 deletions src/aktualizr_secondary/aktualizr_secondary.cc
Original file line number Diff line number Diff line change
Expand Up @@ -120,16 +120,20 @@ bool AktualizrSecondary::sendFirmwareResp(const std::shared_ptr<std::string>& fi
}

std::string treehub_server;
try {
std::string ca, cert, pkey, server_url;
extractCredentialsArchive(*firmware, &ca, &cert, &pkey, &treehub_server);
keys_.loadKeys(&ca, &cert, &pkey);
boost::trim(server_url);
treehub_server = server_url;
} catch (std::runtime_error& exc) {
LOG_ERROR << exc.what();

return false;
if (target_->IsOstree()) {
// this is the ostree specific case
try {
std::string ca, cert, pkey, server_url;
extractCredentialsArchive(*firmware, &ca, &cert, &pkey, &treehub_server);
keys_.loadKeys(&ca, &cert, &pkey);
boost::trim(server_url);
treehub_server = server_url;
} catch (std::runtime_error& exc) {
LOG_ERROR << exc.what();

return false;
}
}

data::InstallationResult install_res;
Expand All @@ -147,7 +151,7 @@ bool AktualizrSecondary::sendFirmwareResp(const std::shared_ptr<std::string>& fi
LOG_ERROR << "Could not pull from OSTree. Aktualizr was built without OSTree support!";
return false;
#endif
} else {
} else if (pacman->name() == "debian") {
// TODO save debian package here.
LOG_ERROR << "Installation of non ostree images is not suppotrted yet.";
return false;
Expand Down
1 change: 1 addition & 0 deletions src/aktualizr_secondary/aktualizr_secondary_common.cc
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ bool AktualizrSecondaryCommon::uptaneInitialize() {
if (storage_->loadEcuSerials(&ecu_serials)) {
ecu_serial_ = ecu_serials[0].first;
hardware_id_ = ecu_serials[0].second;

return true;
}

Expand Down
9 changes: 9 additions & 0 deletions src/aktualizr_secondary/socket_server.cc
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,15 @@ void SocketServer::HandleOneConnection(int socket) {
// Figure out what to do with the message
Asn1Message::Ptr resp = Asn1Message::Empty();
switch (msg->present()) {
case AKIpUptaneMes_PR_getInfoReq: {
std::cout << ">>>>>>>>>>>> Got Info request";
Uptane::EcuSerial serial = impl_->getSerial();
Uptane::HardwareIdentifier hw_id = impl_->getHwId();
resp->present(AKIpUptaneMes_PR_getInfoResp);
auto r = resp->getInfoResp();
SetString(&r->ecuSerial, serial.ToString());
SetString(&r->hwId, hw_id.ToString());
} break;
case AKIpUptaneMes_PR_publicKeyReq: {
PublicKey pk = impl_->getPublicKey();
resp->present(AKIpUptaneMes_PR_publicKeyResp);
Expand Down
11 changes: 7 additions & 4 deletions src/libaktualizr-posix/asn1/asn1_message.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include "utilities/sockaddr_io.h"
#include "utilities/utils.h"

#include <arpa/inet.h>
#include <netinet/tcp.h>

#ifndef MSG_NOSIGNAL
Expand Down Expand Up @@ -53,14 +54,16 @@ void SetString(OCTET_STRING_t* dest, const std::string& str) {
OCTET_STRING_fromBuf(dest, str.c_str(), static_cast<int>(str.size()));
}

Asn1Message::Ptr Asn1Rpc(const Asn1Message::Ptr& tx, const struct sockaddr_storage& client) {
int socket_fd = socket(AF_INET6, SOCK_STREAM, 0);
Asn1Message::Ptr Asn1Rpc(const Asn1Message::Ptr& tx, const struct sockaddr_in& server_sock_addr) {
int socket_fd = socket(AF_INET, SOCK_STREAM, 0);
if (socket_fd < 0) {
throw std::system_error(errno, std::system_category(), "socket");
}
// what's the point in usage of SocketHandle
SocketHandle hdl(new int(socket_fd));
if (connect(*hdl, reinterpret_cast<const struct sockaddr*>(&client), sizeof(sockaddr_in6)) < 0) {
LOG_ERROR << "connect to " << client << " failed:" << std::strerror(errno);

if (connect(*hdl, reinterpret_cast<const struct sockaddr*>(&server_sock_addr), sizeof(server_sock_addr)) < 0) {
LOG_ERROR << "connect to client failed:" << std::strerror(errno);
return Asn1Message::Empty();
}
der_encode(&asn_DEF_AKIpUptaneMes, &tx->msg_, Asn1SocketWriteCallback, hdl.get());
Expand Down
6 changes: 4 additions & 2 deletions src/libaktualizr-posix/asn1/asn1_message.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ class Asn1Message {
return Asn1Sub<MessageType>(this, &msg_.choice.FieldName); /* NOLINT(cppcoreguidelines-pro-type-union-access) */ \
}

ASN1_MESSAGE_DEFINE_ACCESSOR(AKGetInfoReqMes_t, getInfoReq);
ASN1_MESSAGE_DEFINE_ACCESSOR(AKGetInfoRespMes_t, getInfoResp);
ASN1_MESSAGE_DEFINE_ACCESSOR(AKDiscoveryReqMes_t, discoveryReq);
ASN1_MESSAGE_DEFINE_ACCESSOR(AKDiscoveryRespMes_t, discoveryResp);
ASN1_MESSAGE_DEFINE_ACCESSOR(AKPublicKeyReqMes_t, publicKeyReq);
Expand Down Expand Up @@ -122,5 +124,5 @@ void SetString(OCTET_STRING_t* dest, const std::string& str);
* Open a TCP connection to client; send a message and wait for a
* response.
*/
Asn1Message::Ptr Asn1Rpc(const Asn1Message::Ptr& tx, const struct sockaddr_storage& client);
#endif // ASN1_MESSAGE_H_
Asn1Message::Ptr Asn1Rpc(const Asn1Message::Ptr& tx, const struct sockaddr_in& server_sock_addr);
#endif // ASN1_MESSAGE_H_
Loading

0 comments on commit 87325ea

Please sign in to comment.