diff --git a/owprov.properties b/owprov.properties index 58d5f5f..1573b7d 100644 --- a/owprov.properties +++ b/owprov.properties @@ -49,7 +49,7 @@ alb.port = 16104 # ucentral.kafka.group.id = prov ucentral.kafka.client.id = prov1 -ucentral.kafka.enable = true +ucentral.kafka.enable = false ucentral.kafka.brokerlist = a1.arilia.com:9092 # ucentral.kafka.brokerlist = debfarm1-node-c.arilia.com:9092 ucentral.kafka.auto.commit = false diff --git a/src/Daemon.cpp b/src/Daemon.cpp index 30c04e0..df985f1 100644 --- a/src/Daemon.cpp +++ b/src/Daemon.cpp @@ -30,7 +30,7 @@ namespace uCentral { vDAEMON_APP_NAME, vDAEMON_BUS_TIMER, Types::SubSystemVec{ - Storage(), + OpenWifi::Storage(), AuthClient(), RESTAPI_server(), RESTAPI_InternalServer() diff --git a/src/RESTAPI_entity_handler.cpp b/src/RESTAPI_entity_handler.cpp index 3c362e3..0941c94 100644 --- a/src/RESTAPI_entity_handler.cpp +++ b/src/RESTAPI_entity_handler.cpp @@ -3,9 +3,14 @@ // #include "RESTAPI_entity_handler.h" +#include "RESTAPI_ProvObjects.h" +#include "StorageService.h" +#include "Poco/JSON/Parser.h" +#include "Daemon.h" namespace OpenWifi{ + void RESTAPI_entity_handler::handleRequest(Poco::Net::HTTPServerRequest &Request, Poco::Net::HTTPServerResponse &Response) { if (!ContinueProcessing(Request, Response)) @@ -28,13 +33,106 @@ namespace OpenWifi{ } void RESTAPI_entity_handler::DoGet(Poco::Net::HTTPServerRequest &Request, - Poco::Net::HTTPServerResponse &Response) {} + Poco::Net::HTTPServerResponse &Response) { + try { + std::string UUID = GetBinding("uuid", ""); + + if(UUID.empty()) { + BadRequest(Request, Response, "Missing UUID"); + return; + } + + ProvObjects::Entity E; + if(Storage()->EntityDB().GetRecord("id",UUID,E)) { + Poco::JSON::Object Answer; + E.to_json(Answer); + ReturnObject(Request,Answer,Response); + return; + } + NotFound(Request,Response); + return; + } catch (const Poco::Exception &E) { + Logger_.log(E); + } + BadRequest(Request, Response); + } void RESTAPI_entity_handler::DoDelete(Poco::Net::HTTPServerRequest &Request, - Poco::Net::HTTPServerResponse &Response) {} + Poco::Net::HTTPServerResponse &Response) { + try { + std::string UUID = GetBinding("uuid", ""); + + if(UUID.empty()) { + BadRequest(Request, Response, "Missing UUID"); + return; + } + + if(UUID == EntityDB::RootUUID()) { + BadRequest(Request, Response, "Root Entity cannot be removed, only modified"); + return; + } + + ProvObjects::Entity E; + if(Storage()->EntityDB().DeleteRecord("id",UUID)) { + OK(Request, Response); + return; + } + NotFound(Request,Response); + return; + } catch (const Poco::Exception &E) { + Logger_.log(E); + } + BadRequest(Request, Response); + } void RESTAPI_entity_handler::DoPost(Poco::Net::HTTPServerRequest &Request, - Poco::Net::HTTPServerResponse &Response) {} + Poco::Net::HTTPServerResponse &Response) { + try { + std::string UUID = GetBinding("uuid", ""); + + if(UUID.empty()) { + BadRequest(Request, Response, "Missing UUID"); + return; + } + + if(!Storage()->EntityDB().RootExists() && UUID != EntityDB::RootUUID()) { + BadRequest(Request, Response, "Root entity must be created first."); + return; + } + + Poco::JSON::Parser IncomingParser; + Poco::JSON::Object::Ptr Obj = IncomingParser.parse(Request.stream()).extract(); + ProvObjects::Entity E; + if (!E.from_json(Obj)) { + BadRequest(Request, Response); + return; + } + + // When creating an entity, it cannot have any relations other that parent, notes, name, description. Everything else + // must be conveyed through PUT. + E.info.id = (UUID==EntityDB::RootUUID()) ? UUID : uCentral::Daemon()->CreateUUID() ; + if(UUID==EntityDB::RootUUID()) + E.parent=""; + E.venues.clear(); + E.children.clear(); + E.managers.clear(); + E.contacts.clear(); + E.locations.clear(); + + + if(Storage()->EntityDB().CreateRecord(E)) { + if(UUID==EntityDB::RootUUID()) + Storage()->EntityDB().CheckForRoot(); + OK(Request, Response); + return; + } + NotFound(Request,Response); + return; + } catch (const Poco::Exception &E) { + Logger_.log(E); + } + BadRequest(Request, Response); + } void RESTAPI_entity_handler::DoPut(Poco::Net::HTTPServerRequest &Request, Poco::Net::HTTPServerResponse &Response) {} diff --git a/src/StorageService.cpp b/src/StorageService.cpp index 60bd3f9..aabde0e 100644 --- a/src/StorageService.cpp +++ b/src/StorageService.cpp @@ -12,7 +12,7 @@ #include "Daemon.h" #include "Utils.h" -namespace uCentral { +namespace OpenWifi { class Storage *Storage::instance_ = nullptr; @@ -26,7 +26,7 @@ namespace uCentral { Logger_.setLevel(Poco::Message::PRIO_NOTICE); Logger_.notice("Starting."); - std::string DBType = Daemon()->ConfigGetString("storage.type"); + std::string DBType = uCentral::Daemon()->ConfigGetString("storage.type"); if (DBType == "sqlite") { DBType_ = ORM::DBType::sqlite; diff --git a/src/StorageService.h b/src/StorageService.h index 0150fcc..e9f2c41 100644 --- a/src/StorageService.h +++ b/src/StorageService.h @@ -26,9 +26,9 @@ #include "storage_contact.h" #include "storage_inventory.h" -namespace uCentral { +namespace OpenWifi { - class Storage : public SubSystemServer { + class Storage : public uCentral::SubSystemServer { public: static Storage *instance() { if (instance_ == nullptr) { diff --git a/src/orm.h b/src/orm.h index 6d87e01..2866d50 100644 --- a/src/orm.h +++ b/src/orm.h @@ -1,6 +1,7 @@ #ifndef __OPENWIFI_ORM_H__ #define __OPENWIFI_ORM_H__ + #include #include #include @@ -307,15 +308,14 @@ namespace ORM { Poco::Data::Statement Insert(Session); RecordTuple RT; - ConvertParams(R, RT); - + Convert(R, RT); std::string St = "insert into " + DBName + " ( " + SelectFields_ + " ) values " + SelectList_; Insert << ConvertParams(St) , - Poco::Data::Keywords::use(RT), + Poco::Data::Keywords::use(RT); Insert.execute(); return true; } catch (const Poco::Exception &E) { - // Logger_.log(E); + Logger_.log(E); } return false; } @@ -324,18 +324,20 @@ namespace ORM { try { Poco::Data::Session Session = Pool_.get(); Poco::Data::Statement Select(Session); - RecordTuple RT; + RecordTuple RT; std::string St = "select " + SelectFields_ + " from " + DBName + " where " + FieldName + "=?" ; + Select << ConvertParams(St) , Poco::Data::Keywords::into(RT), Poco::Data::Keywords::use(Value); - Select.execute(); - - Convert(RT,R); - return true; + if(Select.execute()==1) { + Convert(RT,R); + return true; + } + return false; } catch (const Poco::Exception &E) { - // Logger_.log(E); + Logger_.log(E); } return false; } @@ -355,12 +357,14 @@ namespace ORM { Poco::Data::Keywords::into(RT), Poco::Data::Keywords::use(V0), Poco::Data::Keywords::use(V1); - Select.execute(); - Convert(RT,R); + if(Select.execute()==1) { + Convert(RT,R); + return true; + } return true; } catch (const Poco::Exception &E) { - // Logger_.log(E); + Logger_.log(E); } return false; } @@ -376,16 +380,18 @@ namespace ORM { Select << ConvertParams(St) , Poco::Data::Keywords::into(RL); - Select.execute(); - for(const auto &i:RL) { - RecordType R; - Convert(i, R); - Records.template emplace_back(R); + if(Select.execute()>0) { + for(const auto &i:RL) { + RecordType R; + Convert(i, R); + Records.template emplace_back(R); + } + return true; } - return true; + return false; } catch (const Poco::Exception &E) { - // Logger_.log(E); + Logger_.log(E); } return false; } @@ -406,7 +412,7 @@ namespace ORM { Update.execute(); return true; } catch (const Poco::Exception &E) { - // Logger_.log(E); + Logger_.log(E); } return false; } @@ -422,7 +428,7 @@ namespace ORM { Delete.execute(); return true; } catch (const Poco::Exception &E) { - // Logger_.log(E); + Logger_.log(E); } return false; } @@ -438,7 +444,7 @@ namespace ORM { Delete.execute(); return true; } catch (const Poco::Exception &E) { - // Logger_.log(E); + Logger_.log(E); } return false; } @@ -469,46 +475,4 @@ namespace ORM { }; } -/* -int main(int, char**) -{ - auto SQLiteConn_ = std::make_unique(); - SQLiteConn_->registerConnector(); - auto Pool_ = std::make_unique(SQLiteConn_->name(), "test.db", 4, 64, 60); - - ORM::FieldVec DB1Fields{ ORM::Field{"id",40, true}, - ORM::Field{"name", ORM::FT_INT} }; - ORM::IndexVec Indexes{ - { std::string("name_index"), ORM::IndexEntryVec{ {std::string("name"), ORM::Indextype::ASC} } } }; - - ORM::DB DB1(ORM::sqlite , - "tab1", - ORM::FieldVec{ - ORM::Field{"id",40, true}, - ORM::Field{"name", ORM::FT_INT} }, - ORM::IndexVec{{ std::string("name_index"), ORM::IndexEntryVec{ {std::string("name"), ORM::Indextype::ASC} } }}, - *Pool_); - - std::cout << DB1.CreateFields() << std::endl; - std::cout << DB1.SelectFields() << std::endl; - std::cout << DB1.SelectList() << std::endl; - std::cout << DB1.UpdateFields() << std::endl; - - std::cout << DB1.Create() << std::endl; - - User U1{ 25, "steph"}; - - auto SS = &User::Name; - - std::cout << (typeid( User::Name ) == typeid( std::string )) << std::endl; - std::cout << "Name: " << U1.*SS << std::endl; - - auto RR = ORM::Escape("I'm a \"cool\" dude"); - std::cout << "RR: " << RR << std::endl; - - return 0; -} - - */ - #endif \ No newline at end of file diff --git a/src/storage_entity.cpp b/src/storage_entity.cpp index 11cb745..3ea2cd7 100644 --- a/src/storage_entity.cpp +++ b/src/storage_entity.cpp @@ -35,7 +35,19 @@ namespace OpenWifi { }; EntityDB::EntityDB( ORM::DBType T, Poco::Data::SessionPool & P, Poco::Logger &L) : - DB(T, "entities", EntityDB_Fields, EntityDB_Indexes, P, L) {} + DB(T, "entities", EntityDB_Fields, EntityDB_Indexes, P, L) { + + CheckForRoot(); + std::cout << "RootExists:" << RootExists_ << std::endl; + } + + inline bool EntityDB::CheckForRoot() { + ProvObjects::Entity E; + if(GetRecord("id",RootUUID(),E)) + RootExists_=true; + + return RootExists_; + } } diff --git a/src/storage_entity.h b/src/storage_entity.h index 606029e..7683e35 100644 --- a/src/storage_entity.h +++ b/src/storage_entity.h @@ -10,20 +10,6 @@ namespace OpenWifi { - /* - ORM::Field{"id",64, true}, - ORM::Field{"name",ORM::FieldType::FT_TEXT}, - ORM::Field{"description",ORM::FieldType::FT_TEXT}, - ORM::Field{"notes",ORM::FieldType::FT_TEXT}, - ORM::Field{"created",ORM::FieldType::FT_BIGINT}, - ORM::Field{"modified",ORM::FieldType::FT_BIGINT}, - ORM::Field{"parent",ORM::FieldType::FT_TEXT}, - ORM::Field{"children",ORM::FieldType::FT_TEXT}, - ORM::Field{"managers",ORM::FieldType::FT_TEXT}, - ORM::Field{"contacts",ORM::FieldType::FT_TEXT}, - ORM::Field{"locations",ORM::FieldType::FT_TEXT}, - ORM::Field{"managementPolicy",ORM::FieldType::FT_TEXT} - */ typedef Poco::Tuple< std::string, std::string, @@ -43,7 +29,11 @@ namespace OpenWifi { class EntityDB : public ORM::DB { public: EntityDB( ORM::DBType T, Poco::Data::SessionPool & P, Poco::Logger &L); + inline bool RootExists() const { return RootExists_; }; + static inline const std::string RootUUID() { return "0000-0000-0000"; } + bool CheckForRoot(); private: + bool RootExists_=false; }; } diff --git a/src/storage_mysql.cpp b/src/storage_mysql.cpp index bd07927..93f71d0 100644 --- a/src/storage_mysql.cpp +++ b/src/storage_mysql.cpp @@ -9,7 +9,7 @@ #include "Daemon.h" #include "StorageService.h" -namespace uCentral { +namespace OpenWifi { #ifdef SMALL_BUILD int Service::Setup_MySQL() { uCentral::instance()->exit(Poco::Util::Application::EXIT_CONFIG);} @@ -18,13 +18,13 @@ namespace uCentral { int Storage::Setup_MySQL() { Logger_.notice("MySQL Storage enabled."); - auto NumSessions = Daemon()->ConfigGetInt("storage.type.mysql.maxsessions", 64); - auto IdleTime = Daemon()->ConfigGetInt("storage.type.mysql.idletime", 60); - auto Host = Daemon()->ConfigGetString("storage.type.mysql.host"); - auto Username = Daemon()->ConfigGetString("storage.type.mysql.username"); - auto Password = Daemon()->ConfigGetString("storage.type.mysql.password"); - auto Database = Daemon()->ConfigGetString("storage.type.mysql.database"); - auto Port = Daemon()->ConfigGetString("storage.type.mysql.port"); + auto NumSessions = uCentral::Daemon()->ConfigGetInt("storage.type.mysql.maxsessions", 64); + auto IdleTime = uCentral::Daemon()->ConfigGetInt("storage.type.mysql.idletime", 60); + auto Host = uCentral::Daemon()->ConfigGetString("storage.type.mysql.host"); + auto Username = uCentral::Daemon()->ConfigGetString("storage.type.mysql.username"); + auto Password = uCentral::Daemon()->ConfigGetString("storage.type.mysql.password"); + auto Database = uCentral::Daemon()->ConfigGetString("storage.type.mysql.database"); + auto Port = uCentral::Daemon()->ConfigGetString("storage.type.mysql.port"); std::string ConnectionStr = "host=" + Host + diff --git a/src/storage_pgql.cpp b/src/storage_pgql.cpp index 8a813f7..0b6ad66 100644 --- a/src/storage_pgql.cpp +++ b/src/storage_pgql.cpp @@ -9,7 +9,7 @@ #include "Daemon.h" #include "StorageService.h" -namespace uCentral { +namespace OpenWifi { #ifdef SMALL_BUILD int Service::Setup_PostgreSQL() { uCentral::instance()->exit(Poco::Util::Application::EXIT_CONFIG);} @@ -17,14 +17,14 @@ namespace uCentral { int Storage::Setup_PostgreSQL() { Logger_.notice("PostgreSQL Storage enabled."); - auto NumSessions = Daemon()->ConfigGetInt("storage.type.postgresql.maxsessions", 64); - auto IdleTime = Daemon()->ConfigGetInt("storage.type.postgresql.idletime", 60); - auto Host = Daemon()->ConfigGetString("storage.type.postgresql.host"); - auto Username = Daemon()->ConfigGetString("storage.type.postgresql.username"); - auto Password = Daemon()->ConfigGetString("storage.type.postgresql.password"); - auto Database = Daemon()->ConfigGetString("storage.type.postgresql.database"); - auto Port = Daemon()->ConfigGetString("storage.type.postgresql.port"); - auto ConnectionTimeout = Daemon()->ConfigGetString("storage.type.postgresql.connectiontimeout"); + auto NumSessions = uCentral::Daemon()->ConfigGetInt("storage.type.postgresql.maxsessions", 64); + auto IdleTime = uCentral::Daemon()->ConfigGetInt("storage.type.postgresql.idletime", 60); + auto Host = uCentral::Daemon()->ConfigGetString("storage.type.postgresql.host"); + auto Username = uCentral::Daemon()->ConfigGetString("storage.type.postgresql.username"); + auto Password = uCentral::Daemon()->ConfigGetString("storage.type.postgresql.password"); + auto Database = uCentral::Daemon()->ConfigGetString("storage.type.postgresql.database"); + auto Port = uCentral::Daemon()->ConfigGetString("storage.type.postgresql.port"); + auto ConnectionTimeout = uCentral::Daemon()->ConfigGetString("storage.type.postgresql.connectiontimeout"); std::string ConnectionStr = "host=" + Host + diff --git a/src/storage_sqlite.cpp b/src/storage_sqlite.cpp index e101326..dc22b1c 100644 --- a/src/storage_sqlite.cpp +++ b/src/storage_sqlite.cpp @@ -9,13 +9,13 @@ #include "Daemon.h" #include "StorageService.h" -namespace uCentral { +namespace OpenWifi { int Storage::Setup_SQLite() { Logger_.notice("SQLite Storage enabled."); - auto DBName = Daemon()->DataDir() + "/" + Daemon()->ConfigGetString("storage.type.sqlite.db"); - auto NumSessions = Daemon()->ConfigGetInt("storage.type.sqlite.maxsessions", 64); - auto IdleTime = Daemon()->ConfigGetInt("storage.type.sqlite.idletime", 60); + auto DBName = uCentral::Daemon()->DataDir() + "/" + uCentral::Daemon()->ConfigGetString("storage.type.sqlite.db"); + auto NumSessions = uCentral::Daemon()->ConfigGetInt("storage.type.sqlite.maxsessions", 64); + auto IdleTime = uCentral::Daemon()->ConfigGetInt("storage.type.sqlite.idletime", 60); SQLiteConn_ = std::make_unique(); SQLiteConn_->registerConnector(); diff --git a/test_scripts/curl/cli b/test_scripts/curl/cli new file mode 100755 index 0000000..228d9fe --- /dev/null +++ b/test_scripts/curl/cli @@ -0,0 +1,139 @@ +#!/bin/bash + +# +# License type: BSD 3-Clause License +# License copy: https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/master/LICENSE +# +# Created by Stephane Bourque on 2021-03-04. +# Arilia Wireless Inc. +# + +if [[ "$(which jq)" == "" ]] +then + echo "You need the package jq installed to use this script." + exit 1 +fi + +if [[ "$(which curl)" == "" ]] +then + echo "You need the package curl installed to use this script." + exit 1 +fi + +if [[ "${UCENTRALSEC}" == "" ]] +then + echo "You must set the variable UCENTRALSEC in order to use this script. Something like" + echo "UCENTRALSEC=security.isp.com:16001" + exit 1 +fi + +if [[ "${FLAGS}" == "" ]] +then + FLAGS="-s" +fi + +token="" +result_file=result.json +username="tip@ucentral.com" +password="openwifi" +browser_list=(firefox sensible-browser xdg-open w3m links links2 lynx youtube-dl) +browser="" + +login() { + payload="{ \"userId\" : \"$username\" , \"password\" : \"$password\" }" + token=$(curl ${FLAGS} -X POST -H "Content-Type: application/json" -d "$payload" "https://${UCENTRALSEC}/api/v1/oauth2" | jq -r '.access_token') + + if [[ "${token}" == "" ]] + then + echo "Could not login. Please verify the host and username/password." + exit 13 + fi + echo "${token}" > token.json + setfms +} + +findbrowser() { + if [[ "${browser}" != "" ]] + then + echo + elif [[ "$(uname)" == "Darwin" ]] + then + browser=open + else + BROWSER_LIST=(firefox sensible-browser xdg-open w3m links links2 lynx youtube-dl) + for br_name in "${browser_list[@]}" + do + if [[ $(which ${br_name}) != "" ]] + then + browser=${br_name} + break + fi + done + fi +} + +setfms() { + curl ${FLAGS} -X GET "https://${UCENTRALSEC}/api/v1/systemEndpoints" \ + -H "accept: application/json" \ + -H "Authorization: Bearer ${token}" > ${result_file} +# jq < ${result_file} + + for index in {0..10} + do + endpointlocation=".endpoints[${index}].uri" + endpointlocationtype=".endpoints[${index}].type" + rawurl="$(cat ${result_file} | jq -r ${endpointlocation})" + svctype="$(cat ${result_file} | jq -r ${endpointlocationtype})" + proto="$(echo $rawurl | grep :// | sed -e's,^\(.*://\).*,\1,g')" + url="$(echo ${rawurl/$proto/})" + user="$(echo $url | grep @ | cut -d@ -f1)" + hostport="$(echo ${url/$user@/} | cut -d/ -f1)" + host="$(echo $hostport | sed -e 's,:.*,,g')" + port="$(echo $hostport | sed -e 's,^.*:,:,g' -e 's,.*:\([0-9]*\).*,\1,g' -e 's,[^0-9],,g')" + path="$(echo $url | grep / | cut -d/ -f2-)" + if [[ ${url} != "null" ]] + then + if [[ ${svctype} == "owprov" ]] + then + OWPROV="${url}" + break + fi + fi + done + echo "Using ${OWPROV}..." +} + +logout() { + curl ${FLAGS} -X DELETE -H "Content-Type: application/json" \ + -H "Authorization: Bearer ${token}" \ + "https://${UCENTRALSEC}/api/v1/oauth2/${token}" + rm -rf token.json +} + +getroot() { + curl ${FLAGS} \ + -H "Content-Type: application/json" \ + -H "Authorization: Bearer ${token}" \ + -H "accept: application/json" \ + "https://${OWPROV}/api/v1/entity/0000-0000-0000" > ${result_file} + jq < ${result_file} +} + +setroot() { + payload="{ \"name\" : \"Arilia Root\", \"description\" ; \"This is the top level entry in the hierarchy.\" }"; + curl ${FLAGS} -X POST "https://${OWPROV}/api/v1/entity/0000-0000-0000" \ + -H "Content-Type: application/json" \ + -H "Authorization: Bearer ${token}" \ + -H "accept: application/json" \ + -d "$payload" > ${result_file} + jq < ${result_file} +} + +shopt -s nocasematch +case "$1" in + "login") login; help ; logout ;; + "getroot") login; getroot; logout;; + "setroot") login; setroot; logout;; + *) help ;; +esac +