diff --git a/CMakeLists.txt b/CMakeLists.txt index 644ef26..2afbc4a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -132,6 +132,7 @@ add_executable(owprov src/Daemon.cpp src/Daemon.h src/Dashboard.h src/Dashboard.cpp src/StorageService.cpp src/StorageService.h + src/storage/storage_entity.cpp src/storage/storage_entity.h src/storage/storage_policies.cpp src/storage/storage_policies.h src/storage/storage_venue.cpp src/storage/storage_venue.h @@ -141,6 +142,14 @@ add_executable(owprov src/storage/storage_management_roles.cpp src/storage/storage_management_roles.h src/storage/storage_configurations.cpp src/storage/storage_configurations.h src/storage/storage_tags.cpp src/storage/storage_tags.h + src/storage/storage_operataor.cpp src/storage/storage_operataor.h + src/storage/storage_sub_devices.cpp src/storage/storage_sub_devices.h + src/storage/storage_service_class.cpp src/storage/storage_service_class.h + src/storage/storage_maps.cpp src/storage/storage_maps.h + src/storage/storage_signup.cpp src/storage/storage_signup.h + src/storage/storage_variables.cpp src/storage/storage_variables.h + src/storage/storage_overrides.cpp src/storage/storage_overrides.h + src/RESTAPI/RESTAPI_entity_handler.cpp src/RESTAPI/RESTAPI_entity_handler.h src/RESTAPI/RESTAPI_contact_handler.cpp src/RESTAPI/RESTAPI_contact_handler.h src/RESTAPI/RESTAPI_location_handler.cpp src/RESTAPI/RESTAPI_location_handler.h @@ -160,6 +169,13 @@ add_executable(owprov src/RESTAPI/RESTAPI_iptocountry_handler.cpp src/RESTAPI/RESTAPI_iptocountry_handler.h src/RESTAPI/RESTAPI_signup_handler.h src/RESTAPI/RESTAPI_signup_handler.cpp src/RESTAPI/RESTAPI_asset_server.cpp src/RESTAPI/RESTAPI_asset_server.h + src/RESTAPI/RESTAPI_db_helpers.h + src/RESTAPI/RESTAPI_map_handler.cpp src/RESTAPI/RESTAPI_map_handler.h + src/RESTAPI/RESTAPI_map_list_handler.cpp src/RESTAPI/RESTAPI_map_list_handler.h + src/RESTAPI/RESTAPI_variables_handler.cpp src/RESTAPI/RESTAPI_variables_handler.h + src/RESTAPI/RESTAPI_variables_list_handler.cpp src/RESTAPI/RESTAPI_variables_list_handler.h + src/RESTAPI/RESTAPI_overrides_handler.cpp src/RESTAPI/RESTAPI_overrides_handler.h + src/FindCountry.h src/sdks/SDK_gw.cpp src/sdks/SDK_gw.h src/sdks/SDK_prov.cpp src/sdks/SDK_prov.h @@ -169,25 +185,14 @@ add_executable(owprov src/AutoDiscovery.cpp src/AutoDiscovery.h src/ConfigSanityChecker.cpp src/ConfigSanityChecker.h src/TagServer.cpp src/TagServer.h - src/RESTAPI/RESTAPI_db_helpers.h src/JobController.cpp src/JobController.h src/JobRegistrations.cpp - src/storage/storage_maps.cpp src/storage/storage_maps.h - src/RESTAPI/RESTAPI_map_handler.cpp src/RESTAPI/RESTAPI_map_handler.h - src/RESTAPI/RESTAPI_map_list_handler.cpp src/RESTAPI/RESTAPI_map_list_handler.h - src/storage/storage_signup.cpp src/storage/storage_signup.h src/Signup.cpp src/Signup.h src/DeviceTypeCache.h - src/storage/storage_variables.cpp src/storage/storage_variables.h - src/RESTAPI/RESTAPI_variables_handler.cpp src/RESTAPI/RESTAPI_variables_handler.h - src/RESTAPI/RESTAPI_variables_list_handler.cpp src/RESTAPI/RESTAPI_variables_list_handler.h src/FileDownloader.cpp src/FileDownloader.h src/Tasks/VenueConfigUpdater.h src/libs/croncpp.h src/Kafka_ProvUpdater.cpp src/Kafka_ProvUpdater.h - src/storage/storage_operataor.cpp src/storage/storage_operataor.h - src/storage/storage_sub_devices.cpp src/storage/storage_sub_devices.h - src/storage/storage_service_class.cpp src/storage/storage_service_class.h src/RESTAPI/RESTAPI_sub_devices_list_handler.cpp src/RESTAPI/RESTAPI_sub_devices_list_handler.h src/RESTAPI/RESTAPI_sub_devices_handler.cpp src/RESTAPI/RESTAPI_sub_devices_handler.h src/RESTAPI/RESTAPI_service_class_list_handler.cpp src/RESTAPI/RESTAPI_service_class_list_handler.h @@ -203,7 +208,7 @@ add_executable(owprov src/ProvWebSocketClient.cpp src/ProvWebSocketClient.h src/Tasks/VenueRebooter.h src/Tasks/VenueUpgrade.h src/sdks/SDK_fms.cpp src/sdks/SDK_fms.h - src/storage/storage_overrides.cpp src/storage/storage_overrides.h src/RESTAPI/RESTAPI_overrides_handler.cpp src/RESTAPI/RESTAPI_overrides_handler.h) + src/RESTAPI/RESTAPI_overrides_handler.cpp src/RESTAPI/RESTAPI_overrides_handler.h) target_link_libraries(owprov PUBLIC ${Poco_LIBRARIES} diff --git a/build b/build index 9d60796..3cacc0b 100644 --- a/build +++ b/build @@ -1 +1 @@ -11 \ No newline at end of file +12 \ No newline at end of file diff --git a/openapi/owprov.yaml b/openapi/owprov.yaml index 27ec82f..35cfc06 100644 --- a/openapi/owprov.yaml +++ b/openapi/owprov.yaml @@ -2525,6 +2525,17 @@ paths: type: boolean default: false required: false + - in: query + name: revisionsAvailable + schema: + type: boolean + default: false + required: false + - in: query + name: revision + schema: + type: string + required: false requestBody: description: Information used to modify the new venue content: diff --git a/src/RESTAPI/RESTAPI_db_helpers.h b/src/RESTAPI/RESTAPI_db_helpers.h index 6793d14..a5b3a5f 100644 --- a/src/RESTAPI/RESTAPI_db_helpers.h +++ b/src/RESTAPI/RESTAPI_db_helpers.h @@ -9,7 +9,6 @@ #include "framework/ConfigurationValidator.h" #include "sdks/SDK_sec.h" #include "Poco/StringTokenizer.h" - #include "libs/croncpp.h" namespace OpenWifi { diff --git a/src/RESTAPI/RESTAPI_venue_handler.cpp b/src/RESTAPI/RESTAPI_venue_handler.cpp index 15b89e4..5cc6d67 100644 --- a/src/RESTAPI/RESTAPI_venue_handler.cpp +++ b/src/RESTAPI/RESTAPI_venue_handler.cpp @@ -208,6 +208,52 @@ namespace OpenWifi{ InternalError(RESTAPI::Errors::RecordNotCreated); } + /* + * Get all the device types for the devices in the venue + * For each unique device type, get all the firmwares that apply for it + * create the intersection of all resulting firmwares + * create a list ordered in 3 types + * - Releases + * - RC of releases + * - Dev + * + * We obtain the revision by stripping and trimming the revision field previous to the "/" + * The sets should be built on the revision and the URI of the images, all per devicetype + */ + + enum class RevisionTypes { + release, + release_candidate, + development + }; + + RevisionTypes RevisionIdentify(const std::string &r) { + auto it = r.find_first_of('/'); + if(it==std::string::npos) { + return RevisionTypes::development; + } + ++it; + if(r.find("TIP-devel-", it)!=std::string::npos) { + return RevisionTypes::development; + } + if(r.find("-rc", it)!=std::string::npos) { + return RevisionTypes::release_candidate; + } + if(r.find("TIP-v", it)!=std::string::npos) { + return RevisionTypes::release; + } + return RevisionTypes::development; + } + + std::uint64_t RevisionDate(const std::string &R, const std::vector &F) { + + for(const auto &f:F) { + if(f.revision==R) + return f.imageDate; + } + return 0; + } + void RESTAPI_venue_handler::DoPut() { std::string UUID = GetBinding("uuid", ""); @@ -241,12 +287,92 @@ namespace OpenWifi{ } if(GetBoolParameter("upgradeAllDevices")) { + if(GetBoolParameter("revisionsAvailable")) { + std::set DeviceTypes; + for (const auto &serialNumber: Existing.devices) { + ProvObjects::InventoryTag Device; + if (StorageService()->InventoryDB().GetRecord("serialNumber", serialNumber, Device)) { + DeviceTypes.insert(Device.deviceType); + } + } + + // Get all the revisions for all the device types + using FirmwareList = std::vector; + using FirmwareRevisions = std::set; + + std::map AllFMs; + FirmwareRevisions AllRevisions; + bool first_pass = true; + for (const auto &device_type: DeviceTypes) { + FirmwareList list; + if (SDK::FMS::Firmware::GetDeviceTypeFirmwares(device_type, list)) { + AllFMs[device_type] = list; + FirmwareRevisions DeviceRevisions; + if (first_pass) { + for (const auto &revision: list) { + AllRevisions.insert(revision.revision); + } + } else { + FirmwareRevisions DeviceTypeRevisions; + for (const auto &revision: list) { + DeviceTypeRevisions.insert(revision.revision); + } + FirmwareRevisions NewRevisions; + std::set_intersection(AllRevisions.begin(), AllRevisions.end(), + DeviceTypeRevisions.begin(), DeviceTypeRevisions.end(), + std::inserter(NewRevisions, NewRevisions.begin())); + AllRevisions = NewRevisions; + } + } + first_pass = false; + } + + // OK we start the solution map with Our first device, and then we + Poco::JSON::Array Releases, ReleaseCandidates, DevelReleases; + for (const auto &revision: AllRevisions) { + auto Date = AllFMs.begin()->second.begin()->imageDate; + switch (RevisionIdentify(revision)) { + case RevisionTypes::release_candidate: { + Poco::JSON::Object E; + E.set("revision",revision); + E.set("date",Date); + ReleaseCandidates.add(E); + } + break; + case RevisionTypes::release: { + Poco::JSON::Object E; + E.set("revision",revision); + E.set("date",Date); + Releases.add(E); + } + break; + case RevisionTypes::development: + default: { + Poco::JSON::Object E; + E.set("revision",revision); + E.set("date",Date); + DevelReleases.add(E); + } + } + } + Poco::JSON::Object Answer; + Answer.set("releases", Releases); + Answer.set("releasesCandidates", ReleaseCandidates); + Answer.set("releases", DevelReleases); + return ReturnObject(Answer); + } + ProvObjects::SerialNumberList SNL; + auto Revision = GetParameter("revision",""); + if(Revision.empty()) { + return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters); + } + Poco::JSON::Object Answer; SNL.serialNumbers = Existing.devices; auto JobId = MicroServiceCreateUUID(); - Types::StringVec Parameters{UUID};; + Types::StringVec Parameters{UUID, Revision};; auto NewJob = new VenueUpgrade(JobId,"VenueFirmwareUpgrade", Parameters, 0, UserInfo_.userinfo, Logger()); JobController()->AddJob(dynamic_cast(NewJob)); SNL.to_json(Answer); diff --git a/src/Tasks/VenueUpgrade.h b/src/Tasks/VenueUpgrade.h index 9ff331b..9955b0d 100644 --- a/src/Tasks/VenueUpgrade.h +++ b/src/Tasks/VenueUpgrade.h @@ -15,9 +15,10 @@ namespace OpenWifi { class VenueDeviceUpgrade : public Poco::Runnable { public: - VenueDeviceUpgrade(const std::string &UUID, const std::string &venue, const ProvObjects::DeviceRules &Rules, Poco::Logger &L) : + VenueDeviceUpgrade(const std::string &UUID, const std::string &venue, const std::string &revision, const ProvObjects::DeviceRules &Rules, Poco::Logger &L) : uuid_(UUID), venue_(venue), + revision_(revision), rules_(Rules), Logger_(L) { } @@ -37,12 +38,12 @@ namespace OpenWifi { } FMSObjects::Firmware F; - if(SDK::FMS::Firmware::GetLatest(Device.deviceType,Device.deviceRules.rcOnly=="yes",F)) { + if(SDK::FMS::Firmware::GetFirmware(Device.deviceType,revision_,F)) { if (SDK::GW::Device::Upgrade(nullptr, Device.serialNumber, 0, F.uri)) { - Logger().debug(fmt::format("{}: Upgraded.",Device.serialNumber)); + Logger().debug(fmt::format("{}: Upgraded to {}.",Device.serialNumber, revision_)); upgraded_++; } else { - poco_information(Logger(),fmt::format("{}: Not Upgraded.", Device.serialNumber)); + poco_information(Logger(),fmt::format("{}: Not Upgraded to {}.", Device.serialNumber, revision_)); not_connected_++; } } else { @@ -65,6 +66,7 @@ namespace OpenWifi { private: std::string uuid_; std::string venue_; + std::string revision_; ProvObjects::DeviceRules rules_; Poco::Logger &Logger_; inline Poco::Logger & Logger() { return Logger_; } @@ -81,6 +83,7 @@ namespace OpenWifi { Utils::SetThreadName("venue-upgr"); auto VenueUUID_ = Parameter(0); + auto Revision_ = Parameter(1); ProvWebSocketNotifications::VenueFWUpgradeList_t N; @@ -101,7 +104,7 @@ namespace OpenWifi { StorageService()->VenueDB().EvaluateDeviceRules(Venue.info.id, Rules); for(const auto &uuid:Venue.devices) { - auto NewTask = new VenueDeviceUpgrade(uuid, Venue.info.name, Rules, Logger()); + auto NewTask = new VenueDeviceUpgrade(uuid, Venue.info.name, Revision_, Rules, Logger()); bool TaskAdded = false; while (!TaskAdded) { if (Pool_.available()) { diff --git a/src/framework/ConfigurationValidator.cpp b/src/framework/ConfigurationValidator.cpp index 36d8fd3..bf7618a 100644 --- a/src/framework/ConfigurationValidator.cpp +++ b/src/framework/ConfigurationValidator.cpp @@ -2922,6 +2922,24 @@ static std::string DefaultUCentralSchema = R"foo( } ] }, + "service.gps": { + "type": "object", + "properties": { + "adjust-time": { + "type": "boolean", + "default": false + }, + "baud-rate": { + "type": "integer", + "enum": [ + 2400, + 4800, + 9600, + 19200 + ] + } + } + }, "service": { "type": "object", "properties": { @@ -2978,6 +2996,9 @@ static std::string DefaultUCentralSchema = R"foo( }, "captive": { "$ref": "#/$defs/service.captive" + }, + "gps": { + "$ref": "#/$defs/service.gps" } } }, @@ -3070,6 +3091,31 @@ static std::string DefaultUCentralSchema = R"foo( } } }, + "metrics.telemetry": { + "type": "object", + "properties": { + "interval": { + "type": "integer" + }, + "types": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "metrics.realtime": { + "type": "object", + "properties": { + "types": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, "metrics": { "type": "object", "properties": { @@ -3084,6 +3130,12 @@ static std::string DefaultUCentralSchema = R"foo( }, "dhcp-snooping": { "$ref": "#/$defs/metrics.dhcp-snooping" + }, + "telemetry": { + "$ref": "#/$defs/metrics.telemetry" + }, + "realtime": { + "$ref": "#/$defs/metrics.realtime" } } }, @@ -3130,7 +3182,6 @@ static std::string DefaultUCentralSchema = R"foo( } } - )foo"; diff --git a/src/framework/orm.h b/src/framework/orm.h index 347b1ad..23eb591 100644 --- a/src/framework/orm.h +++ b/src/framework/orm.h @@ -561,6 +561,21 @@ namespace ORM { return false; } + template bool Join(const std::string &statement, std::vector &records) { + try { + Poco::Data::Session Session = Pool_.get(); + Poco::Data::Statement Select(Session); + + Select << statement , + Poco::Data::Keywords::into(records); + Select.execute(); + return true; + } catch (const Poco::Exception &E) { + Logger_.log(E); + } + return false; + } + typedef std::vector RecordList; typedef std::vector RecordVec; typedef RecordType RecordName; diff --git a/src/framework/ow_constants.h b/src/framework/ow_constants.h index cc9146a..060873d 100644 --- a/src/framework/ow_constants.h +++ b/src/framework/ow_constants.h @@ -251,6 +251,7 @@ namespace OpenWifi::RESTAPI::Errors { static const struct msg CertificateTransferEntityNoLongerExists{1167,"The entity tied to this transfer no longer seems to exist."}; static const struct msg CannotRollBackDueToDigiCert{1168,"The change could not be rolled back at this time. Please try later."}; static const struct msg CertificateTransferAlreadyRolledBack{1169,"The certificate has already been rolled back."}; + static const struct msg FirmwareBDInProgress{1170,"Firmware DB update already in progress."}; } diff --git a/src/sdks/SDK_fms.cpp b/src/sdks/SDK_fms.cpp index f97c51a..01d54b3 100644 --- a/src/sdks/SDK_fms.cpp +++ b/src/sdks/SDK_fms.cpp @@ -32,6 +32,43 @@ namespace OpenWifi::SDK::FMS { return false; } + bool GetDeviceTypeFirmwares(const std::string &device_type, std::vector & FirmWares) { + static const std::string EndPoint{"/api/v1/firmwares"}; + + OpenWifi::OpenAPIRequestGet API( uSERVICE_FIRMWARE, + EndPoint, + { + { "deviceType", device_type} + }, + 50000); + + auto CallResponse = Poco::makeShared(); + auto StatusCode = API.Do(CallResponse); + if( StatusCode == Poco::Net::HTTPResponse::HTTP_OK) { + Poco::JSON::Array::Ptr FirmwareArr = CallResponse->getArray("firmwares"); + for(uint64_t i=0;isize();i++) { + FMSObjects::Firmware F; + F.from_json(FirmwareArr->getObject(i)); + FirmWares.emplace_back(F); + } + return true; + } + return false; + } + + bool GetFirmware(const std::string &device_type, const std::string & revision, FMSObjects::Firmware & Firmware) { + std::vector Firmwares; + if(GetDeviceTypeFirmwares(device_type,Firmwares)) { + for(const auto &firmware:Firmwares) { + if(firmware.revision==revision) { + Firmware = firmware; + return true; + } + } + } + return false; + } + } }; diff --git a/src/sdks/SDK_fms.h b/src/sdks/SDK_fms.h index c299b51..6ac3263 100644 --- a/src/sdks/SDK_fms.h +++ b/src/sdks/SDK_fms.h @@ -10,6 +10,8 @@ namespace OpenWifi::SDK::FMS { namespace Firmware { bool GetLatest(const std::string &device_type, bool RCOnly, FMSObjects::Firmware & FirmWare); + bool GetDeviceTypeFirmwares(const std::string &device_type, std::vector & FirmWares); + bool GetFirmware(const std::string &device_type, const std::string & revision, FMSObjects::Firmware & FirmWare); } };