From c8038f545754766a82213e48b6cb98b281434b73 Mon Sep 17 00:00:00 2001 From: Jan Olszak Date: Wed, 4 Feb 2015 14:26:31 +0100 Subject: [PATCH 01/16] IPC: Added unique PeerID to the API to identify peers [Bug/Feature] PeerCallback takes peer's ID and fd All API methods take PeerID Replaced unordered map with a vector [Cause] N/A [Solution] N/A [Verification] Build, install, run tests, run tests under valgrind Change-Id: I352fd3942c4a2e6f7f5c891b1dcc0109d8bf7128 --- common/ipc/client.cpp | 10 +- common/ipc/client.hpp | 6 +- common/ipc/internals/add-peer-request.hpp | 8 +- common/ipc/internals/method-request.hpp | 16 +- common/ipc/internals/processor.cpp | 236 ++++++++++++++------------- common/ipc/internals/processor.hpp | 98 ++++++----- common/ipc/internals/remove-peer-request.hpp | 6 +- common/ipc/internals/signal-request.hpp | 14 +- common/ipc/service.cpp | 8 +- common/ipc/service.hpp | 16 +- common/ipc/types.cpp | 5 + common/ipc/types.hpp | 15 +- tests/unit_tests/ipc/ut-ipc.cpp | 69 ++++---- 13 files changed, 274 insertions(+), 233 deletions(-) diff --git a/common/ipc/client.cpp b/common/ipc/client.cpp index 1b7ae56..51e59f8 100644 --- a/common/ipc/client.cpp +++ b/common/ipc/client.cpp @@ -61,7 +61,7 @@ void Client::start(const bool usesExternalPolling) LOGD("Connecting to " + mSocketPath); auto socketPtr = std::make_shared(Socket::connectSocket(mSocketPath)); - mServiceFD = mProcessor.addPeer(socketPtr); + mServiceID = mProcessor.addPeer(socketPtr); } bool Client::isStarted() @@ -123,12 +123,12 @@ void Client::handle(const FileDescriptor fd, const short pollEvent) void Client::setNewPeerCallback(const PeerCallback& newPeerCallback) { LOGS("Client setNewPeerCallback"); - auto callback = [newPeerCallback, this](FileDescriptor fd) { + auto callback = [newPeerCallback, this](PeerID peerID, FileDescriptor fd) { if (mIPCGSourcePtr) { mIPCGSourcePtr->addFD(fd); } if (newPeerCallback) { - newPeerCallback(fd); + newPeerCallback(peerID, fd); } }; mProcessor.setNewPeerCallback(callback); @@ -137,12 +137,12 @@ void Client::setNewPeerCallback(const PeerCallback& newPeerCallback) void Client::setRemovedPeerCallback(const PeerCallback& removedPeerCallback) { LOGS("Client setRemovedPeerCallback"); - auto callback = [removedPeerCallback, this](FileDescriptor fd) { + auto callback = [removedPeerCallback, this](PeerID peerID, FileDescriptor fd) { if (mIPCGSourcePtr) { mIPCGSourcePtr->removeFD(fd); } if (removedPeerCallback) { - removedPeerCallback(fd); + removedPeerCallback(peerID, fd); } }; mProcessor.setRemovedPeerCallback(callback); diff --git a/common/ipc/client.hpp b/common/ipc/client.hpp index 1ee44bb..321b4da 100644 --- a/common/ipc/client.hpp +++ b/common/ipc/client.hpp @@ -174,7 +174,7 @@ private: void startPoll(); void stopPoll(); - FileDescriptor mServiceFD; + PeerID mServiceID; Processor mProcessor; std::string mSocketPath; IPCGSource::Pointer mIPCGSourcePtr; @@ -202,7 +202,7 @@ std::shared_ptr Client::callSync(const MethodID methodID, unsigned int timeoutMS) { LOGS("Client callSync, methodID: " << methodID << ", timeoutMS: " << timeoutMS); - return mProcessor.callSync(methodID, mServiceFD, data, timeoutMS); + return mProcessor.callSync(methodID, mServiceID, data, timeoutMS); } template @@ -213,7 +213,7 @@ void Client::callAsync(const MethodID methodID, LOGS("Client callAsync, methodID: " << methodID); mProcessor.callAsync(methodID, - mServiceFD, + mServiceID, data, resultCallback); } diff --git a/common/ipc/internals/add-peer-request.hpp b/common/ipc/internals/add-peer-request.hpp index 3409ba5..57ec06c 100644 --- a/common/ipc/internals/add-peer-request.hpp +++ b/common/ipc/internals/add-peer-request.hpp @@ -36,14 +36,14 @@ public: AddPeerRequest(const AddPeerRequest&) = delete; AddPeerRequest& operator=(const AddPeerRequest&) = delete; - AddPeerRequest(const FileDescriptor peerFD, const std::shared_ptr& socketPtr) - : peerFD(peerFD), - socketPtr(socketPtr) + AddPeerRequest(const std::shared_ptr& socketPtr) + : socketPtr(socketPtr), + peerID(getNextPeerID()) { } - FileDescriptor peerFD; std::shared_ptr socketPtr; + PeerID peerID; }; } // namespace ipc diff --git a/common/ipc/internals/method-request.hpp b/common/ipc/internals/method-request.hpp index 8ed17c5..8ec1223 100644 --- a/common/ipc/internals/method-request.hpp +++ b/common/ipc/internals/method-request.hpp @@ -42,12 +42,12 @@ public: template static std::shared_ptr create(const MethodID methodID, - const FileDescriptor peerFD, + const PeerID peerID, const std::shared_ptr& data, const typename ResultHandler::type& process); MethodID methodID; - FileDescriptor peerFD; + PeerID peerID; MessageID messageID; std::shared_ptr data; SerializeCallback serialize; @@ -55,9 +55,9 @@ public: ResultBuilderHandler process; private: - MethodRequest(const MethodID methodID, const FileDescriptor peerFD) + MethodRequest(const MethodID methodID, const PeerID peerID) : methodID(methodID), - peerFD(peerFD), + peerID(peerID), messageID(getNextMessageID()) {} }; @@ -65,21 +65,21 @@ private: template std::shared_ptr MethodRequest::create(const MethodID methodID, - const FileDescriptor peerFD, + const PeerID peerID, const std::shared_ptr& data, const typename ResultHandler::type& process) { - std::shared_ptr request(new MethodRequest(methodID, peerFD)); + std::shared_ptr request(new MethodRequest(methodID, peerID)); request->data = data; request->serialize = [](const int fd, std::shared_ptr& data)->void { - LOGS("Method serialize, peerFD: " << fd); + LOGS("Method serialize, peerID: " << fd); config::saveToFD(fd, *std::static_pointer_cast(data)); }; request->parse = [](const int fd)->std::shared_ptr { - LOGS("Method parse, peerFD: " << fd); + LOGS("Method parse, peerID: " << fd); std::shared_ptr data(new ReceivedDataType()); config::loadFromFD(fd, *data); return data; diff --git a/common/ipc/internals/processor.cpp b/common/ipc/internals/processor.cpp index 1f51d5e..d63e490 100644 --- a/common/ipc/internals/processor.cpp +++ b/common/ipc/internals/processor.cpp @@ -84,6 +84,20 @@ Processor::~Processor() } } +Processor::Peers::iterator Processor::getPeerInfoIterator(const FileDescriptor fd) +{ + return std::find_if(mPeerInfo.begin(), mPeerInfo.end(), [&fd](const PeerInfo & peerInfo) { + return fd == peerInfo.socketPtr->getFD(); + }); +} + +Processor::Peers::iterator Processor::getPeerInfoIterator(const PeerID peerID) +{ + return std::find_if(mPeerInfo.begin(), mPeerInfo.end(), [&peerID](const PeerInfo & peerInfo) { + return peerID == peerInfo.peerID; + }); +} + bool Processor::isStarted() { Lock lock(mStateMutex); @@ -155,55 +169,54 @@ void Processor::removeMethod(const MethodID methodID) mMethodsCallbacks.erase(methodID); } -FileDescriptor Processor::addPeer(const std::shared_ptr& socketPtr) +PeerID Processor::addPeer(const std::shared_ptr& socketPtr) { LOGS(mLogPrefix + "Processor addPeer"); Lock lock(mStateMutex); - FileDescriptor peerFD = socketPtr->getFD(); - auto request = std::make_shared(peerFD, socketPtr); - mRequestQueue.pushBack(Event::ADD_PEER, request); + auto requestPtr = std::make_shared(socketPtr); + mRequestQueue.pushBack(Event::ADD_PEER, requestPtr); - LOGI(mLogPrefix + "Add Peer Request. Id: " << peerFD); + LOGI(mLogPrefix + "Add Peer Request. Id: " << requestPtr->peerID); - return peerFD; + return requestPtr->peerID; } -void Processor::removePeerSyncInternal(const FileDescriptor peerFD, Lock& lock) +void Processor::removePeerSyncInternal(const PeerID peerID, Lock& lock) { - LOGS(mLogPrefix + "Processor removePeer peerFD: " << peerFD); + LOGS(mLogPrefix + "Processor removePeer peerID: " << peerID); - auto isPeerDeleted = [&peerFD, this]()->bool { - return mSockets.count(peerFD) == 0; + auto isPeerDeleted = [&peerID, this]()->bool { + return getPeerInfoIterator(peerID) == mPeerInfo.end(); }; - mRequestQueue.removeIf([peerFD](Request & request) { + mRequestQueue.removeIf([peerID](Request & request) { return request.requestID == Event::ADD_PEER && - request.get()->peerFD == peerFD; + request.get()->peerID == peerID; }); // Remove peer and wait till he's gone std::shared_ptr conditionPtr(new std::condition_variable()); - auto request = std::make_shared(peerFD, conditionPtr); + auto request = std::make_shared(peerID, conditionPtr); mRequestQueue.pushBack(Event::REMOVE_PEER, request); conditionPtr->wait(lock, isPeerDeleted); } -void Processor::removePeerInternal(const FileDescriptor peerFD, const std::exception_ptr& exceptionPtr) +void Processor::removePeerInternal(Peers::iterator peerIt, const std::exception_ptr& exceptionPtr) { - LOGS(mLogPrefix + "Processor removePeerInternal peerFD: " << peerFD); - LOGI(mLogPrefix + "Removing peer. peerFD: " << peerFD); + LOGS(mLogPrefix + "Processor removePeerInternal peerID: " << peerIt->peerID); + LOGI(mLogPrefix + "Removing peer. peerID: " << peerIt->peerID); - if (!mSockets.erase(peerFD)) { - LOGW(mLogPrefix + "No such peer. Another thread called removePeerInternal"); + if (peerIt == mPeerInfo.end()) { + LOGW("Peer already removed"); return; } // Remove from signal addressees for (auto it = mSignalsPeers.begin(); it != mSignalsPeers.end();) { - it->second.remove(peerFD); + it->second.remove(peerIt->peerID); if (it->second.empty()) { it = mSignalsPeers.erase(it); } else { @@ -213,7 +226,7 @@ void Processor::removePeerInternal(const FileDescriptor peerFD, const std::excep // Erase associated return value callbacks for (auto it = mReturnCallbacks.begin(); it != mReturnCallbacks.end();) { - if (it->second.peerFD == peerFD) { + if (it->second.peerID == peerIt->peerID) { ResultBuilder resultBuilder(exceptionPtr); IGNORE_EXCEPTIONS(it->second.process(resultBuilder)); it = mReturnCallbacks.erase(it); @@ -224,8 +237,10 @@ void Processor::removePeerInternal(const FileDescriptor peerFD, const std::excep if (mRemovedPeerCallback) { // Notify about the deletion - mRemovedPeerCallback(peerFD); + mRemovedPeerCallback(peerIt->peerID, peerIt->socketPtr->getFD()); } + + mPeerInfo.erase(peerIt); } void Processor::resetPolling() @@ -236,19 +251,20 @@ void Processor::resetPolling() return; } - LOGI(mLogPrefix + "Reseting mFDS.size: " << mSockets.size()); // Setup polling on eventfd and sockets - mFDs.resize(mSockets.size() + 1); + mFDs.resize(mPeerInfo.size() + 1); + LOGI(mLogPrefix + "Reseting mFDS.size: " << mFDs.size()); mFDs[0].fd = mRequestQueue.getFD(); mFDs[0].events = POLLIN; - auto socketIt = mSockets.begin(); for (unsigned int i = 1; i < mFDs.size(); ++i) { - LOGI(mLogPrefix + "Reseting fd: " << socketIt->second->getFD()); - mFDs[i].fd = socketIt->second->getFD(); + auto fd = mPeerInfo[i - 1].socketPtr->getFD(); + + LOGI(mLogPrefix + "Reseting fd: " << fd); + + mFDs[i].fd = fd; mFDs[i].events = POLLIN | POLLHUP; // Listen for input events - ++socketIt; // TODO: It's possible to block on writing to fd. Maybe listen for POLLOUT too? } } @@ -306,25 +322,26 @@ bool Processor::handleLostConnections() Lock lock(mStateMutex); bool isPeerRemoved = false; - { - for (unsigned int i = 1; i < mFDs.size(); ++i) { - if (mFDs[i].revents & POLLHUP) { - LOGI(mLogPrefix + "Lost connection to peer: " << mFDs[i].fd); - mFDs[i].revents &= ~(POLLHUP); - removePeerInternal(mFDs[i].fd, - std::make_exception_ptr(IPCPeerDisconnectedException())); - isPeerRemoved = true; - } + + for (unsigned int i = 1; i < mFDs.size(); ++i) { + if (mFDs[i].revents & POLLHUP) { + auto peerIt = getPeerInfoIterator(mFDs[i].fd); + LOGI(mLogPrefix + "Lost connection to peer: " << peerIt->peerID); + mFDs[i].revents &= ~(POLLHUP); + removePeerInternal(peerIt, + std::make_exception_ptr(IPCPeerDisconnectedException())); + isPeerRemoved = true; } } return isPeerRemoved; } -bool Processor::handleLostConnection(const FileDescriptor peerFD) +bool Processor::handleLostConnection(const FileDescriptor fd) { Lock lock(mStateMutex); - removePeerInternal(peerFD, + auto peerIt = getPeerInfoIterator(fd); + removePeerInternal(peerIt, std::make_exception_ptr(IPCPeerDisconnectedException())); return true; } @@ -344,54 +361,53 @@ bool Processor::handleInputs() return pollChanged; } -bool Processor::handleInput(const FileDescriptor peerFD) +bool Processor::handleInput(const FileDescriptor fd) { - LOGS(mLogPrefix + "Processor handleInput peerFD: " << peerFD); + LOGS(mLogPrefix + "Processor handleInput fd: " << fd); Lock lock(mStateMutex); - std::shared_ptr socketPtr; - try { - // Get the peer's socket - socketPtr = mSockets.at(peerFD); - } catch (const std::out_of_range&) { - LOGE(mLogPrefix + "No such peer: " << peerFD); + auto peerIt = getPeerInfoIterator(fd); + + if (peerIt == mPeerInfo.end()) { + LOGE(mLogPrefix + "No peer for fd: " << fd); return false; } + Socket& socket = *peerIt->socketPtr; + MethodID methodID; MessageID messageID; { - Socket::Guard guard = socketPtr->getGuard(); + Socket::Guard guard = socket.getGuard(); try { - socketPtr->read(&methodID, sizeof(methodID)); - socketPtr->read(&messageID, sizeof(messageID)); + socket.read(&methodID, sizeof(methodID)); + socket.read(&messageID, sizeof(messageID)); } catch (const IPCException& e) { LOGE(mLogPrefix + "Error during reading the socket"); - removePeerInternal(socketPtr->getFD(), + removePeerInternal(peerIt, std::make_exception_ptr(IPCNaughtyPeerException())); return true; } if (methodID == RETURN_METHOD_ID) { - return onReturnValue(*socketPtr, messageID); + return onReturnValue(peerIt, messageID); } else { if (mMethodsCallbacks.count(methodID)) { // Method std::shared_ptr methodCallbacks = mMethodsCallbacks.at(methodID); - return onRemoteMethod(*socketPtr, methodID, messageID, methodCallbacks); + return onRemoteMethod(peerIt, methodID, messageID, methodCallbacks); } else if (mSignalsCallbacks.count(methodID)) { // Signal std::shared_ptr signalCallbacks = mSignalsCallbacks.at(methodID); - return onRemoteSignal(*socketPtr, methodID, messageID, signalCallbacks); + return onRemoteSignal(peerIt, methodID, messageID, signalCallbacks); } else { - // Nothing LOGW(mLogPrefix + "No method or signal callback for methodID: " << methodID); - removePeerInternal(socketPtr->getFD(), + removePeerInternal(peerIt, std::make_exception_ptr(IPCNaughtyPeerException())); return true; } @@ -399,20 +415,20 @@ bool Processor::handleInput(const FileDescriptor peerFD) } } -void Processor::onNewSignals(const FileDescriptor peerFD, - std::shared_ptr& data) +void Processor::onNewSignals(const PeerID peerID, std::shared_ptr& data) { - LOGS(mLogPrefix + "Processor onNewSignals peerFD: " << peerFD); + LOGS(mLogPrefix + "Processor onNewSignals peerID: " << peerID); for (const MethodID methodID : data->ids) { - mSignalsPeers[methodID].push_back(peerFD); + mSignalsPeers[methodID].push_back(peerID); } } -void Processor::onErrorSignal(const FileDescriptor, std::shared_ptr& data) +void Processor::onErrorSignal(const PeerID, std::shared_ptr& data) { LOGS(mLogPrefix + "Processor onErrorSignal messageID: " << data->messageID); + // If there is no return callback an out_of_range error will be thrown and peer will be removed ReturnCallbacks returnCallbacks = std::move(mReturnCallbacks.at(data->messageID)); mReturnCallbacks.erase(data->messageID); @@ -420,7 +436,7 @@ void Processor::onErrorSignal(const FileDescriptor, std::shared_ptr data; try { LOGT(mLogPrefix + "Parsing incoming return data"); - data = returnCallbacks.parse(socket.getFD()); + data = returnCallbacks.parse(peerIt->socketPtr->getFD()); } catch (const std::exception& e) { LOGE(mLogPrefix + "Exception during parsing: " << e.what()); ResultBuilder resultBuilder(std::make_exception_ptr(IPCParsingException())); IGNORE_EXCEPTIONS(returnCallbacks.process(resultBuilder)); - removePeerInternal(socket.getFD(), + removePeerInternal(peerIt, std::make_exception_ptr(IPCParsingException())); return true; } @@ -456,7 +472,7 @@ bool Processor::onReturnValue(const Socket& socket, return false; } -bool Processor::onRemoteSignal(const Socket& socket, +bool Processor::onRemoteSignal(Peers::iterator& peerIt, const MethodID methodID, const MessageID messageID, std::shared_ptr signalCallbacks) @@ -466,22 +482,22 @@ bool Processor::onRemoteSignal(const Socket& socket, std::shared_ptr data; try { LOGT(mLogPrefix + "Parsing incoming data"); - data = signalCallbacks->parse(socket.getFD()); + data = signalCallbacks->parse(peerIt->socketPtr->getFD()); } catch (const std::exception& e) { LOGE(mLogPrefix + "Exception during parsing: " << e.what()); - removePeerInternal(socket.getFD(), + removePeerInternal(peerIt, std::make_exception_ptr(IPCParsingException())); return true; } try { - signalCallbacks->signal(socket.getFD(), data); + signalCallbacks->signal(peerIt->peerID, data); } catch (const IPCUserException& e) { LOGW("Discarded user's exception"); return false; } catch (const std::exception& e) { LOGE(mLogPrefix + "Exception in method handler: " << e.what()); - removePeerInternal(socket.getFD(), + removePeerInternal(peerIt, std::make_exception_ptr(IPCNaughtyPeerException())); return true; @@ -490,7 +506,7 @@ bool Processor::onRemoteSignal(const Socket& socket, return false; } -bool Processor::onRemoteMethod(const Socket& socket, +bool Processor::onRemoteMethod(Peers::iterator& peerIt, const MethodID methodID, const MessageID messageID, std::shared_ptr methodCallbacks) @@ -500,10 +516,10 @@ bool Processor::onRemoteMethod(const Socket& socket, std::shared_ptr data; try { LOGT(mLogPrefix + "Parsing incoming data"); - data = methodCallbacks->parse(socket.getFD()); + data = methodCallbacks->parse(peerIt->socketPtr->getFD()); } catch (const std::exception& e) { LOGE(mLogPrefix + "Exception during parsing: " << e.what()); - removePeerInternal(socket.getFD(), + removePeerInternal(peerIt, std::make_exception_ptr(IPCParsingException())); return true; } @@ -511,15 +527,15 @@ bool Processor::onRemoteMethod(const Socket& socket, LOGT(mLogPrefix + "Process callback for methodID: " << methodID << "; messageID: " << messageID); std::shared_ptr returnData; try { - returnData = methodCallbacks->method(socket.getFD(), data); + returnData = methodCallbacks->method(peerIt->peerID, data); } catch (const IPCUserException& e) { LOGW("User's exception"); auto data = std::make_shared(messageID, e.getCode(), e.what()); - signalInternal(ERROR_METHOD_ID, socket.getFD(), data); + signalInternal(ERROR_METHOD_ID, peerIt->peerID, data); return false; } catch (const std::exception& e) { LOGE(mLogPrefix + "Exception in method handler: " << e.what()); - removePeerInternal(socket.getFD(), + removePeerInternal(peerIt, std::make_exception_ptr(IPCNaughtyPeerException())); return true; } @@ -527,13 +543,14 @@ bool Processor::onRemoteMethod(const Socket& socket, LOGT(mLogPrefix + "Sending return data; methodID: " << methodID << "; messageID: " << messageID); try { // Send the call with the socket + Socket& socket = *peerIt->socketPtr; Socket::Guard guard = socket.getGuard(); socket.write(&RETURN_METHOD_ID, sizeof(RETURN_METHOD_ID)); socket.write(&messageID, sizeof(messageID)); methodCallbacks->serialize(socket.getFD(), returnData); } catch (const std::exception& e) { LOGE(mLogPrefix + "Exception during serialization: " << e.what()); - removePeerInternal(socket.getFD(), + removePeerInternal(peerIt, std::make_exception_ptr(IPCSerializationException())); return true; @@ -565,13 +582,11 @@ bool Processor::handleEvent() bool Processor::onMethodRequest(MethodRequest& request) { LOGS(mLogPrefix + "Processor onMethodRequest"); - std::shared_ptr socketPtr; - try { - // Get the peer's socket - socketPtr = mSockets.at(request.peerFD); - } catch (const std::out_of_range&) { - LOGE(mLogPrefix + "Peer disconnected. No socket with a peerFD: " << request.peerFD); + auto peerIt = getPeerInfoIterator(request.peerID); + + if (peerIt == mPeerInfo.end()) { + LOGE(mLogPrefix + "Peer disconnected. No user with a peerID: " << request.peerID); // Pass the error to the processing callback ResultBuilder resultBuilder(std::make_exception_ptr(IPCPeerDisconnectedException())); @@ -583,17 +598,18 @@ bool Processor::onMethodRequest(MethodRequest& request) if (mReturnCallbacks.count(request.messageID) != 0) { LOGE(mLogPrefix + "There already was a return callback for messageID: " << request.messageID); } - mReturnCallbacks[request.messageID] = std::move(ReturnCallbacks(request.peerFD, + mReturnCallbacks[request.messageID] = std::move(ReturnCallbacks(peerIt->peerID, std::move(request.parse), std::move(request.process))); + Socket& socket = *peerIt->socketPtr; try { // Send the call with the socket - Socket::Guard guard = socketPtr->getGuard(); - socketPtr->write(&request.methodID, sizeof(request.methodID)); - socketPtr->write(&request.messageID, sizeof(request.messageID)); + Socket::Guard guard = socket.getGuard(); + socket.write(&request.methodID, sizeof(request.methodID)); + socket.write(&request.messageID, sizeof(request.messageID)); LOGT(mLogPrefix + "Serializing the message"); - request.serialize(socketPtr->getFD(), request.data); + request.serialize(socket.getFD(), request.data); } catch (const std::exception& e) { LOGE(mLogPrefix + "Error during sending a method: " << e.what()); @@ -603,10 +619,8 @@ bool Processor::onMethodRequest(MethodRequest& request) mReturnCallbacks.erase(request.messageID); - removePeerInternal(request.peerFD, + removePeerInternal(peerIt, std::make_exception_ptr(IPCSerializationException())); - - return true; } @@ -618,27 +632,25 @@ bool Processor::onSignalRequest(SignalRequest& request) { LOGS(mLogPrefix + "Processor onSignalRequest"); - std::shared_ptr socketPtr; - try { - // Get the peer's socket - socketPtr = mSockets.at(request.peerFD); - } catch (const std::out_of_range&) { - LOGE(mLogPrefix + "Peer disconnected. No socket with a peerFD: " << request.peerFD); + auto peerIt = getPeerInfoIterator(request.peerID); + + if (peerIt == mPeerInfo.end()) { + LOGE(mLogPrefix + "Peer disconnected. No user for peerID: " << request.peerID); return false; } + Socket& socket = *peerIt->socketPtr; try { // Send the call with the socket - Socket::Guard guard = socketPtr->getGuard(); - socketPtr->write(&request.methodID, sizeof(request.methodID)); - socketPtr->write(&request.messageID, sizeof(request.messageID)); - request.serialize(socketPtr->getFD(), request.data); + Socket::Guard guard = socket.getGuard(); + socket.write(&request.methodID, sizeof(request.methodID)); + socket.write(&request.messageID, sizeof(request.messageID)); + request.serialize(socket.getFD(), request.data); } catch (const std::exception& e) { LOGE(mLogPrefix + "Error during sending a signal: " << e.what()); - removePeerInternal(request.peerFD, + removePeerInternal(peerIt, std::make_exception_ptr(IPCSerializationException())); - return true; } @@ -649,16 +661,18 @@ bool Processor::onAddPeerRequest(AddPeerRequest& request) { LOGS(mLogPrefix + "Processor onAddPeerRequest"); - if (mSockets.size() > mMaxNumberOfPeers) { - LOGE(mLogPrefix + "There are too many peers. I don't accept the connection with " << request.peerFD); + if (mPeerInfo.size() > mMaxNumberOfPeers) { + LOGE(mLogPrefix + "There are too many peers. I don't accept the connection with " << request.peerID); return false; } - if (mSockets.count(request.peerFD) != 0) { - LOGE(mLogPrefix + "There already was a socket for peerFD: " << request.peerFD); + + if (getPeerInfoIterator(request.peerID) != mPeerInfo.end()) { + LOGE(mLogPrefix + "There already was a socket for peerID: " << request.peerID); return false; } - mSockets[request.peerFD] = std::move(request.socketPtr); + PeerInfo peerInfo(request.peerID, request.socketPtr); + mPeerInfo.push_back(std::move(peerInfo)); // Sending handled signals @@ -668,16 +682,16 @@ bool Processor::onAddPeerRequest(AddPeerRequest& request) } auto data = std::make_shared(ids); signalInternal(REGISTER_SIGNAL_METHOD_ID, - request.peerFD, + request.peerID, data); if (mNewPeerCallback) { // Notify about the new user. LOGT(mLogPrefix + "Calling NewPeerCallback"); - mNewPeerCallback(request.peerFD); + mNewPeerCallback(request.peerID, request.socketPtr->getFD()); } - LOGI(mLogPrefix + "New peer: " << request.peerFD); + LOGI(mLogPrefix + "New peerID: " << request.peerID); return true; } @@ -685,7 +699,7 @@ bool Processor::onRemovePeerRequest(RemovePeerRequest& request) { LOGS(mLogPrefix + "Processor onRemovePeer"); - removePeerInternal(request.peerFD, + removePeerInternal(getPeerInfoIterator(request.peerID), std::make_exception_ptr(IPCRemovedPeerException())); request.conditionPtr->notify_all(); diff --git a/common/ipc/internals/processor.hpp b/common/ipc/internals/processor.hpp index a77c072..604d863 100644 --- a/common/ipc/internals/processor.hpp +++ b/common/ipc/internals/processor.hpp @@ -170,9 +170,9 @@ public: * Calls the newPeerCallback. * * @param socketPtr pointer to the new socket - * @return peerFD of the new socket + * @return peerID of the new user */ - FileDescriptor addPeer(const std::shared_ptr& socketPtr); + PeerID addPeer(const std::shared_ptr& socketPtr); /** * Saves the callbacks connected to the method id. @@ -219,7 +219,7 @@ public: * Synchronous method call. * * @param methodID API dependent id of the method - * @param peerFD id of the peer + * @param peerD id of the peer * @param data data to sent * @param timeoutMS how long to wait for the return value before throw * @tparam SentDataType data type to send @@ -227,7 +227,7 @@ public: */ template std::shared_ptr callSync(const MethodID methodID, - const FileDescriptor peerFD, + const PeerID peerID, const std::shared_ptr& data, unsigned int timeoutMS = 500); @@ -235,7 +235,7 @@ public: * Asynchronous method call * * @param methodID API dependent id of the method - * @param peerFD id of the peer + * @param peerID id of the peer * @param data data to sent * @param process callback processing the return data * @tparam SentDataType data type to send @@ -243,7 +243,7 @@ public: */ template MessageID callAsync(const MethodID methodID, - const FileDescriptor peerFD, + const PeerID peerID, const std::shared_ptr& data, const typename ResultHandler::type& process); @@ -265,19 +265,19 @@ public: * Removes one peer. * Handler used in external polling. * - * @param peerFD file description identifying the peer + * @param fd file description identifying the peer * @return should the polling structure be rebuild */ - bool handleLostConnection(const FileDescriptor peerFD); + bool handleLostConnection(const FileDescriptor fd); /** * Handles input from one peer. * Handler used in external polling. * - * @param peerFD file description identifying the peer + * @param fd file description identifying the peer * @return should the polling structure be rebuild */ - bool handleInput(const FileDescriptor peerFD); + bool handleInput(const FileDescriptor fd); /** * Handle one event from the internal event's queue @@ -361,14 +361,31 @@ private: ReturnCallbacks(ReturnCallbacks&&) = default; ReturnCallbacks& operator=(ReturnCallbacks &&) = default; - ReturnCallbacks(FileDescriptor peerFD, const ParseCallback& parse, const ResultBuilderHandler& process) - : peerFD(peerFD), parse(parse), process(process) {} + ReturnCallbacks(PeerID peerID, const ParseCallback& parse, const ResultBuilderHandler& process) + : peerID(peerID), parse(parse), process(process) {} - FileDescriptor peerFD; + PeerID peerID; ParseCallback parse; ResultBuilderHandler process; }; + struct PeerInfo { + PeerInfo(const PeerInfo& other) = delete; + PeerInfo& operator=(const PeerInfo&) = delete; + PeerInfo() = delete; + + PeerInfo(PeerInfo&&) = default; + PeerInfo& operator=(PeerInfo &&) = default; + + PeerInfo(PeerID peerID, const std::shared_ptr& socketPtr) + : peerID(peerID), socketPtr(socketPtr) {} + + PeerID peerID; + std::shared_ptr socketPtr; + }; + + typedef std::vector Peers; + std::string mLogPrefix; RequestQueue mRequestQueue; @@ -378,9 +395,9 @@ private: std::unordered_map> mMethodsCallbacks; std::unordered_map> mSignalsCallbacks; - std::unordered_map> mSignalsPeers; + std::unordered_map> mSignalsPeers; - std::unordered_map > mSockets; + Peers mPeerInfo; std::vector mFDs; std::unordered_map mReturnCallbacks; @@ -405,7 +422,7 @@ private: template void signalInternal(const MethodID methodID, - const FileDescriptor peerFD, + const PeerID peerID, const std::shared_ptr& data); void run(); @@ -420,27 +437,30 @@ private: bool handleLostConnections(); bool handleInputs(); - bool onReturnValue(const Socket& socket, + bool onReturnValue(Peers::iterator& peerIt, const MessageID messageID); - bool onRemoteMethod(const Socket& socket, + bool onRemoteMethod(Peers::iterator& peerIt, const MethodID methodID, const MessageID messageID, std::shared_ptr methodCallbacks); - bool onRemoteSignal(const Socket& socket, + bool onRemoteSignal(Peers::iterator& peerIt, const MethodID methodID, const MessageID messageID, std::shared_ptr signalCallbacks); void resetPolling(); - FileDescriptor getNextFileDescriptor(); - void removePeerInternal(const FileDescriptor peerFD, const std::exception_ptr& exceptionPtr); - void removePeerSyncInternal(const FileDescriptor peerFD, Lock& lock); - void onNewSignals(const FileDescriptor peerFD, + void removePeerInternal(Peers::iterator peerIt, + const std::exception_ptr& exceptionPtr); + void removePeerSyncInternal(const PeerID peerID, Lock& lock); + + void onNewSignals(const PeerID peerID, std::shared_ptr& data); - void onErrorSignal(const FileDescriptor peerFD, + void onErrorSignal(const PeerID peerID, std::shared_ptr& data); + Peers::iterator getPeerInfoIterator(const FileDescriptor fd); + Peers::iterator getPeerInfoIterator(const PeerID peerID); }; @@ -460,9 +480,9 @@ void Processor::setMethodHandlerInternal(const MethodID methodID, config::saveToFD(fd, *std::static_pointer_cast(data)); }; - methodCall.method = [method](const FileDescriptor peerFD, std::shared_ptr& data)->std::shared_ptr { + methodCall.method = [method](const PeerID peerID, std::shared_ptr& data)->std::shared_ptr { std::shared_ptr tmpData = std::static_pointer_cast(data); - return method(peerFD, tmpData); + return method(peerID, tmpData); }; mMethodsCallbacks[methodID] = std::make_shared(std::move(methodCall)); @@ -502,9 +522,9 @@ void Processor::setSignalHandlerInternal(const MethodID methodID, return dataToFill; }; - signalCall.signal = [handler](const FileDescriptor peerFD, std::shared_ptr& dataReceived) { + signalCall.signal = [handler](const PeerID peerID, std::shared_ptr& dataReceived) { std::shared_ptr tmpData = std::static_pointer_cast(dataReceived); - handler(peerFD, tmpData); + handler(peerID, tmpData); }; mSignalsCallbacks[methodID] = std::make_shared(std::move(signalCall)); @@ -537,9 +557,9 @@ void Processor::setSignalHandler(const MethodID methodID, std::vector ids {methodID}; data = std::make_shared(ids); - for (const auto kv : mSockets) { + for (const PeerInfo& peerInfo : mPeerInfo) { signalInternal(REGISTER_SIGNAL_METHOD_ID, - kv.first, + peerInfo.peerID, data); } } @@ -548,12 +568,12 @@ void Processor::setSignalHandler(const MethodID methodID, template MessageID Processor::callAsync(const MethodID methodID, - const FileDescriptor peerFD, + const PeerID peerID, const std::shared_ptr& data, const typename ResultHandler::type& process) { Lock lock(mStateMutex); - auto request = MethodRequest::create(methodID, peerFD, data, process); + auto request = MethodRequest::create(methodID, peerID, data, process); mRequestQueue.pushBack(Event::METHOD, request); return request->messageID; } @@ -561,7 +581,7 @@ MessageID Processor::callAsync(const MethodID methodID, template std::shared_ptr Processor::callSync(const MethodID methodID, - const FileDescriptor peerFD, + const PeerID peerID, const std::shared_ptr& data, unsigned int timeoutMS) { @@ -575,7 +595,7 @@ std::shared_ptr Processor::callSync(const MethodID methodID, }; MessageID messageID = callAsync(methodID, - peerFD, + peerID, data, process); @@ -597,7 +617,7 @@ std::shared_ptr Processor::callSync(const MethodID methodID, if (isTimeout) { LOGE(mLogPrefix + "Function call timeout; methodID: " << methodID); - removePeerSyncInternal(peerFD, lock); + removePeerSyncInternal(peerID, lock); throw IPCTimeoutException("Function call timeout; methodID: " + std::to_string(methodID)); } else { LOGW(mLogPrefix + "Timeout started during the return value processing, so wait for it to finish"); @@ -613,10 +633,10 @@ std::shared_ptr Processor::callSync(const MethodID methodID, template void Processor::signalInternal(const MethodID methodID, - const FileDescriptor peerFD, + const PeerID peerID, const std::shared_ptr& data) { - auto request = SignalRequest::create(methodID, peerFD, data); + auto request = SignalRequest::create(methodID, peerID, data); mRequestQueue.pushFront(Event::SIGNAL, request); } @@ -630,8 +650,8 @@ void Processor::signal(const MethodID methodID, LOGW(mLogPrefix + "No peer is handling signal with methodID: " << methodID); return; } - for (const FileDescriptor peerFD : it->second) { - auto request = SignalRequest::create(methodID, peerFD, data); + for (const PeerID peerID : it->second) { + auto request = SignalRequest::create(methodID, peerID, data); mRequestQueue.pushBack(Event::SIGNAL, request); } } diff --git a/common/ipc/internals/remove-peer-request.hpp b/common/ipc/internals/remove-peer-request.hpp index 900a8a0..6ef8eca 100644 --- a/common/ipc/internals/remove-peer-request.hpp +++ b/common/ipc/internals/remove-peer-request.hpp @@ -38,14 +38,14 @@ public: RemovePeerRequest(const RemovePeerRequest&) = delete; RemovePeerRequest& operator=(const RemovePeerRequest&) = delete; - RemovePeerRequest(const FileDescriptor peerFD, + RemovePeerRequest(const PeerID peerID, const std::shared_ptr& conditionPtr) - : peerFD(peerFD), + : peerID(peerID), conditionPtr(conditionPtr) { } - FileDescriptor peerFD; + PeerID peerID; std::shared_ptr conditionPtr; }; diff --git a/common/ipc/internals/signal-request.hpp b/common/ipc/internals/signal-request.hpp index ad80d91..8a11ee8 100644 --- a/common/ipc/internals/signal-request.hpp +++ b/common/ipc/internals/signal-request.hpp @@ -41,19 +41,19 @@ public: template static std::shared_ptr create(const MethodID methodID, - const FileDescriptor peerFD, + const PeerID peerID, const std::shared_ptr& data); MethodID methodID; - FileDescriptor peerFD; + PeerID peerID; MessageID messageID; std::shared_ptr data; SerializeCallback serialize; private: - SignalRequest(const MethodID methodID, const FileDescriptor peerFD) + SignalRequest(const MethodID methodID, const PeerID peerID) : methodID(methodID), - peerFD(peerFD), + peerID(peerID), messageID(getNextMessageID()) {} @@ -61,15 +61,15 @@ private: template std::shared_ptr SignalRequest::create(const MethodID methodID, - const FileDescriptor peerFD, + const PeerID peerID, const std::shared_ptr& data) { - std::shared_ptr request(new SignalRequest(methodID, peerFD)); + std::shared_ptr request(new SignalRequest(methodID, peerID)); request->data = data; request->serialize = [](const int fd, std::shared_ptr& data)->void { - LOGS("Signal serialize, peerFD: " << fd); + LOGS("Signal serialize, peerID: " << fd); config::saveToFD(fd, *std::static_pointer_cast(data)); }; diff --git a/common/ipc/service.cpp b/common/ipc/service.cpp index 9bf721b..d945f73 100644 --- a/common/ipc/service.cpp +++ b/common/ipc/service.cpp @@ -142,12 +142,12 @@ void Service::handle(const FileDescriptor fd, const short pollEvent) void Service::setNewPeerCallback(const PeerCallback& newPeerCallback) { LOGS("Service setNewPeerCallback"); - auto callback = [newPeerCallback, this](FileDescriptor fd) { + auto callback = [newPeerCallback, this](PeerID peerID, FileDescriptor fd) { if (mIPCGSourcePtr) { mIPCGSourcePtr->addFD(fd); } if (newPeerCallback) { - newPeerCallback(fd); + newPeerCallback(peerID, fd); } }; mProcessor.setNewPeerCallback(callback); @@ -156,12 +156,12 @@ void Service::setNewPeerCallback(const PeerCallback& newPeerCallback) void Service::setRemovedPeerCallback(const PeerCallback& removedPeerCallback) { LOGS("Service setRemovedPeerCallback"); - auto callback = [removedPeerCallback, this](FileDescriptor fd) { + auto callback = [removedPeerCallback, this](PeerID peerID, FileDescriptor fd) { if (mIPCGSourcePtr) { mIPCGSourcePtr->removeFD(fd); } if (removedPeerCallback) { - removedPeerCallback(fd); + removedPeerCallback(peerID, fd); } }; mProcessor.setRemovedPeerCallback(callback); diff --git a/common/ipc/service.hpp b/common/ipc/service.hpp index 383c71d..022c9c9 100644 --- a/common/ipc/service.hpp +++ b/common/ipc/service.hpp @@ -143,7 +143,7 @@ public: */ template std::shared_ptr callSync(const MethodID methodID, - const FileDescriptor peerFD, + const PeerID peerID, const std::shared_ptr& data, unsigned int timeoutMS = 500); @@ -158,7 +158,7 @@ public: */ template void callAsync(const MethodID methodID, - const FileDescriptor peerFD, + const PeerID peerID, const std::shared_ptr& data, const typename ResultHandler::type& resultCallback); @@ -204,26 +204,26 @@ void Service::setSignalHandler(const MethodID methodID, template std::shared_ptr Service::callSync(const MethodID methodID, - const FileDescriptor peerFD, + const PeerID peerID, const std::shared_ptr& data, unsigned int timeoutMS) { LOGS("Service callSync, methodID: " << methodID - << ", peerFD: " << peerFD + << ", peerID: " << peerID << ", timeoutMS: " << timeoutMS); - return mProcessor.callSync(methodID, peerFD, data, timeoutMS); + return mProcessor.callSync(methodID, peerID, data, timeoutMS); } template void Service::callAsync(const MethodID methodID, - const FileDescriptor peerFD, + const PeerID peerID, const std::shared_ptr& data, const typename ResultHandler::type& resultCallback) { - LOGS("Service callAsync, methodID: " << methodID << ", peerFD: " << peerFD); + LOGS("Service callAsync, methodID: " << methodID << ", peerID: " << peerID); mProcessor.callAsync(methodID, - peerFD, + peerID, data, resultCallback); } diff --git a/common/ipc/types.cpp b/common/ipc/types.cpp index a73a612..9854e0e 100644 --- a/common/ipc/types.cpp +++ b/common/ipc/types.cpp @@ -34,6 +34,7 @@ namespace ipc { namespace { std::atomic gLastMessageID(0); +std::atomic gLastPeerID(0); } // namespace MessageID getNextMessageID() @@ -41,6 +42,10 @@ MessageID getNextMessageID() return ++gLastMessageID; } +PeerID getNextPeerID() +{ + return ++gLastPeerID; +} } // namespace ipc diff --git a/common/ipc/types.hpp b/common/ipc/types.hpp index b5411b3..fe132ec 100644 --- a/common/ipc/types.hpp +++ b/common/ipc/types.hpp @@ -22,11 +22,10 @@ * @brief Types definitions */ -#ifndef COMMON_IPC_HANDLERS_HPP -#define COMMON_IPC_HANDLERS_HPP +#ifndef COMMON_IPC_TYPES_HPP +#define COMMON_IPC_TYPES_HPP #include "ipc/exception.hpp" - #include #include #include @@ -37,26 +36,28 @@ namespace ipc { typedef int FileDescriptor; typedef unsigned int MethodID; typedef unsigned int MessageID; +typedef unsigned int PeerID; -typedef std::function PeerCallback; +typedef std::function PeerCallback; typedef std::function& data)> SerializeCallback; typedef std::function(int fd)> ParseCallback; MessageID getNextMessageID(); +PeerID getNextPeerID(); template struct MethodHandler { - typedef std::function(FileDescriptor peerFD, + typedef std::function(PeerID peerID, std::shared_ptr& data)> type; }; template struct SignalHandler { - typedef std::function& data)> type; }; } // namespace ipc } // namespace vasum -#endif // COMMON_IPC_HANDLERS_HPP +#endif // COMMON_IPC_TYPES_HPP diff --git a/tests/unit_tests/ipc/ut-ipc.cpp b/tests/unit_tests/ipc/ut-ipc.cpp index 5408735..cb475f1 100644 --- a/tests/unit_tests/ipc/ut-ipc.cpp +++ b/tests/unit_tests/ipc/ut-ipc.cpp @@ -136,33 +136,33 @@ struct ThrowOnAcceptData { } }; -std::shared_ptr returnEmptyCallback(const FileDescriptor, std::shared_ptr&) +std::shared_ptr returnEmptyCallback(const PeerID, std::shared_ptr&) { return std::make_shared(); } -std::shared_ptr returnDataCallback(const FileDescriptor, std::shared_ptr&) +std::shared_ptr returnDataCallback(const PeerID, std::shared_ptr&) { return std::make_shared(1); } -std::shared_ptr echoCallback(const FileDescriptor, std::shared_ptr& data) +std::shared_ptr echoCallback(const PeerID, std::shared_ptr& data) { return std::make_shared(data->intVal); } -std::shared_ptr longEchoCallback(const FileDescriptor, std::shared_ptr& data) +std::shared_ptr longEchoCallback(const PeerID, std::shared_ptr& data) { std::this_thread::sleep_for(std::chrono::milliseconds(LONG_OPERATION_TIME)); return std::make_shared(data->intVal); } -FileDescriptor connect(Service& s, Client& c, bool isServiceGlib = false, bool isClientGlib = false) +PeerID connect(Service& s, Client& c, bool isServiceGlib = false, bool isClientGlib = false) { - // Connects the Client to the Service and returns Clients FileDescriptor - ValueLatch peerFDLatch; - auto newPeerCallback = [&peerFDLatch](const FileDescriptor newFD) { - peerFDLatch.set(newFD); + // Connects the Client to the Service and returns Clients PeerID + ValueLatch peerIDLatch; + auto newPeerCallback = [&peerIDLatch](const PeerID newID, const FileDescriptor) { + peerIDLatch.set(newID); }; s.setNewPeerCallback(newPeerCallback); @@ -173,18 +173,18 @@ FileDescriptor connect(Service& s, Client& c, bool isServiceGlib = false, bool i c.start(isClientGlib); - FileDescriptor peerFD = peerFDLatch.get(TIMEOUT); + PeerID peerID = peerIDLatch.get(TIMEOUT); s.setNewPeerCallback(nullptr); - BOOST_REQUIRE_NE(peerFD, 0); - return peerFD; + BOOST_REQUIRE_NE(peerID, 0); + return peerID; } -FileDescriptor connectServiceGSource(Service& s, Client& c) +PeerID connectServiceGSource(Service& s, Client& c) { return connect(s, c, true, false); } -FileDescriptor connectClientGSource(Service& s, Client& c) +PeerID connectClientGSource(Service& s, Client& c) { return connect(s, c, false, true); } @@ -197,10 +197,10 @@ void testEcho(Client& c, const MethodID methodID) BOOST_CHECK_EQUAL(recvData->intVal, sentData->intVal); } -void testEcho(Service& s, const MethodID methodID, const FileDescriptor peerFD) +void testEcho(Service& s, const MethodID methodID, const PeerID peerID) { std::shared_ptr sentData(new SendData(56)); - std::shared_ptr recvData = s.callSync(methodID, peerFD, sentData, TIMEOUT); + std::shared_ptr recvData = s.callSync(methodID, peerID, sentData, TIMEOUT); BOOST_REQUIRE(recvData); BOOST_CHECK_EQUAL(recvData->intVal, sentData->intVal); } @@ -244,17 +244,17 @@ BOOST_AUTO_TEST_CASE(ClientAddRemoveMethod) c.setMethodHandler(1, returnEmptyCallback); c.setMethodHandler(1, returnDataCallback); - FileDescriptor peerFD = connect(s, c); + PeerID peerID = connect(s, c); c.setMethodHandler(1, echoCallback); c.setMethodHandler(2, returnDataCallback); - testEcho(s, 1, peerFD); + testEcho(s, 1, peerID); c.removeMethod(1); c.removeMethod(2); - BOOST_CHECK_THROW(testEcho(s, 1, peerFD), IPCException); + BOOST_CHECK_THROW(testEcho(s, 1, peerID), IPCException); } BOOST_AUTO_TEST_CASE(ServiceStartStop) @@ -333,10 +333,10 @@ BOOST_AUTO_TEST_CASE(SyncServiceToClientEcho) Service s(socketPath); Client c(socketPath); c.setMethodHandler(1, echoCallback); - FileDescriptor peerFD = connect(s, c); + PeerID peerID = connect(s, c); std::shared_ptr sentData(new SendData(56)); - std::shared_ptr recvData = s.callSync(1, peerFD, sentData); + std::shared_ptr recvData = s.callSync(1, peerID, sentData); BOOST_REQUIRE(recvData); BOOST_CHECK_EQUAL(recvData->intVal, sentData->intVal); } @@ -372,14 +372,14 @@ BOOST_AUTO_TEST_CASE(AsyncServiceToClientEcho) Service s(socketPath); Client c(socketPath); c.setMethodHandler(1, echoCallback); - FileDescriptor peerFD = connect(s, c); + PeerID peerID = connect(s, c); // Async call auto dataBack = [&recvDataLatch](Result && r) { recvDataLatch.set(r.get()); }; - s.callAsync(1, peerFD, sentData, dataBack); + s.callAsync(1, peerID, sentData, dataBack); // Wait for the response std::shared_ptr recvData(recvDataLatch.get(TIMEOUT)); @@ -431,7 +431,7 @@ BOOST_AUTO_TEST_CASE(DisconnectedPeerError) ValueLatch> retStatusLatch; Service s(socketPath); - auto method = [](const FileDescriptor, std::shared_ptr&) { + auto method = [](const PeerID, std::shared_ptr&) { return std::shared_ptr(new SendData(1)); }; @@ -462,7 +462,7 @@ BOOST_AUTO_TEST_CASE(DisconnectedPeerError) BOOST_AUTO_TEST_CASE(ReadTimeout) { Service s(socketPath); - auto longEchoCallback = [](const FileDescriptor, std::shared_ptr& data) { + auto longEchoCallback = [](const PeerID, std::shared_ptr& data) { return std::shared_ptr(new LongSendData(data->intVal, LONG_OPERATION_TIME)); }; s.setMethodHandler(1, longEchoCallback); @@ -506,14 +506,15 @@ BOOST_AUTO_TEST_CASE(AddSignalInRuntime) Client c(socketPath); connect(s, c); - auto handlerA = [&recvDataLatchA](const FileDescriptor, std::shared_ptr& data) { + auto handlerA = [&recvDataLatchA](const PeerID, std::shared_ptr& data) { recvDataLatchA.set(data); }; - auto handlerB = [&recvDataLatchB](const FileDescriptor, std::shared_ptr& data) { + auto handlerB = [&recvDataLatchB](const PeerID, std::shared_ptr& data) { recvDataLatchB.set(data); }; + LOGH("SETTING SIGNAAALS"); c.setSignalHandler(1, handlerA); c.setSignalHandler(2, handlerB); @@ -541,11 +542,11 @@ BOOST_AUTO_TEST_CASE(AddSignalOffline) Service s(socketPath); Client c(socketPath); - auto handlerA = [&recvDataLatchA](const FileDescriptor, std::shared_ptr& data) { + auto handlerA = [&recvDataLatchA](const PeerID, std::shared_ptr& data) { recvDataLatchA.set(data); }; - auto handlerB = [&recvDataLatchB](const FileDescriptor, std::shared_ptr& data) { + auto handlerB = [&recvDataLatchB](const PeerID, std::shared_ptr& data) { recvDataLatchB.set(data); }; @@ -575,7 +576,7 @@ BOOST_AUTO_TEST_CASE(ServiceGSource) utils::Latch l; ScopedGlibLoop loop; - auto signalHandler = [&l](const FileDescriptor, std::shared_ptr&) { + auto signalHandler = [&l](const PeerID, std::shared_ptr&) { l.set(); }; @@ -602,7 +603,7 @@ BOOST_AUTO_TEST_CASE(ClientGSource) utils::Latch l; ScopedGlibLoop loop; - auto signalHandler = [&l](const FileDescriptor, std::shared_ptr&) { + auto signalHandler = [&l](const PeerID, std::shared_ptr&) { l.set(); }; @@ -614,9 +615,9 @@ BOOST_AUTO_TEST_CASE(ClientGSource) c.setMethodHandler(1, echoCallback); c.setSignalHandler(2, signalHandler); - FileDescriptor peerFD = connectClientGSource(s, c); + PeerID peerID = connectClientGSource(s, c); - testEcho(s, 1, peerFD); + testEcho(s, 1, peerID); auto data = std::make_shared(1); s.signal(2, data); @@ -633,7 +634,7 @@ BOOST_AUTO_TEST_CASE(UsersError) Client c(socketPath); auto clientID = connect(s, c); - auto throwingMethodHandler = [&](const FileDescriptor, std::shared_ptr&) -> std::shared_ptr { + auto throwingMethodHandler = [&](const PeerID, std::shared_ptr&) -> std::shared_ptr { throw IPCUserException(TEST_ERROR_CODE, TEST_ERROR_MESSAGE); }; -- 2.7.4 From 44bc3f2ad37cbad8df3d1cb59a7c92ead26910ae Mon Sep 17 00:00:00 2001 From: Mateusz Malicki Date: Tue, 27 Jan 2015 16:53:35 +0100 Subject: [PATCH 02/16] Add remove and list to vasum-server and vasum-client [Bug/Feature] Ability to list and remove provision [Cause] N/A [Solution] N/A [Verification] Build, run tests Change-Id: I57783a0b79466ef60d781e6206b92fb266fe5f38 --- client/vasum-client-impl.cpp | 99 +++++++++++++++++++++++++++++++---- client/vasum-client-impl.hpp | 19 +++++-- client/vasum-client.cpp | 19 +++++-- client/vasum-client.h | 29 ++++++++++ server/host-connection.cpp | 31 +++++++++++ server/host-connection.hpp | 19 +++++++ server/host-dbus-definitions.hpp | 13 +++++ server/zone.cpp | 10 ++++ server/zone.hpp | 12 ++++- server/zones-manager.cpp | 70 ++++++++++++++++++++++--- server/zones-manager.hpp | 5 ++ tests/unit_tests/client/ut-client.cpp | 20 +++++++ 12 files changed, 320 insertions(+), 26 deletions(-) diff --git a/client/vasum-client-impl.cpp b/client/vasum-client-impl.cpp index 0af5269..9ca5de5 100644 --- a/client/vasum-client-impl.cpp +++ b/client/vasum-client-impl.cpp @@ -585,14 +585,29 @@ VsmStatus Client::vsm_declare_file(const char* zone, VsmFileType type, const char *path, int32_t flags, - mode_t mode) noexcept + mode_t mode, + VsmString* id) noexcept { assert(path); + GVariant* out = NULL; GVariant* args_in = g_variant_new("(sisii)", zone, type, path, flags, mode); - return callMethod(ZONE_INTERFACE, - api::host::METHOD_DECLARE_FILE, - args_in); + VsmStatus ret = callMethod(HOST_INTERFACE, + api::host::METHOD_DECLARE_FILE, + args_in, + "(s)", + &out); + if (ret != VSMCLIENT_SUCCESS) { + return ret; + } + GVariant* unpacked; + if (id != NULL) { + g_variant_get(out, "(*)", &unpacked); + toBasic(unpacked, id); + g_variant_unref(unpacked); + } + g_variant_unref(out); + return ret; } VsmStatus Client::vsm_declare_mount(const char *source, @@ -600,7 +615,8 @@ VsmStatus Client::vsm_declare_mount(const char *source, const char *target, const char *type, uint64_t flags, - const char *data) noexcept + const char *data, + VsmString* id) noexcept { assert(source); assert(target); @@ -609,22 +625,83 @@ VsmStatus Client::vsm_declare_mount(const char *source, data = ""; } + GVariant* out = NULL; GVariant* args_in = g_variant_new("(ssssts)", source, zone, target, type, flags, data); - return callMethod(ZONE_INTERFACE, - api::host::METHOD_DECLARE_MOUNT, - args_in); + VsmStatus ret = callMethod(HOST_INTERFACE, + api::host::METHOD_DECLARE_MOUNT, + args_in, + "(s)", + &out); + if (ret != VSMCLIENT_SUCCESS) { + return ret; + } + GVariant* unpacked; + if (id != NULL) { + g_variant_get(out, "(*)", &unpacked); + toBasic(unpacked, id); + g_variant_unref(unpacked); + } + g_variant_unref(out); + return ret; } VsmStatus Client::vsm_declare_link(const char *source, const char* zone, - const char *target) noexcept + const char *target, + VsmString* id) noexcept { assert(source); assert(target); + GVariant* out = NULL; GVariant* args_in = g_variant_new("(sss)", source, zone, target); - return callMethod(ZONE_INTERFACE, - api::host::METHOD_DECLARE_LINK, + VsmStatus ret = callMethod(HOST_INTERFACE, + api::host::METHOD_DECLARE_LINK, + args_in, + "(s)", + &out); + if (ret != VSMCLIENT_SUCCESS) { + return ret; + } + GVariant* unpacked; + if (id != NULL) { + g_variant_get(out, "(*)", &unpacked); + toBasic(unpacked, id); + g_variant_unref(unpacked); + } + g_variant_unref(out); + return ret; +} + +VsmStatus Client::vsm_list_declarations(const char* zone, VsmArrayString* declarations) +{ + assert(declarations); + + GVariant* out = NULL; + GVariant* args_in = g_variant_new("(s)", zone); + VsmStatus ret = callMethod(HOST_INTERFACE, + api::host::METHOD_GET_DECLARATIONS, + args_in, + "(as)", + &out); + if (ret != VSMCLIENT_SUCCESS) { + return ret; + } + GVariant* unpacked; + g_variant_get(out, "(*)", &unpacked); + toArray(unpacked, declarations); + g_variant_unref(unpacked); + g_variant_unref(out); + return ret; +} + +VsmStatus Client::vsm_remove_declaration(const char* zone, VsmString declaration) +{ + assert(declaration); + + GVariant* args_in = g_variant_new("(ss)", zone, declaration); + return callMethod(HOST_INTERFACE, + api::host::METHOD_REMOVE_DECLARATION, args_in); } diff --git a/client/vasum-client-impl.hpp b/client/vasum-client-impl.hpp index f545d77..b5acee7 100644 --- a/client/vasum-client-impl.hpp +++ b/client/vasum-client-impl.hpp @@ -254,7 +254,8 @@ public: VsmFileType type, const char* path, int32_t flags, - mode_t mode) noexcept; + mode_t mode, + VsmString* id) noexcept; /** * @see ::vsm_declare_mount @@ -264,13 +265,25 @@ public: const char* target, const char* type, uint64_t flags, - const char* data) noexcept; + const char* data, + VsmString* id) noexcept; /** * @see ::vsm_declare_link */ VsmStatus vsm_declare_link(const char* source, const char* zone, - const char* target) noexcept; + const char* target, + VsmString* id) noexcept; + + /** + * @see ::vsm_list_declarations + */ + VsmStatus vsm_list_declarations(const char* zone, VsmArrayString* declarations); + + /** + * @see ::vsm_remove_declaration + */ + VsmStatus vsm_remove_declaration(const char* zone, VsmString declaration); /** * @see ::vsm_notify_active_zone diff --git a/client/vasum-client.cpp b/client/vasum-client.cpp index 00a4dfb..5310b42 100644 --- a/client/vasum-client.cpp +++ b/client/vasum-client.cpp @@ -279,7 +279,7 @@ API VsmStatus vsm_declare_file(VsmClient client, int32_t flags, mode_t mode) { - return getClient(client).vsm_declare_file(zone, type, path, flags, mode); + return getClient(client).vsm_declare_file(zone, type, path, flags, mode, NULL); } @@ -291,7 +291,7 @@ API VsmStatus vsm_declare_mount(VsmClient client, uint64_t flags, const char* data) { - return getClient(client).vsm_declare_mount(source, zone, target, type, flags, data); + return getClient(client).vsm_declare_mount(source, zone, target, type, flags, data, NULL); } API VsmStatus vsm_declare_link(VsmClient client, @@ -299,9 +299,22 @@ API VsmStatus vsm_declare_link(VsmClient client, const char* zone, const char* target) { - return getClient(client).vsm_declare_link(source, zone, target); + return getClient(client).vsm_declare_link(source, zone, target, NULL); } +API VsmStatus vsm_list_declarations(VsmClient client, + const char* zone, + VsmArrayString* declarations) +{ + return getClient(client).vsm_list_declarations(zone, declarations); +} + +API VsmStatus vsm_remove_declaration(VsmClient client, + const char* zone, + VsmString declaration) +{ + return getClient(client).vsm_remove_declaration(zone, declaration); +} API VsmStatus vsm_notify_active_zone(VsmClient client, const char* application, diff --git a/client/vasum-client.h b/client/vasum-client.h index bf15f25..6793722 100644 --- a/client/vasum-client.h +++ b/client/vasum-client.h @@ -653,6 +653,35 @@ VsmStatus vsm_declare_link(VsmClient client, const char* zone, const char *target); +/** + * Get all declarations + * + * Gets all declarations of resourcies + * (@see ::vsm_declare_link, @see ::vsm_declare_mount, @see ::vsm_declare_linki) + * + * @param[in] client vasum-server's client + * @param[in] zone zone id + * @param[out] declarations array of declarations id + * @return status of this function call + */ +VsmStatus vsm_list_declarations(VsmClient client, + const char* zone, + VsmArrayString* declarations); + +/** + * Remove declaration + * + * Removes given declaration by its id (@see ::vsm_list_declarations) + * + * @param[in] client vasum-server's client + * @param[in] zone zone id + * @param[in] declaration declaration id + * @return status of this function call + */ +VsmStatus vsm_remove_declaration(VsmClient client, + const char* zone, + VsmString declaration); + /** @} Host API */ diff --git a/server/host-connection.cpp b/server/host-connection.cpp index db6130f..a90a47c 100644 --- a/server/host-connection.cpp +++ b/server/host-connection.cpp @@ -145,6 +145,16 @@ void HostConnection::setDeclareLinkCallback(const DeclareLinkCallback& callback) mDeclareLinkCallback = callback; } +void HostConnection::setGetDeclarationsCallback(const GetDeclarationsCallback& callback) +{ + mGetDeclarationsCallback = callback; +} + +void HostConnection::setRemoveDeclarationCallback(const RemoveDeclarationCallback& callback) +{ + mRemoveDeclarationCallback = callback; +} + void HostConnection::setSetActiveZoneCallback(const SetActiveZoneCallback& callback) { mSetActiveZoneCallback = callback; @@ -319,6 +329,27 @@ void HostConnection::onMessageCall(const std::string& objectPath, return; } + if (methodName == api::host::METHOD_GET_DECLARATIONS) { + const gchar* zone; + g_variant_get(parameters, "(&s)", &zone); + + if (mGetDeclarationsCallback) { + mGetDeclarationsCallback(zone, result); + } + return; + } + + if (methodName == api::host::METHOD_REMOVE_DECLARATION) { + const gchar* zone; + const gchar* declarationId; + g_variant_get(parameters, "(&s&s)", &zone, &declarationId); + + if (mRemoveDeclarationCallback) { + mRemoveDeclarationCallback(zone, declarationId, result); + } + return; + } + if (methodName == api::host::METHOD_CREATE_ZONE) { const gchar* id = NULL; g_variant_get(parameters, "(&s)", &id); diff --git a/server/host-connection.hpp b/server/host-connection.hpp index db8cf34..39708ad 100644 --- a/server/host-connection.hpp +++ b/server/host-connection.hpp @@ -82,6 +82,13 @@ public: )> DeclareLinkCallback; typedef std::function GetDeclarationsCallback; + typedef std::function RemoveDeclarationCallback; + typedef std::function SetActiveZoneCallback; typedef std::function" " " + " " " " " " " " @@ -97,11 +100,21 @@ const std::string DEFINITION = " " " " " " + " " " " " " " " " " " " + " " + " " + " " + " " + " " + " " + " " + " " + " " " " " " " " diff --git a/server/zone.cpp b/server/zone.cpp index c3f6991..e7ea3d6 100644 --- a/server/zone.cpp +++ b/server/zone.cpp @@ -404,4 +404,14 @@ std::string Zone::declareLink(const std::string& source, return mProvision->declareLink(source, target); } +std::vector Zone::getDeclarations() const +{ + return mProvision->list(); +} + +void Zone::removeDeclaration(const std::string& declarationId) +{ + mProvision->remove(declarationId); +} + } // namespace vasum diff --git a/server/zone.hpp b/server/zone.hpp index 6105209..ab24615 100644 --- a/server/zone.hpp +++ b/server/zone.hpp @@ -249,7 +249,17 @@ public: std::string declareLink(const std::string& source, const std::string& target); - /** + /** + * Gets all declarations + */ + std::vector getDeclarations() const; + + /** + * Remove declaration + */ + void removeDeclaration(const std::string& declarationId); + + /** * Get zone root path */ std::string getRootPath() const; diff --git a/server/zones-manager.cpp b/server/zones-manager.cpp index f554bdc..34e1531 100644 --- a/server/zones-manager.cpp +++ b/server/zones-manager.cpp @@ -171,6 +171,12 @@ ZonesManager::ZonesManager(const std::string& configPath) mHostConnection.setDeclareLinkCallback(bind(&ZonesManager::handleDeclareLinkCall, this, _1, _2, _3, _4)); + mHostConnection.setGetDeclarationsCallback(bind(&ZonesManager::handleGetDeclarationsCall, + this, _1, _2)); + + mHostConnection.setRemoveDeclarationCallback(bind(&ZonesManager::handleRemoveDeclarationCall, + this, _1, _2, _3)); + mHostConnection.setSetActiveZoneCallback(bind(&ZonesManager::handleSetActiveZoneCall, this, _1, _2)); @@ -725,7 +731,7 @@ void ZonesManager::handleGetZoneDbuses(dbus::MethodResultBuilder::Pointer result entries.push_back(entry); } GVariant* dict = g_variant_new_array(G_VARIANT_TYPE("{ss}"), entries.data(), entries.size()); - result->set(g_variant_new("(*)", dict)); + result->set(g_variant_new("(@a{ss})", dict)); } void ZonesManager::handleDbusStateChanged(const std::string& zoneId, @@ -746,7 +752,7 @@ void ZonesManager::handleGetZoneIdsCall(dbus::MethodResultBuilder::Pointer resul GVariant* array = g_variant_new_array(G_VARIANT_TYPE("s"), zoneIds.data(), zoneIds.size()); - result->set(g_variant_new("(*)", array)); + result->set(g_variant_new("(@as)", array)); } void ZonesManager::handleGetActiveZoneIdCall(dbus::MethodResultBuilder::Pointer result) @@ -804,8 +810,8 @@ void ZonesManager::handleDeclareFileCall(const std::string& zone, try { Lock lock(mMutex); - at(mZones, zone).declareFile(type, path, flags, mode); - result->setVoid(); + const std::string id = at(mZones, zone).declareFile(type, path, flags, mode); + result->set(g_variant_new("(s)", id.c_str())); } catch (const std::out_of_range&) { LOGE("No zone with id=" << zone); result->setError(api::ERROR_INVALID_ID, "No such zone id"); @@ -828,8 +834,8 @@ void ZonesManager::handleDeclareMountCall(const std::string& source, try { Lock lock(mMutex); - at(mZones, zone).declareMount(source, target, type, flags, data); - result->setVoid(); + const std::string id = at(mZones, zone).declareMount(source, target, type, flags, data); + result->set(g_variant_new("(s)", id.c_str())); } catch (const std::out_of_range&) { LOGE("No zone with id=" << zone); result->setError(api::ERROR_INVALID_ID, "No such zone id"); @@ -848,8 +854,8 @@ void ZonesManager::handleDeclareLinkCall(const std::string& source, try { Lock lock(mMutex); - at(mZones, zone).declareLink(source, target); - result->setVoid(); + const std::string id = at(mZones, zone).declareLink(source, target); + result->set(g_variant_new("(s)", id.c_str())); } catch (const std::out_of_range&) { LOGE("No zone with id=" << zone); result->setError(api::ERROR_INVALID_ID, "No such zone id"); @@ -859,6 +865,54 @@ void ZonesManager::handleDeclareLinkCall(const std::string& source, } } +void ZonesManager::handleGetDeclarationsCall(const std::string& zone, + dbus::MethodResultBuilder::Pointer result) +{ + LOGI("GetDeclarations call Id=" << zone); + try { + Lock lock(mMutex); + + std::vector declarations = at(mZones, zone).getDeclarations(); + + std::vector out; + for (auto declaration : declarations) { + out.push_back(g_variant_new_string(declaration.c_str())); + } + + GVariant* array = g_variant_new_array(G_VARIANT_TYPE("s"), + out.data(), + out.size()); + result->set(g_variant_new("(@as)", array)); + } catch (const std::out_of_range&) { + LOGE("No zone with id=" << zone); + result->setError(api::ERROR_INVALID_ID, "No such zone id"); + } catch (const VasumException& ex) { + LOGE(ex.what()); + result->setError(api::ERROR_INTERNAL, ex.what()); + } + +} + +void ZonesManager::handleRemoveDeclarationCall(const std::string& zone, + const std::string& declarationId, + dbus::MethodResultBuilder::Pointer result) +{ + LOGI("RemoveDeclaration call Id=" << zone); + try { + Lock lock(mMutex); + + at(mZones, zone).removeDeclaration(declarationId); + + result->setVoid(); + } catch (const std::out_of_range&) { + LOGE("No zone with id=" << zone); + result->setError(api::ERROR_INVALID_ID, "No such zone id"); + } catch (const VasumException& ex) { + LOGE(ex.what()); + result->setError(api::ERROR_INTERNAL, ex.what()); + } +} + void ZonesManager::handleSetActiveZoneCall(const std::string& id, dbus::MethodResultBuilder::Pointer result) { diff --git a/server/zones-manager.hpp b/server/zones-manager.hpp index 740e074..9ede4e9 100644 --- a/server/zones-manager.hpp +++ b/server/zones-manager.hpp @@ -174,6 +174,11 @@ private: const std::string& zone, const std::string& target, dbus::MethodResultBuilder::Pointer result); + void handleGetDeclarationsCall(const std::string& zone, + dbus::MethodResultBuilder::Pointer result); + void handleRemoveDeclarationCall(const std::string& zone, + const std::string& declarationId, + dbus::MethodResultBuilder::Pointer result); void handleSetActiveZoneCall(const std::string& id, dbus::MethodResultBuilder::Pointer result); void handleCreateZoneCall(const std::string& id, diff --git a/tests/unit_tests/client/ut-client.cpp b/tests/unit_tests/client/ut-client.cpp index 49e18d2..a188a9d 100644 --- a/tests/unit_tests/client/ut-client.cpp +++ b/tests/unit_tests/client/ut-client.cpp @@ -394,4 +394,24 @@ BOOST_AUTO_TEST_CASE(GrantRevokeTest) vsm_client_free(client); } +BOOST_AUTO_TEST_CASE(ProvisionTest) +{ + VsmClient client = vsm_client_create(); + BOOST_REQUIRE_EQUAL(VSMCLIENT_SUCCESS, vsm_connect(client)); + const std::string zone = cm.getRunningForegroundZoneId(); + VsmArrayString declarations; + BOOST_REQUIRE_EQUAL(VSMCLIENT_SUCCESS, vsm_list_declarations(client, zone.c_str(), &declarations)); + BOOST_REQUIRE(declarations != NULL && declarations[0] == NULL); + vsm_array_string_free(declarations); + BOOST_REQUIRE_EQUAL(VSMCLIENT_SUCCESS, vsm_declare_link(client, "/tmp/fake", zone.c_str(), "/tmp/fake/")); + BOOST_REQUIRE_EQUAL(VSMCLIENT_SUCCESS, vsm_list_declarations(client, zone.c_str(), &declarations)); + BOOST_REQUIRE(declarations != NULL && declarations[0] != NULL && declarations[1] == NULL); + BOOST_CHECK_EQUAL(VSMCLIENT_SUCCESS, vsm_remove_declaration(client, zone.c_str(), declarations[0])); + vsm_array_string_free(declarations); + BOOST_CHECK_EQUAL(VSMCLIENT_SUCCESS, vsm_list_declarations(client, zone.c_str(), &declarations)); + BOOST_CHECK(declarations != NULL && declarations[0] == NULL); + vsm_array_string_free(declarations); + vsm_client_free(client); +} + BOOST_AUTO_TEST_SUITE_END() -- 2.7.4 From 3fba1ebb9ce6503b15605e6c0d1d282109146822 Mon Sep 17 00:00:00 2001 From: Piotr Bartosiewicz Date: Fri, 6 Feb 2015 12:49:43 +0100 Subject: [PATCH 03/16] Code cleanup [Bug/Feature] N/A [Cause] N/A [Solution] N/A [Verification] Build, run tests Change-Id: I8911fcc2e51bd14fa94eac6d75e655ba1ce275d8 --- common/ipc/internals/processor.hpp | 2 +- common/ipc/internals/socket.cpp | 4 +- common/ipc/internals/socket.hpp | 9 ++- common/lxc/zone.cpp | 4 +- common/utils/fs.cpp | 20 +++--- server/zone-provision.cpp | 4 +- server/zones-manager.cpp | 123 +++++++++++++++++-------------------- server/zones-manager.hpp | 2 + 8 files changed, 83 insertions(+), 85 deletions(-) diff --git a/common/ipc/internals/processor.hpp b/common/ipc/internals/processor.hpp index 604d863..b890cda 100644 --- a/common/ipc/internals/processor.hpp +++ b/common/ipc/internals/processor.hpp @@ -219,7 +219,7 @@ public: * Synchronous method call. * * @param methodID API dependent id of the method - * @param peerD id of the peer + * @param peerID id of the peer * @param data data to sent * @param timeoutMS how long to wait for the return value before throw * @tparam SentDataType data type to send diff --git a/common/ipc/internals/socket.cpp b/common/ipc/internals/socket.cpp index b12dfa0..2469af6 100644 --- a/common/ipc/internals/socket.cpp +++ b/common/ipc/internals/socket.cpp @@ -51,13 +51,13 @@ Socket::Socket(int socketFD) { } -Socket::Socket(Socket&& socket) +Socket::Socket(Socket&& socket) noexcept : mFD(socket.mFD) { socket.mFD = -1; } -Socket::~Socket() +Socket::~Socket() noexcept { try { ipc::close(mFD); diff --git a/common/ipc/internals/socket.hpp b/common/ipc/internals/socket.hpp index 91f0dcd..839afe4 100644 --- a/common/ipc/internals/socket.hpp +++ b/common/ipc/internals/socket.hpp @@ -48,10 +48,13 @@ public: * * @param socketFD socket obtained outside the class. */ - Socket(int socketFD = -1); - Socket(Socket&& socket); - ~Socket(); + explicit Socket(int socketFD = -1); + Socket(Socket&& socket) noexcept; + ~Socket() noexcept; + + Socket(const Socket&) = delete; Socket& operator=(const Socket&) = delete; + Socket& operator=(Socket&&) = delete; /** * @return reference to the socket's file descriptor diff --git a/common/lxc/zone.cpp b/common/lxc/zone.cpp index e4371f8..dc148e4 100644 --- a/common/lxc/zone.cpp +++ b/common/lxc/zone.cpp @@ -316,8 +316,8 @@ bool LxcZone::waitForState(State state, int timeout) bool LxcZone::setRunLevel(int runLevel) { auto callback = [](void* param) -> int { - utils::RunLevel runLevel = *reinterpret_cast(param); - return utils::setRunLevel(runLevel) ? 0 : 1; + utils::RunLevel level = *reinterpret_cast(param); + return utils::setRunLevel(level) ? 0 : 1; }; lxc_attach_options_t options = LXC_ATTACH_OPTIONS_DEFAULT; diff --git a/common/utils/fs.cpp b/common/utils/fs.cpp index 763bdfe..b2260cc 100644 --- a/common/utils/fs.cpp +++ b/common/utils/fs.cpp @@ -363,23 +363,25 @@ bool createDir(const std::string& path, uid_t uid, uid_t gid, boost::filesystem: bool createDirs(const std::string& path, mode_t mode) { - boost::filesystem::perms perms = getPerms(mode); - std::vector dirs; + const boost::filesystem::perms perms = getPerms(mode); + std::vector dirsCreated; fs::path prefix; - fs::path dirPath = fs::path(path); - for (const auto dir : dirPath) { - prefix /= dir; + const fs::path dirPath = fs::path(path); + for (const auto& dirSegment : dirPath) { + prefix /= dirSegment; if (!fs::exists(prefix)) { bool created = createDir(prefix.string(), -1, -1, perms); if (created) { - dirs.push_back(prefix); + dirsCreated.push_back(prefix); } else { LOGE("Failed to create dir"); - for (auto dir = dirs.rbegin(); dir != dirs.rend(); ++dir) { + // undo + for (auto iter = dirsCreated.rbegin(); iter != dirsCreated.rend(); ++iter) { boost::system::error_code errorCode; - fs::remove(*dir, errorCode); + fs::remove(*iter, errorCode); if (errorCode) { - LOGE("Error during cleaning: dir: " << *dir << ", msg: " << errorCode.message()); + LOGE("Error during cleaning: dir: " << *iter + << ", msg: " << errorCode.message()); } } return false; diff --git a/server/zone-provision.cpp b/server/zone-provision.cpp index 861a506..1c542f7 100644 --- a/server/zone-provision.cpp +++ b/server/zone-provision.cpp @@ -71,8 +71,8 @@ std::string ZoneProvision::declareProvision(ZoneProvisioningConfig::Provision&& std::string id = getId(provision); auto it = std::find_if(mProvisioningConfig.provisions.begin(), mProvisioningConfig.provisions.end(), - [&](const ZoneProvisioningConfig::Provision& provision) { - return getId(provision) == id; + [&](const ZoneProvisioningConfig::Provision& existingProvision) { + return getId(existingProvision) == id; }); if (it != mProvisioningConfig.provisions.end()) { LOGE("Can't add provision. It already exists: " << id); diff --git a/server/zones-manager.cpp b/server/zones-manager.cpp index 34e1531..167f9f4 100644 --- a/server/zones-manager.cpp +++ b/server/zones-manager.cpp @@ -106,29 +106,11 @@ Iter circularFindNext(Iter begin, Iter end, Iter current, Predicate pred) } } -std::vector>::iterator find(std::vector>& zones, - const std::string& id) -{ - auto equalId = [&id](const std::unique_ptr& zone) { - return zone->getId() == id; - }; - return std::find_if(zones.begin(), zones.end(), equalId); -} - Zone& get(std::vector>::iterator iter) { return **iter; } -Zone& at(std::vector>& zones, const std::string& id) -{ - auto iter = find(zones, id); - if (iter == zones.end()) { - throw std::out_of_range("id not found"); - } - return get(iter); -} - bool zoneIsRunning(const std::unique_ptr& zone) { return zone->isRunning(); } @@ -240,6 +222,22 @@ ZonesManager::~ZonesManager() LOGD("ZonesManager object destroyed"); } +ZonesManager::Zones::iterator ZonesManager::findZone(const std::string& id) +{ + return std::find_if(mZones.begin(), mZones.end(), [&id](const std::unique_ptr& zone) { + return zone->getId() == id; + }); +} + +Zone& ZonesManager::getZone(const std::string& id) +{ + auto iter = findZone(id); + if (iter == mZones.end()) { + throw std::out_of_range("id not found"); + } + return get(iter); +} + void ZonesManager::saveDynamicConfig() { config::saveToKVStore(mConfig.dbPath, mDynamicConfig, DB_PREFIX); @@ -252,7 +250,7 @@ void ZonesManager::updateDefaultId() LOGT("Keep empty defaultId"); return; } - if (find(mZones, mDynamicConfig.defaultId) != mZones.end()) { + if (findZone(mDynamicConfig.defaultId) != mZones.end()) { LOGT("Keep " << mDynamicConfig.defaultId << " as defaultId"); return; } @@ -300,7 +298,7 @@ void ZonesManager::createZone(const std::string& zoneConfigPath) Lock lock(mMutex); - if (find(mZones, id) != mZones.end()) { + if (findZone(id) != mZones.end()) { throw ZoneOperationException("Zone already exists"); } mZones.push_back(std::move(zone)); @@ -318,7 +316,7 @@ void ZonesManager::destroyZone(const std::string& zoneId) { Lock lock(mMutex); - auto iter = find(mZones, zoneId); + auto iter = findZone(zoneId); if (iter == mZones.end()) { LOGE("Failed to destroy zone " << zoneId << ": no such zone"); throw ZoneOperationException("No such zone"); @@ -344,7 +342,7 @@ void ZonesManager::destroyZone(const std::string& zoneId) void ZonesManager::focus(const std::string& zoneId) { Lock lock(mMutex); - auto iter = find(mZones, zoneId); + auto iter = findZone(zoneId); focusInternal(iter); } @@ -361,29 +359,29 @@ void ZonesManager::focusInternal(Zones::iterator iter) return; } - Zone& zone = get(iter); - std::string zoneId = zone.getId(); + Zone& zoneToFocus = get(iter); + const std::string idToFocus = zoneToFocus.getId(); - if (zoneId == mActiveZoneId) { + if (idToFocus == mActiveZoneId) { return; } - if (!zone.isRunning()) { - LOGE("Can't focus not running zone " << zoneId); + if (!zoneToFocus.isRunning()) { + LOGE("Can't focus not running zone " << idToFocus); assert(false); return; } - LOGI("Focus to: " << zone.getId()); + LOGI("Focus to: " << idToFocus); - if (!zone.activateVT()) { + if (!zoneToFocus.activateVT()) { LOGE("Failed to activate zones VT"); return; } for (auto& zone : mZones) { std::string id = zone->getId(); - if (id == zoneId) { + if (id == idToFocus) { LOGD(id << ": being sent to foreground"); zone->goForeground(); } else { @@ -391,7 +389,7 @@ void ZonesManager::focusInternal(Zones::iterator iter) zone->goBackground(); } } - mActiveZoneId = zoneId; + mActiveZoneId = idToFocus; } void ZonesManager::refocus() @@ -399,25 +397,18 @@ void ZonesManager::refocus() // assume mutex is locked // check if refocus is required - auto oldIter = find(mZones, mActiveZoneId); + auto oldIter = findZone(mActiveZoneId); if (oldIter != mZones.end() && get(oldIter).isRunning()) { return; } // try to refocus to defaultId - auto iter = find(mZones, mDynamicConfig.defaultId); - if (iter != mZones.end() && get(iter).isRunning()) { - // focus to default - focusInternal(iter); - } else { + auto iter = findZone(mDynamicConfig.defaultId); + if (iter == mZones.end() || !get(iter).isRunning()) { // focus to any running or to host if not found - auto iter = std::find_if(mZones.begin(), mZones.end(), zoneIsRunning); - if (iter == mZones.end()) { - focusInternal(mZones.end()); - } else { - focusInternal(iter); - } + iter = std::find_if(mZones.begin(), mZones.end(), zoneIsRunning); } + focusInternal(iter); } void ZonesManager::startAll() @@ -450,7 +441,7 @@ bool ZonesManager::isPaused(const std::string& zoneId) { Lock lock(mMutex); - auto iter = find(mZones, zoneId); + auto iter = findZone(zoneId); if (iter == mZones.end()) { LOGE("No such zone id: " << zoneId); throw ZoneOperationException("No such zone"); @@ -463,7 +454,7 @@ bool ZonesManager::isRunning(const std::string& zoneId) { Lock lock(mMutex); - auto iter = find(mZones, zoneId); + auto iter = findZone(zoneId); if (iter == mZones.end()) { LOGE("No such zone id: " << zoneId); throw ZoneOperationException("No such zone"); @@ -491,7 +482,7 @@ ZonesManager::Zones::iterator ZonesManager::getRunningForegroundZoneIterator() if (mActiveZoneId.empty()) { return mZones.end(); } - auto iter = find(mZones, mActiveZoneId); + auto iter = findZone(mActiveZoneId); if (!get(iter).isRunning()) { // Can zone change its state by itself? // Maybe when it is shut down by itself? TODO check it @@ -505,7 +496,7 @@ ZonesManager::Zones::iterator ZonesManager::getRunningForegroundZoneIterator() ZonesManager::Zones::iterator ZonesManager::getNextToForegroundZoneIterator() { // assume mutex is locked - auto current = find(mZones, mActiveZoneId); + auto current = findZone(mActiveZoneId); if (current == mZones.end()) { // find any running return std::find_if(mZones.begin(), mZones.end(), zoneIsRunning); @@ -564,8 +555,8 @@ void ZonesManager::displayOffHandler(const std::string& /*caller*/) // get config of currently set zone and switch if switchToDefaultAfterTimeout is true Lock lock(mMutex); - auto activeIter = find(mZones, mActiveZoneId); - auto defaultIter = find(mZones, mDynamicConfig.defaultId); + auto activeIter = findZone(mActiveZoneId); + auto defaultIter = findZone(mDynamicConfig.defaultId); if (activeIter != mZones.end() && defaultIter != mZones.end() && @@ -608,14 +599,14 @@ void ZonesManager::handleZoneMoveFileRequest(const std::string& srcZoneId, Lock lock(mMutex); - auto srcIter = find(mZones, srcZoneId); + auto srcIter = findZone(srcZoneId); if (srcIter == mZones.end()) { LOGE("Source zone '" << srcZoneId << "' not found"); return; } Zone& srcZone = get(srcIter); - auto dstIter = find(mZones, dstZoneId); + auto dstIter = findZone(dstZoneId); if (dstIter == mZones.end()) { LOGE("Destination zone '" << dstZoneId << "' not found"); result->set(g_variant_new("(s)", api::zone::FILE_MOVE_DESTINATION_NOT_FOUND.c_str())); @@ -703,7 +694,7 @@ void ZonesManager::handleProxyCall(const std::string& caller, Lock lock(mMutex); - auto targetIter = find(mZones, target); + auto targetIter = findZone(target); if (targetIter == mZones.end()) { LOGE("Target zone '" << target << "' not found"); result->setError(api::ERROR_INVALID_ID, "Unknown proxy call target"); @@ -770,7 +761,7 @@ void ZonesManager::handleGetZoneInfoCall(const std::string& id, Lock lock(mMutex); - auto iter = find(mZones, id); + auto iter = findZone(id); if (iter == mZones.end()) { LOGE("No zone with id=" << id); result->setError(api::ERROR_INVALID_ID, "No such zone id"); @@ -810,7 +801,7 @@ void ZonesManager::handleDeclareFileCall(const std::string& zone, try { Lock lock(mMutex); - const std::string id = at(mZones, zone).declareFile(type, path, flags, mode); + const std::string id = getZone(zone).declareFile(type, path, flags, mode); result->set(g_variant_new("(s)", id.c_str())); } catch (const std::out_of_range&) { LOGE("No zone with id=" << zone); @@ -834,7 +825,7 @@ void ZonesManager::handleDeclareMountCall(const std::string& source, try { Lock lock(mMutex); - const std::string id = at(mZones, zone).declareMount(source, target, type, flags, data); + const std::string id = getZone(zone).declareMount(source, target, type, flags, data); result->set(g_variant_new("(s)", id.c_str())); } catch (const std::out_of_range&) { LOGE("No zone with id=" << zone); @@ -854,7 +845,7 @@ void ZonesManager::handleDeclareLinkCall(const std::string& source, try { Lock lock(mMutex); - const std::string id = at(mZones, zone).declareLink(source, target); + const std::string id = getZone(zone).declareLink(source, target); result->set(g_variant_new("(s)", id.c_str())); } catch (const std::out_of_range&) { LOGE("No zone with id=" << zone); @@ -872,7 +863,7 @@ void ZonesManager::handleGetDeclarationsCall(const std::string& zone, try { Lock lock(mMutex); - std::vector declarations = at(mZones, zone).getDeclarations(); + std::vector declarations = getZone(zone).getDeclarations(); std::vector out; for (auto declaration : declarations) { @@ -901,7 +892,7 @@ void ZonesManager::handleRemoveDeclarationCall(const std::string& zone, try { Lock lock(mMutex); - at(mZones, zone).removeDeclaration(declarationId); + getZone(zone).removeDeclaration(declarationId); result->setVoid(); } catch (const std::out_of_range&) { @@ -920,7 +911,7 @@ void ZonesManager::handleSetActiveZoneCall(const std::string& id, Lock lock(mMutex); - auto iter = find(mZones, id); + auto iter = findZone(id); if (iter == mZones.end()){ LOGE("No zone with id=" << id ); result->setError(api::ERROR_INVALID_ID, "No such zone id"); @@ -1024,7 +1015,7 @@ void ZonesManager::handleCreateZoneCall(const std::string& id, namespace fs = boost::filesystem; // check if zone does not exist - if (find(mZones, id) != mZones.end()) { + if (findZone(id) != mZones.end()) { LOGE("Cannot create " << id << " zone - already exists!"); result->setError(api::ERROR_INVALID_ID, "Already exists"); return; @@ -1120,7 +1111,7 @@ void ZonesManager::handleShutdownZoneCall(const std::string& id, LOGT("Shutdown zone " << id); Lock lock(mMutex); - auto iter = find(mZones, id); + auto iter = findZone(id); if (iter == mZones.end()) { LOGE("Failed to shutdown zone - no such zone id: " << id); result->setError(api::ERROR_INVALID_ID, "No such zone id"); @@ -1149,7 +1140,7 @@ void ZonesManager::handleStartZoneCall(const std::string& id, LOGT("Start zone " << id ); Lock lock(mMutex); - auto iter = find(mZones, id); + auto iter = findZone(id); if (iter == mZones.end()) { LOGE("Failed to start zone - no such zone id: " << id); result->setError(api::ERROR_INVALID_ID, "No such zone id"); @@ -1173,7 +1164,7 @@ void ZonesManager::handleLockZoneCall(const std::string& id, Lock lock(mMutex); - auto iter = find(mZones, id); + auto iter = findZone(id); if (iter == mZones.end()) { LOGE("Failed to lock zone - no such zone id: " << id); result->setError(api::ERROR_INVALID_ID, "No such zone id"); @@ -1207,7 +1198,7 @@ void ZonesManager::handleUnlockZoneCall(const std::string& id, Lock lock(mMutex); - auto iter = find(mZones, id); + auto iter = findZone(id); if (iter == mZones.end()) { LOGE("Failed to unlock zone - no such zone id: " << id); result->setError(api::ERROR_INVALID_ID, "No such zone id"); @@ -1242,7 +1233,7 @@ void ZonesManager::handleGrantDeviceCall(const std::string& id, Lock lock(mMutex); - auto iter = find(mZones, id); + auto iter = findZone(id); if (iter == mZones.end()) { LOGE("Failed to grant device - no such zone id: " << id); result->setError(api::ERROR_INVALID_ID, "No such zone id"); @@ -1282,7 +1273,7 @@ void ZonesManager::handleRevokeDeviceCall(const std::string& id, Lock lock(mMutex); - auto iter = find(mZones, id); + auto iter = findZone(id); if (iter == mZones.end()) { LOGE("Failed to revoke device - no such zone id: " << id); result->setError(api::ERROR_INVALID_ID, "No such zone id"); diff --git a/server/zones-manager.hpp b/server/zones-manager.hpp index 9ede4e9..755bc97 100644 --- a/server/zones-manager.hpp +++ b/server/zones-manager.hpp @@ -123,6 +123,8 @@ private: std::string mActiveZoneId; bool mDetachOnExit; + Zones::iterator findZone(const std::string& id); + Zone& getZone(const std::string& id); Zones::iterator getRunningForegroundZoneIterator(); Zones::iterator getNextToForegroundZoneIterator(); void focusInternal(Zones::iterator iter); -- 2.7.4 From 5ff143397f8038c6c292e00c22a44bca1bfdc9df Mon Sep 17 00:00:00 2001 From: Piotr Bartosiewicz Date: Mon, 26 Jan 2015 11:37:03 +0100 Subject: [PATCH 04/16] Create zone api method support templateName parameter [Bug/Feature] Not implemented create zone parameter [Cause] N/A [Solution] N/A [Verification] Build, run tests Change-Id: I5dff390db6b82927b1f8f300f82212c2a534a571 --- client/vasum-client-impl.cpp | 7 ++----- client/vasum-client.h | 2 +- server/configs/daemon.conf.in | 2 +- server/configs/templates/{template.conf => default.conf} | 0 server/host-connection.cpp | 5 +++-- server/host-connection.hpp | 1 + server/host-dbus-definitions.hpp | 1 + server/zone-config.hpp | 4 ++++ server/zone.cpp | 1 + server/zone.hpp | 1 + server/zones-manager-config.hpp | 6 +++--- server/zones-manager.cpp | 10 +++++++--- server/zones-manager.hpp | 1 + .../client/configs/ut-client/test-dbus-daemon.conf.in | 2 +- tests/unit_tests/server/configs/CMakeLists.txt | 4 ++-- .../unit_tests/server/configs/ut-server/buggy-daemon.conf.in | 2 +- .../unit_tests/server/configs/ut-server/test-daemon.conf.in | 2 +- .../server/configs/ut-zones-manager/buggy-daemon.conf.in | 2 +- .../configs/ut-zones-manager/empty-dbus-daemon.conf.in | 2 +- .../templates/{template.conf.in => default.conf.in} | 0 .../server/configs/ut-zones-manager/test-daemon.conf.in | 2 +- .../server/configs/ut-zones-manager/test-dbus-daemon.conf.in | 2 +- tests/unit_tests/server/ut-zones-manager.cpp | 12 +++++++----- 23 files changed, 42 insertions(+), 29 deletions(-) rename server/configs/templates/{template.conf => default.conf} (100%) rename tests/unit_tests/server/configs/ut-zones-manager/templates/{template.conf.in => default.conf.in} (100%) diff --git a/client/vasum-client-impl.cpp b/client/vasum-client-impl.cpp index 9ca5de5..d27fad3 100644 --- a/client/vasum-client-impl.cpp +++ b/client/vasum-client-impl.cpp @@ -444,12 +444,9 @@ VsmStatus Client::vsm_set_active_zone(const char* id) noexcept VsmStatus Client::vsm_create_zone(const char* id, const char* tname) noexcept { assert(id); - if (tname) { - mStatus = Status(VSMCLIENT_OTHER_ERROR, "Named template isn't implemented"); - return vsm_get_status(); - } + const char* template_name = tname ? tname : "default"; - GVariant* args_in = g_variant_new("(s)", id); + GVariant* args_in = g_variant_new("(ss)", id, template_name); return callMethod(HOST_INTERFACE, api::host::METHOD_CREATE_ZONE, args_in); } diff --git a/client/vasum-client.h b/client/vasum-client.h index 6793722..ba21449 100644 --- a/client/vasum-client.h +++ b/client/vasum-client.h @@ -378,7 +378,7 @@ VsmStatus vsm_set_active_zone(VsmClient client, const char* id); * * @param[in] client vasum-server's client * @param[in] id zone id - * @param[in] tname template name, NULL for default + * @param[in] tname template name, NULL is equivalent to "default" * @return status of this function call */ VsmStatus vsm_create_zone(VsmClient client, const char* id, const char* tname); diff --git a/server/configs/daemon.conf.in b/server/configs/daemon.conf.in index 2040ccf..327e470 100644 --- a/server/configs/daemon.conf.in +++ b/server/configs/daemon.conf.in @@ -3,7 +3,7 @@ "zoneConfigs" : [], "zonesPath" : "${DATA_DIR}/.zones", "zoneImagePath" : "", - "zoneTemplatePath" : "/etc/vasum/templates/template.conf", + "zoneTemplateDir" : "/etc/vasum/templates/", "zoneNewConfigPrefix" : "/var/lib/vasum", "runMountPointPrefix" : "/var/run/zones", "defaultId" : "", diff --git a/server/configs/templates/template.conf b/server/configs/templates/default.conf similarity index 100% rename from server/configs/templates/template.conf rename to server/configs/templates/default.conf diff --git a/server/host-connection.cpp b/server/host-connection.cpp index a90a47c..4a8a2ac 100644 --- a/server/host-connection.cpp +++ b/server/host-connection.cpp @@ -352,10 +352,11 @@ void HostConnection::onMessageCall(const std::string& objectPath, if (methodName == api::host::METHOD_CREATE_ZONE) { const gchar* id = NULL; - g_variant_get(parameters, "(&s)", &id); + const gchar* templateName = NULL; + g_variant_get(parameters, "(&s&s)", &id, &templateName); if (mCreateZoneCallback){ - mCreateZoneCallback(id, result); + mCreateZoneCallback(id, templateName, result); } return; } diff --git a/server/host-connection.hpp b/server/host-connection.hpp index 39708ad..2d029c1 100644 --- a/server/host-connection.hpp +++ b/server/host-connection.hpp @@ -91,6 +91,7 @@ public: dbus::MethodResultBuilder::Pointer result )> SetActiveZoneCallback; typedef std::function CreateZoneCallback; typedef std::function" " " + " " " " " " " " diff --git a/server/zone-config.hpp b/server/zone-config.hpp index f92ca8f..02db1c4 100644 --- a/server/zone-config.hpp +++ b/server/zone-config.hpp @@ -137,6 +137,10 @@ struct ZoneConfig { ) }; +struct ZoneDynamicConfig { + //TODO a place for zone dynamic config (other than provisioning which has its own struct) + CONFIG_REGISTER_EMPTY +}; } // namespace vasum diff --git a/server/zone.cpp b/server/zone.cpp index e7ea3d6..1617bd6 100644 --- a/server/zone.cpp +++ b/server/zone.cpp @@ -79,6 +79,7 @@ Zone::Zone(const utils::Worker::Pointer& worker, mRootPath = (zonePath / fs::path("rootfs")).string(); const std::string dbPrefix = DB_PREFIX + mAdmin->getId(); + config::loadFromKVStoreWithJsonFile(dbPath, zoneConfigPath, mDynamicConfig, dbPrefix); mProvision.reset(new ZoneProvision(mRootPath, zoneConfigPath, dbPath, dbPrefix, mConfig.validLinkPrefixes)); } diff --git a/server/zone.hpp b/server/zone.hpp index ab24615..dbffc22 100644 --- a/server/zone.hpp +++ b/server/zone.hpp @@ -267,6 +267,7 @@ public: private: utils::Worker::Pointer mWorker; ZoneConfig mConfig; + ZoneDynamicConfig mDynamicConfig; std::vector mPermittedToSend; std::vector mPermittedToRecv; std::unique_ptr mConnectionTransport; diff --git a/server/zones-manager-config.hpp b/server/zones-manager-config.hpp index 38c17ac..3ae6e5a 100644 --- a/server/zones-manager-config.hpp +++ b/server/zones-manager-config.hpp @@ -55,9 +55,9 @@ struct ZonesManagerConfig { std::string zoneImagePath; /** - * A path where template configuration files for new zones reside + * A dir where template configuration files for new zones reside */ - std::string zoneTemplatePath; + std::string zoneTemplateDir; /** * Prefix added to a path for new zone configuration files @@ -94,7 +94,7 @@ struct ZonesManagerConfig { dbPath, zonesPath, zoneImagePath, - zoneTemplatePath, + zoneTemplateDir, zoneNewConfigPrefix, lxcTemplatePrefix, availableVTs, diff --git a/server/zones-manager.cpp b/server/zones-manager.cpp index 167f9f4..6acc128 100644 --- a/server/zones-manager.cpp +++ b/server/zones-manager.cpp @@ -163,7 +163,7 @@ ZonesManager::ZonesManager(const std::string& configPath) this, _1, _2)); mHostConnection.setCreateZoneCallback(bind(&ZonesManager::handleCreateZoneCall, - this, _1, _2)); + this, _1, _2, _3)); mHostConnection.setDestroyZoneCallback(bind(&ZonesManager::handleDestroyZoneCall, this, _1, _2)); @@ -998,6 +998,7 @@ int ZonesManager::getVTForNewZone() } void ZonesManager::handleCreateZoneCall(const std::string& id, + const std::string& templateName, dbus::MethodResultBuilder::Pointer result) { if (id.empty()) { @@ -1051,9 +1052,12 @@ void ZonesManager::handleCreateZoneCall(const std::string& id, return true; }; + std::string zoneTemplatePath = utils::createFilePath(mConfig.zoneTemplateDir, + templateName + ".conf"); + try { - LOGI("Generating config from " << mConfig.zoneTemplatePath << " to " << newConfigPath); - generateNewConfig(id, mConfig.zoneTemplatePath, newConfigPath); + LOGI("Generating config from " << zoneTemplatePath << " to " << newConfigPath); + generateNewConfig(id, zoneTemplatePath, newConfigPath); } catch (VasumException& e) { LOGE("Generate config failed: " << e.what()); diff --git a/server/zones-manager.hpp b/server/zones-manager.hpp index 755bc97..99dfa4b 100644 --- a/server/zones-manager.hpp +++ b/server/zones-manager.hpp @@ -184,6 +184,7 @@ private: void handleSetActiveZoneCall(const std::string& id, dbus::MethodResultBuilder::Pointer result); void handleCreateZoneCall(const std::string& id, + const std::string& templateName, dbus::MethodResultBuilder::Pointer result); void handleDestroyZoneCall(const std::string& id, dbus::MethodResultBuilder::Pointer result); diff --git a/tests/unit_tests/client/configs/ut-client/test-dbus-daemon.conf.in b/tests/unit_tests/client/configs/ut-client/test-dbus-daemon.conf.in index debc303..b51ee9a 100644 --- a/tests/unit_tests/client/configs/ut-client/test-dbus-daemon.conf.in +++ b/tests/unit_tests/client/configs/ut-client/test-dbus-daemon.conf.in @@ -6,7 +6,7 @@ "defaultId" : "ut-zones-manager-console1-dbus", "zonesPath" : "/tmp/ut-zones", "zoneImagePath" : "", - "zoneTemplatePath" : "no_need_for_templates_in_this_test", + "zoneTemplateDir" : "no_need_for_templates_in_this_test", "zoneNewConfigPrefix" : "@VSM_TEST_CONFIG_INSTALL_DIR@/client/ut-client/", "runMountPointPrefix" : "", "lxcTemplatePrefix" : "@VSM_TEST_LXC_TEMPLATES_INSTALL_DIR@", diff --git a/tests/unit_tests/server/configs/CMakeLists.txt b/tests/unit_tests/server/configs/CMakeLists.txt index fac9d99..fca8500 100644 --- a/tests/unit_tests/server/configs/CMakeLists.txt +++ b/tests/unit_tests/server/configs/CMakeLists.txt @@ -64,8 +64,8 @@ CONFIGURE_FILE(ut-zones-manager/zones/console3-dbus.conf.in ${CMAKE_BINARY_DIR}/ut-zones-manager/zones/console3-dbus.conf @ONLY) FILE(GLOB manager_zone_CONF_GEN ${CMAKE_BINARY_DIR}/ut-zones-manager/zones/*.conf) -CONFIGURE_FILE(ut-zones-manager/templates/template.conf.in - ${CMAKE_BINARY_DIR}/ut-zones-manager/templates/template.conf @ONLY) +CONFIGURE_FILE(ut-zones-manager/templates/default.conf.in + ${CMAKE_BINARY_DIR}/ut-zones-manager/templates/default.conf @ONLY) FILE(GLOB manager_zone_TEMPLATE_GEN ${CMAKE_BINARY_DIR}/ut-zones-manager/templates/*.conf) diff --git a/tests/unit_tests/server/configs/ut-server/buggy-daemon.conf.in b/tests/unit_tests/server/configs/ut-server/buggy-daemon.conf.in index 8deaa6f..a39bcb4 100644 --- a/tests/unit_tests/server/configs/ut-server/buggy-daemon.conf.in +++ b/tests/unit_tests/server/configs/ut-server/buggy-daemon.conf.in @@ -3,7 +3,7 @@ "zoneConfigs" : ["zones/zone1.conf", "missing/file/path/missing.conf", "zones/zone3.conf"], "zonesPath" : "/tmp/ut-zones", "zoneImagePath" : "", - "zoneTemplatePath" : "no_need_for_templates_in_this_test", + "zoneTemplateDir" : "no_need_for_templates_in_this_test", "zoneNewConfigPrefix" : "@VSM_TEST_CONFIG_INSTALL_DIR@/server/ut-server/", "runMountPointPrefix" : "", "defaultId" : "ut-server-zone1", diff --git a/tests/unit_tests/server/configs/ut-server/test-daemon.conf.in b/tests/unit_tests/server/configs/ut-server/test-daemon.conf.in index 7066583..932ee89 100644 --- a/tests/unit_tests/server/configs/ut-server/test-daemon.conf.in +++ b/tests/unit_tests/server/configs/ut-server/test-daemon.conf.in @@ -3,7 +3,7 @@ "zoneConfigs" : ["zones/zone1.conf", "zones/zone2.conf", "zones/zone3.conf"], "zonesPath" : "/tmp/ut-zones", "zoneImagePath" : "", - "zoneTemplatePath" : "no_need_for_templates_in_this_test", + "zoneTemplateDir" : "no_need_for_templates_in_this_test", "zoneNewConfigPrefix" : "@VSM_TEST_CONFIG_INSTALL_DIR@/server/ut-server/", "runMountPointPrefix" : "", "defaultId" : "ut-server-zone1", diff --git a/tests/unit_tests/server/configs/ut-zones-manager/buggy-daemon.conf.in b/tests/unit_tests/server/configs/ut-zones-manager/buggy-daemon.conf.in index a1fe350..50a95b2 100644 --- a/tests/unit_tests/server/configs/ut-zones-manager/buggy-daemon.conf.in +++ b/tests/unit_tests/server/configs/ut-zones-manager/buggy-daemon.conf.in @@ -5,7 +5,7 @@ "defaultId" : "ut-zones-manager-console1", "zonesPath" : "/tmp/ut-zones", "zoneImagePath" : "", - "zoneTemplatePath" : "@VSM_TEST_CONFIG_INSTALL_DIR@/server/ut-zones-manager/templates/template.conf", + "zoneTemplateDir" : "@VSM_TEST_CONFIG_INSTALL_DIR@/server/ut-zones-manager/templates/", "zoneNewConfigPrefix" : "@VSM_TEST_CONFIG_INSTALL_DIR@/server/ut-zones-manager/", "lxcTemplatePrefix" : "@VSM_TEST_LXC_TEMPLATES_INSTALL_DIR@", "availableVTs" : [], diff --git a/tests/unit_tests/server/configs/ut-zones-manager/empty-dbus-daemon.conf.in b/tests/unit_tests/server/configs/ut-zones-manager/empty-dbus-daemon.conf.in index 21faee1..83b1124 100644 --- a/tests/unit_tests/server/configs/ut-zones-manager/empty-dbus-daemon.conf.in +++ b/tests/unit_tests/server/configs/ut-zones-manager/empty-dbus-daemon.conf.in @@ -4,7 +4,7 @@ "defaultId" : "", "zonesPath" : "/tmp/ut-zones", "zoneImagePath" : "", - "zoneTemplatePath" : "@VSM_TEST_CONFIG_INSTALL_DIR@/server/ut-zones-manager/templates/template.conf", + "zoneTemplateDir" : "@VSM_TEST_CONFIG_INSTALL_DIR@/server/ut-zones-manager/templates/", "zoneNewConfigPrefix" : "/tmp/ut-zones/generated-configs/", "runMountPointPrefix" : "", "lxcTemplatePrefix" : "@VSM_TEST_LXC_TEMPLATES_INSTALL_DIR@", diff --git a/tests/unit_tests/server/configs/ut-zones-manager/templates/template.conf.in b/tests/unit_tests/server/configs/ut-zones-manager/templates/default.conf.in similarity index 100% rename from tests/unit_tests/server/configs/ut-zones-manager/templates/template.conf.in rename to tests/unit_tests/server/configs/ut-zones-manager/templates/default.conf.in diff --git a/tests/unit_tests/server/configs/ut-zones-manager/test-daemon.conf.in b/tests/unit_tests/server/configs/ut-zones-manager/test-daemon.conf.in index 73da57f..d8f1ad4 100644 --- a/tests/unit_tests/server/configs/ut-zones-manager/test-daemon.conf.in +++ b/tests/unit_tests/server/configs/ut-zones-manager/test-daemon.conf.in @@ -5,7 +5,7 @@ "defaultId" : "ut-zones-manager-console1", "zonesPath" : "/tmp/ut-zones", "zoneImagePath" : "", - "zoneTemplatePath" : "@VSM_TEST_CONFIG_INSTALL_DIR@/server/ut-zones-manager/templates/template.conf", + "zoneTemplateDir" : "@VSM_TEST_CONFIG_INSTALL_DIR@/server/ut-zones-manager/templates/", "zoneNewConfigPrefix" : "@VSM_TEST_CONFIG_INSTALL_DIR@/server/ut-zones-manager/", "lxcTemplatePrefix" : "@VSM_TEST_LXC_TEMPLATES_INSTALL_DIR@", "availableVTs" : [], diff --git a/tests/unit_tests/server/configs/ut-zones-manager/test-dbus-daemon.conf.in b/tests/unit_tests/server/configs/ut-zones-manager/test-dbus-daemon.conf.in index 3305552..4f8f6e8 100644 --- a/tests/unit_tests/server/configs/ut-zones-manager/test-dbus-daemon.conf.in +++ b/tests/unit_tests/server/configs/ut-zones-manager/test-dbus-daemon.conf.in @@ -6,7 +6,7 @@ "defaultId" : "ut-zones-manager-console1-dbus", "zonesPath" : "/tmp/ut-zones", "zoneImagePath" : "", - "zoneTemplatePath" : "@VSM_TEST_CONFIG_INSTALL_DIR@/server/ut-zones-manager/templates/template.conf", + "zoneTemplateDir" : "@VSM_TEST_CONFIG_INSTALL_DIR@/server/ut-zones-manager/templates/", "zoneNewConfigPrefix" : "@VSM_TEST_CONFIG_INSTALL_DIR@/server/ut-zones-manager/", "runMountPointPrefix" : "", "lxcTemplatePrefix" : "@VSM_TEST_LXC_TEMPLATES_INSTALL_DIR@", diff --git a/tests/unit_tests/server/ut-zones-manager.cpp b/tests/unit_tests/server/ut-zones-manager.cpp index 65f0f2b..b0ab2e2 100644 --- a/tests/unit_tests/server/ut-zones-manager.cpp +++ b/tests/unit_tests/server/ut-zones-manager.cpp @@ -78,6 +78,7 @@ const std::string FILE_CONTENT = "File content\n" "Line 2\n"; const std::string NON_EXISTANT_ZONE_ID = "NON_EXISTANT_ZONE_ID"; const std::string ZONES_PATH = "/tmp/ut-zones"; // the same as in daemon.conf +const std::string TEMPLATE_NAME = "default"; /** * Currently there is no way to propagate an error from async call @@ -326,6 +327,7 @@ public: } void callAsyncMethodCreateZone(const std::string& id, + const std::string& templateName, const VoidResultCallback& result) { auto asyncResult = [result](dbus::AsyncMethodCallResult& asyncMethodCallResult) { @@ -335,7 +337,7 @@ public: }; assert(isHost()); - GVariant* parameters = g_variant_new("(s)", id.c_str()); + GVariant* parameters = g_variant_new("(ss)", id.c_str(), templateName.c_str()); mClient->callMethodAsync(api::host::BUS_NAME, api::host::OBJECT_PATH, api::host::INTERFACE, @@ -1028,15 +1030,15 @@ BOOST_AUTO_TEST_CASE(CreateDestroyZoneTest) DbusAccessory dbus(DbusAccessory::HOST_ID); // create zone1 - dbus.callAsyncMethodCreateZone(zone1, resultCallback); + dbus.callAsyncMethodCreateZone(zone1, TEMPLATE_NAME, resultCallback); BOOST_REQUIRE(callDone.wait(EVENT_TIMEOUT)); // create zone2 - dbus.callAsyncMethodCreateZone(zone2, resultCallback); + dbus.callAsyncMethodCreateZone(zone2, TEMPLATE_NAME, resultCallback); BOOST_REQUIRE(callDone.wait(EVENT_TIMEOUT)); // create zone3 - dbus.callAsyncMethodCreateZone(zone3, resultCallback); + dbus.callAsyncMethodCreateZone(zone3, TEMPLATE_NAME, resultCallback); BOOST_REQUIRE(callDone.wait(EVENT_TIMEOUT)); cm.startAll(); @@ -1084,7 +1086,7 @@ BOOST_AUTO_TEST_CASE(CreateDestroyZonePersistenceTest) { ZonesManager cm(EMPTY_DBUS_CONFIG_PATH); DbusAccessory dbus(DbusAccessory::HOST_ID); - dbus.callAsyncMethodCreateZone(zone, resultCallback); + dbus.callAsyncMethodCreateZone(zone, TEMPLATE_NAME, resultCallback); BOOST_REQUIRE(callDone.wait(EVENT_TIMEOUT)); } -- 2.7.4 From 43b699c16859c7be00815d9e4c1fbc994c9f3482 Mon Sep 17 00:00:00 2001 From: Jan Olszak Date: Fri, 6 Feb 2015 13:13:12 +0100 Subject: [PATCH 05/16] IPC: Asynchronous method result sending [Bug/Feature] N/A [Cause] N/A [Solution] N/A [Verification] Build, install, run tests, run tests under valgrind Change-Id: I16cc384545c273f65c8f57f11adde61709e08bc4 --- common/ipc/internals/processor.cpp | 116 +++++++++++++++++++++------ common/ipc/internals/processor.hpp | 68 +++++++++++++--- common/ipc/internals/request-queue.hpp | 18 ++++- common/ipc/internals/send-result-request.hpp | 58 ++++++++++++++ common/ipc/internals/signal-request.hpp | 2 - common/ipc/method-result.cpp | 59 ++++++++++++++ common/ipc/method-result.hpp | 75 +++++++++++++++++ common/ipc/types.hpp | 6 -- tests/unit_tests/ipc/ut-ipc.cpp | 105 ++++++++++++++++++++---- 9 files changed, 443 insertions(+), 64 deletions(-) create mode 100644 common/ipc/internals/send-result-request.hpp create mode 100644 common/ipc/method-result.cpp create mode 100644 common/ipc/method-result.hpp diff --git a/common/ipc/internals/processor.cpp b/common/ipc/internals/processor.cpp index d63e490..79c1a22 100644 --- a/common/ipc/internals/processor.cpp +++ b/common/ipc/internals/processor.cpp @@ -163,6 +163,33 @@ FileDescriptor Processor::getEventFD() return mRequestQueue.getFD(); } +void Processor::sendResult(const MethodID methodID, + const PeerID peerID, + const MessageID messageID, + const std::shared_ptr& data) +{ + auto requestPtr = std::make_shared(methodID, peerID, messageID, data); + mRequestQueue.pushFront(Event::SEND_RESULT, requestPtr); +} + +void Processor::sendError(const PeerID peerID, + const MessageID messageID, + const int errorCode, + const std::string& message) +{ + auto data = std::make_shared(messageID, errorCode, message); + signalInternal(ERROR_METHOD_ID, peerID , data); +} + +void Processor::sendVoid(const MethodID methodID, + const PeerID peerID, + const MessageID messageID) +{ + auto data = std::make_shared(); + auto requestPtr = std::make_shared(methodID, peerID, messageID, data); + mRequestQueue.pushFront(Event::SEND_RESULT, requestPtr); +} + void Processor::removeMethod(const MethodID methodID) { Lock lock(mStateMutex); @@ -374,16 +401,16 @@ bool Processor::handleInput(const FileDescriptor fd) return false; } - Socket& socket = *peerIt->socketPtr; MethodID methodID; MessageID messageID; { - Socket::Guard guard = socket.getGuard(); try { + // Read information about the incoming data + Socket& socket = *peerIt->socketPtr; + Socket::Guard guard = socket.getGuard(); socket.read(&methodID, sizeof(methodID)); socket.read(&messageID, sizeof(messageID)); - } catch (const IPCException& e) { LOGE(mLogPrefix + "Error during reading the socket"); removePeerInternal(peerIt, @@ -525,13 +552,13 @@ bool Processor::onRemoteMethod(Peers::iterator& peerIt, } LOGT(mLogPrefix + "Process callback for methodID: " << methodID << "; messageID: " << messageID); - std::shared_ptr returnData; try { - returnData = methodCallbacks->method(peerIt->peerID, data); + methodCallbacks->method(peerIt->peerID, + data, + std::make_shared(*this, methodID, messageID, peerIt->peerID)); } catch (const IPCUserException& e) { LOGW("User's exception"); - auto data = std::make_shared(messageID, e.getCode(), e.what()); - signalInternal(ERROR_METHOD_ID, peerIt->peerID, data); + sendError(peerIt->peerID, messageID, e.getCode(), e.what()); return false; } catch (const std::exception& e) { LOGE(mLogPrefix + "Exception in method handler: " << e.what()); @@ -540,22 +567,6 @@ bool Processor::onRemoteMethod(Peers::iterator& peerIt, return true; } - LOGT(mLogPrefix + "Sending return data; methodID: " << methodID << "; messageID: " << messageID); - try { - // Send the call with the socket - Socket& socket = *peerIt->socketPtr; - Socket::Guard guard = socket.getGuard(); - socket.write(&RETURN_METHOD_ID, sizeof(RETURN_METHOD_ID)); - socket.write(&messageID, sizeof(messageID)); - methodCallbacks->serialize(socket.getFD(), returnData); - } catch (const std::exception& e) { - LOGE(mLogPrefix + "Exception during serialization: " << e.what()); - removePeerInternal(peerIt, - std::make_exception_ptr(IPCSerializationException())); - - return true; - } - return false; } @@ -573,6 +584,7 @@ bool Processor::handleEvent() case Event::SIGNAL: return onSignalRequest(*request.get()); case Event::ADD_PEER: return onAddPeerRequest(*request.get()); case Event::REMOVE_PEER: return onRemovePeerRequest(*request.get()); + case Event::SEND_RESULT: return onSendResultRequest(*request.get()); case Event::FINISH: return onFinishRequest(*request.get()); } @@ -602,9 +614,9 @@ bool Processor::onMethodRequest(MethodRequest& request) std::move(request.parse), std::move(request.process))); - Socket& socket = *peerIt->socketPtr; try { // Send the call with the socket + Socket& socket = *peerIt->socketPtr; Socket::Guard guard = socket.getGuard(); socket.write(&request.methodID, sizeof(request.methodID)); socket.write(&request.messageID, sizeof(request.messageID)); @@ -639,9 +651,9 @@ bool Processor::onSignalRequest(SignalRequest& request) return false; } - Socket& socket = *peerIt->socketPtr; try { // Send the call with the socket + Socket& socket = *peerIt->socketPtr; Socket::Guard guard = socket.getGuard(); socket.write(&request.methodID, sizeof(request.methodID)); socket.write(&request.messageID, sizeof(request.messageID)); @@ -707,6 +719,51 @@ bool Processor::onRemovePeerRequest(RemovePeerRequest& request) return true; } +bool Processor::onSendResultRequest(SendResultRequest& request) +{ + LOGS(mLogPrefix + "Processor onMethodRequest"); + + auto peerIt = getPeerInfoIterator(request.peerID); + + if (peerIt == mPeerInfo.end()) { + LOGE(mLogPrefix + "Peer disconnected, no result is sent. No user with a peerID: " << request.peerID); + return false; + } + + std::shared_ptr methodCallbacks; + try { + methodCallbacks = mMethodsCallbacks.at(request.methodID); + } catch (const std::out_of_range&) { + LOGW(mLogPrefix + "No method, might have been deleted. methodID: " << request.methodID); + return true; + } + + try { + // Send the call with the socket + Socket& socket = *peerIt->socketPtr; + Socket::Guard guard = socket.getGuard(); + socket.write(&RETURN_METHOD_ID, sizeof(RETURN_METHOD_ID)); + socket.write(&request.messageID, sizeof(request.messageID)); + LOGT(mLogPrefix + "Serializing the message"); + methodCallbacks->serialize(socket.getFD(), request.data); + } catch (const std::exception& e) { + LOGE(mLogPrefix + "Error during sending a method: " << e.what()); + + // Inform about the error + ResultBuilder resultBuilder(std::make_exception_ptr(IPCSerializationException())); + IGNORE_EXCEPTIONS(mReturnCallbacks[request.messageID].process(resultBuilder)); + + + mReturnCallbacks.erase(request.messageID); + removePeerInternal(peerIt, + std::make_exception_ptr(IPCSerializationException())); + return true; + + } + + return false; +} + bool Processor::onFinishRequest(FinishRequest& request) { LOGS(mLogPrefix + "Processor onFinishRequest"); @@ -727,6 +784,10 @@ bool Processor::onFinishRequest(FinishRequest& request) onRemovePeerRequest(*request.get()); break; } + case Event::SEND_RESULT: { + onSendResultRequest(*request.get()); + break; + } case Event::SIGNAL: case Event::ADD_PEER: case Event::FINISH: @@ -768,6 +829,11 @@ std::ostream& operator<<(std::ostream& os, const Processor::Event& event) os << "Event::REMOVE_PEER"; break; } + + case Processor::Event::SEND_RESULT: { + os << "Event::SEND_RESULT"; + break; + } } return os; diff --git a/common/ipc/internals/processor.hpp b/common/ipc/internals/processor.hpp index b890cda..86a3f42 100644 --- a/common/ipc/internals/processor.hpp +++ b/common/ipc/internals/processor.hpp @@ -32,8 +32,10 @@ #include "ipc/internals/signal-request.hpp" #include "ipc/internals/add-peer-request.hpp" #include "ipc/internals/remove-peer-request.hpp" +#include "ipc/internals/send-result-request.hpp" #include "ipc/internals/finish-request.hpp" #include "ipc/exception.hpp" +#include "ipc/method-result.hpp" #include "ipc/types.hpp" #include "config/manager.hpp" #include "config/fields.hpp" @@ -51,12 +53,12 @@ #include #include #include +#include namespace vasum { namespace ipc { const unsigned int DEFAULT_MAX_NUMBER_OF_PEERS = 500; - /** * This class wraps communication via UX sockets * @@ -89,11 +91,12 @@ const unsigned int DEFAULT_MAX_NUMBER_OF_PEERS = 500; class Processor { private: enum class Event { - FINISH, // Shutdown request - METHOD, // New method call in the queue - SIGNAL, // New signal call in the queue - ADD_PEER, // New peer in the queue - REMOVE_PEER // Remove peer + FINISH, // Shutdown request + METHOD, // New method call in the queue + SIGNAL, // New signal call in the queue + ADD_PEER, // New peer in the queue + REMOVE_PEER, // Remove peer + SEND_RESULT // Send the result of a method's call }; public: @@ -209,6 +212,44 @@ public: const typename SignalHandler::type& process); /** + * Send result of the method. + * Used for asynchronous communication, only internally. + * + * @param methodID API dependent id of the method + * @param peerID id of the peer + * @param messageID id of the message to which it replies + * @param data data to send + */ + void sendResult(const MethodID methodID, + const PeerID peerID, + const MessageID messageID, + const std::shared_ptr& data); + + /** + * Send error result of the method + * + * @param peerID id of the peer + * @param messageID id of the message to which it replies + * @param errorCode code of the error + * @param message description of the error + */ + void sendError(const PeerID peerID, + const MessageID messageID, + const int errorCode, + const std::string& message); + + /** + * Indicate that the method handler finished + * + * @param methodID API dependent id of the method + * @param peerID id of the peer + * @param messageID id of the message to which it replies + */ + void sendVoid(const MethodID methodID, + const PeerID peerID, + const MessageID messageID); + + /** * Removes the callback * * @param methodID API dependent id of the method @@ -220,7 +261,7 @@ public: * * @param methodID API dependent id of the method * @param peerID id of the peer - * @param data data to sent + * @param data data to send * @param timeoutMS how long to wait for the return value before throw * @tparam SentDataType data type to send * @tparam ReceivedDataType data type to receive @@ -432,6 +473,7 @@ private: bool onSignalRequest(SignalRequest& request); bool onAddPeerRequest(AddPeerRequest& request); bool onRemovePeerRequest(RemovePeerRequest& request); + bool onSendResultRequest(SendResultRequest& request); bool onFinishRequest(FinishRequest& request); bool handleLostConnections(); @@ -480,9 +522,9 @@ void Processor::setMethodHandlerInternal(const MethodID methodID, config::saveToFD(fd, *std::static_pointer_cast(data)); }; - methodCall.method = [method](const PeerID peerID, std::shared_ptr& data)->std::shared_ptr { + methodCall.method = [method](const PeerID peerID, std::shared_ptr& data, MethodResult::Pointer && methodResult) { std::shared_ptr tmpData = std::static_pointer_cast(data); - return method(peerID, tmpData); + method(peerID, tmpData, std::forward(methodResult)); }; mMethodsCallbacks[methodID] = std::make_shared(std::move(methodCall)); @@ -636,8 +678,8 @@ void Processor::signalInternal(const MethodID methodID, const PeerID peerID, const std::shared_ptr& data) { - auto request = SignalRequest::create(methodID, peerID, data); - mRequestQueue.pushFront(Event::SIGNAL, request); + auto requestPtr = SignalRequest::create(methodID, peerID, data); + mRequestQueue.pushFront(Event::SIGNAL, requestPtr); } template @@ -651,8 +693,8 @@ void Processor::signal(const MethodID methodID, return; } for (const PeerID peerID : it->second) { - auto request = SignalRequest::create(methodID, peerID, data); - mRequestQueue.pushBack(Event::SIGNAL, request); + auto requestPtr = SignalRequest::create(methodID, peerID, data); + mRequestQueue.pushBack(Event::SIGNAL, requestPtr); } } diff --git a/common/ipc/internals/request-queue.hpp b/common/ipc/internals/request-queue.hpp index f648345..e1ad46b 100644 --- a/common/ipc/internals/request-queue.hpp +++ b/common/ipc/internals/request-queue.hpp @@ -31,6 +31,7 @@ #include #include +#include #include namespace vasum { @@ -70,12 +71,12 @@ public: /** * @return event's file descriptor */ - int getFD() const; + int getFD(); /** * @return is the queue empty */ - bool isEmpty() const; + bool isEmpty(); /** * Push data to back of the queue @@ -110,19 +111,24 @@ public: bool removeIf(Predicate predicate); private: + typedef std::unique_lock Lock; + std::list mRequests; + std::mutex mStateMutex; EventFD mEventFD; }; template -int RequestQueue::getFD() const +int RequestQueue::getFD() { + Lock lock(mStateMutex); return mEventFD.getFD(); } template -bool RequestQueue::isEmpty() const +bool RequestQueue::isEmpty() { + Lock lock(mStateMutex); return mRequests.empty(); } @@ -130,6 +136,7 @@ template void RequestQueue::pushBack(const RequestIdType requestID, const std::shared_ptr& data) { + Lock lock(mStateMutex); Request request(requestID, data); mRequests.push_back(std::move(request)); mEventFD.send(); @@ -139,6 +146,7 @@ template void RequestQueue::pushFront(const RequestIdType requestID, const std::shared_ptr& data) { + Lock lock(mStateMutex); Request request(requestID, data); mRequests.push_front(std::move(request)); mEventFD.send(); @@ -147,6 +155,7 @@ void RequestQueue::pushFront(const RequestIdType requestID, template typename RequestQueue::Request RequestQueue::pop() { + Lock lock(mStateMutex); mEventFD.receive(); if (mRequests.empty()) { LOGE("Request queue is empty"); @@ -161,6 +170,7 @@ template template bool RequestQueue::removeIf(Predicate predicate) { + Lock lock(mStateMutex); auto it = std::find_if(mRequests.begin(), mRequests.end(), predicate); if (it == mRequests.end()) { return false; diff --git a/common/ipc/internals/send-result-request.hpp b/common/ipc/internals/send-result-request.hpp new file mode 100644 index 0000000..bc1db6c --- /dev/null +++ b/common/ipc/internals/send-result-request.hpp @@ -0,0 +1,58 @@ +/* +* Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved +* +* Contact: Jan Olszak +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License +*/ + +/** + * @file + * @author Jan Olszak (j.olszak@samsung.com) + * @brief Processor's request to send the result of a method + */ + +#ifndef COMMON_IPC_INTERNALS_SEND_RESULT_REQUEST_HPP +#define COMMON_IPC_INTERNALS_SEND_RESULT_REQUEST_HPP + +#include "ipc/types.hpp" +#include "logger/logger-scope.hpp" + +namespace vasum { +namespace ipc { + +class SendResultRequest { +public: + SendResultRequest(const SendResultRequest&) = delete; + SendResultRequest& operator=(const SendResultRequest&) = delete; + + SendResultRequest(const MethodID methodID, + const PeerID peerID, + const MessageID messageID, + const std::shared_ptr& data) + : methodID(methodID), + peerID(peerID), + messageID(messageID), + data(data) + {} + + MethodID methodID; + PeerID peerID; + MessageID messageID; + std::shared_ptr data; +}; + +} // namespace ipc +} // namespace vasum + +#endif // COMMON_IPC_INTERNALS_SEND_RESULT_REQUEST_HPP diff --git a/common/ipc/internals/signal-request.hpp b/common/ipc/internals/signal-request.hpp index 8a11ee8..dac9c4d 100644 --- a/common/ipc/internals/signal-request.hpp +++ b/common/ipc/internals/signal-request.hpp @@ -37,8 +37,6 @@ public: SignalRequest(const SignalRequest&) = delete; SignalRequest& operator=(const SignalRequest&) = delete; - - template static std::shared_ptr create(const MethodID methodID, const PeerID peerID, diff --git a/common/ipc/method-result.cpp b/common/ipc/method-result.cpp new file mode 100644 index 0000000..826354c --- /dev/null +++ b/common/ipc/method-result.cpp @@ -0,0 +1,59 @@ +/* +* Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved +* +* Contact: Jan Olszak +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License +*/ + +/** + * @file + * @author Jan Olszak (j.olszak@samsung.com) + * @brief Class for sending the result of a method + */ + +#include "config.hpp" + +#include "ipc/method-result.hpp" +#include "ipc/internals/processor.hpp" + +namespace vasum { +namespace ipc { + +MethodResult::MethodResult(Processor& processor, + const MethodID methodID, + const MessageID messageID, + const PeerID peerID) + : mProcessor(processor), + mMethodID(methodID), + mPeerID(peerID), + mMessageID(messageID) +{} + +void MethodResult::setInternal(const std::shared_ptr& data) +{ + mProcessor.sendResult(mMethodID, mPeerID, mMessageID, data); +} + +void MethodResult::setVoid() +{ + mProcessor.sendVoid(mMethodID, mPeerID, mMessageID); +} + +void MethodResult::setError(const int code, const std::string& message) +{ + mProcessor.sendError(mPeerID, mMessageID, code, message); +} + +} // namespace ipc +} // namespace vasum diff --git a/common/ipc/method-result.hpp b/common/ipc/method-result.hpp new file mode 100644 index 0000000..ebe9697 --- /dev/null +++ b/common/ipc/method-result.hpp @@ -0,0 +1,75 @@ +/* +* Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved +* +* Contact: Jan Olszak +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License +*/ + +/** + * @file + * @author Jan Olszak (j.olszak@samsung.com) + * @brief Class for sending the result of a method + */ + +#ifndef COMMON_IPC_METHOD_RESULT_HPP +#define COMMON_IPC_METHOD_RESULT_HPP + +#include "ipc/types.hpp" +#include "logger/logger.hpp" +#include + +namespace vasum { +namespace ipc { + +class Processor; + +class MethodResult { +public: + typedef std::shared_ptr Pointer; + + MethodResult(Processor& processor, + const MethodID methodID, + const MessageID messageID, + const PeerID peerID); + + + template + void set(const std::shared_ptr& data) + { + setInternal(data); + } + + void setVoid(); + void setError(const int code, const std::string& message); + +private: + Processor& mProcessor; + MethodID mMethodID; + PeerID mPeerID; + MessageID mMessageID; + + void setInternal(const std::shared_ptr& data); +}; + +template +struct MethodHandler { + typedef std::function < void(PeerID peerID, + std::shared_ptr& data, + MethodResult::Pointer&& methodResult) > type; +}; + +} // namespace ipc +} // namespace vasum + +#endif // COMMON_IPC_METHOD_RESULT_HPP diff --git a/common/ipc/types.hpp b/common/ipc/types.hpp index fe132ec..3fec337 100644 --- a/common/ipc/types.hpp +++ b/common/ipc/types.hpp @@ -25,7 +25,6 @@ #ifndef COMMON_IPC_TYPES_HPP #define COMMON_IPC_TYPES_HPP -#include "ipc/exception.hpp" #include #include #include @@ -45,11 +44,6 @@ typedef std::function(int fd)> ParseCallback; MessageID getNextMessageID(); PeerID getNextPeerID(); -template -struct MethodHandler { - typedef std::function(PeerID peerID, - std::shared_ptr& data)> type; -}; template struct SignalHandler { diff --git a/tests/unit_tests/ipc/ut-ipc.cpp b/tests/unit_tests/ipc/ut-ipc.cpp index cb475f1..56c94cb 100644 --- a/tests/unit_tests/ipc/ut-ipc.cpp +++ b/tests/unit_tests/ipc/ut-ipc.cpp @@ -46,6 +46,7 @@ #include #include #include +#include #include using namespace vasum; @@ -136,25 +137,36 @@ struct ThrowOnAcceptData { } }; -std::shared_ptr returnEmptyCallback(const PeerID, std::shared_ptr&) +void returnEmptyCallback(const PeerID, + std::shared_ptr&, + MethodResult::Pointer methodResult) { - return std::make_shared(); + methodResult->setVoid(); } -std::shared_ptr returnDataCallback(const PeerID, std::shared_ptr&) +void returnDataCallback(const PeerID, + std::shared_ptr&, + MethodResult::Pointer methodResult) { - return std::make_shared(1); + auto returnData = std::make_shared(1); + methodResult->set(returnData); } -std::shared_ptr echoCallback(const PeerID, std::shared_ptr& data) +void echoCallback(const PeerID, + std::shared_ptr& data, + MethodResult::Pointer methodResult) { - return std::make_shared(data->intVal); + auto returnData = std::make_shared(data->intVal); + methodResult->set(returnData); } -std::shared_ptr longEchoCallback(const PeerID, std::shared_ptr& data) +void longEchoCallback(const PeerID, + std::shared_ptr& data, + MethodResult::Pointer methodResult) { std::this_thread::sleep_for(std::chrono::milliseconds(LONG_OPERATION_TIME)); - return std::make_shared(data->intVal); + auto returnData = std::make_shared(data->intVal); + methodResult->set(returnData); } PeerID connect(Service& s, Client& c, bool isServiceGlib = false, bool isClientGlib = false) @@ -431,8 +443,9 @@ BOOST_AUTO_TEST_CASE(DisconnectedPeerError) ValueLatch> retStatusLatch; Service s(socketPath); - auto method = [](const PeerID, std::shared_ptr&) { - return std::shared_ptr(new SendData(1)); + auto method = [](const PeerID, std::shared_ptr&, MethodResult::Pointer methodResult) { + auto resultData = std::make_shared(1); + methodResult->set(resultData); }; // Method will throw during serialization and disconnect automatically @@ -462,8 +475,9 @@ BOOST_AUTO_TEST_CASE(DisconnectedPeerError) BOOST_AUTO_TEST_CASE(ReadTimeout) { Service s(socketPath); - auto longEchoCallback = [](const PeerID, std::shared_ptr& data) { - return std::shared_ptr(new LongSendData(data->intVal, LONG_OPERATION_TIME)); + auto longEchoCallback = [](const PeerID, std::shared_ptr& data, MethodResult::Pointer methodResult) { + auto resultData = std::make_shared(data->intVal, LONG_OPERATION_TIME); + methodResult->set(resultData); }; s.setMethodHandler(1, longEchoCallback); @@ -514,7 +528,6 @@ BOOST_AUTO_TEST_CASE(AddSignalInRuntime) recvDataLatchB.set(data); }; - LOGH("SETTING SIGNAAALS"); c.setSignalHandler(1, handlerA); c.setSignalHandler(2, handlerB); @@ -634,12 +647,18 @@ BOOST_AUTO_TEST_CASE(UsersError) Client c(socketPath); auto clientID = connect(s, c); - auto throwingMethodHandler = [&](const PeerID, std::shared_ptr&) -> std::shared_ptr { + auto throwingMethodHandler = [&](const PeerID, std::shared_ptr&, MethodResult::Pointer) { throw IPCUserException(TEST_ERROR_CODE, TEST_ERROR_MESSAGE); }; + auto sendErrorMethodHandler = [&](const PeerID, std::shared_ptr&, MethodResult::Pointer methodResult) { + methodResult->setError(TEST_ERROR_CODE, TEST_ERROR_MESSAGE); + }; + s.setMethodHandler(1, throwingMethodHandler); + s.setMethodHandler(2, sendErrorMethodHandler); c.setMethodHandler(1, throwingMethodHandler); + c.setMethodHandler(2, sendErrorMethodHandler); std::shared_ptr sentData(new SendData(78)); @@ -649,8 +668,66 @@ BOOST_AUTO_TEST_CASE(UsersError) BOOST_CHECK_EXCEPTION((c.callSync(1, sentData, TIMEOUT)), IPCUserException, hasProperData); BOOST_CHECK_EXCEPTION((s.callSync(1, clientID, sentData, TIMEOUT)), IPCUserException, hasProperData); + BOOST_CHECK_EXCEPTION((c.callSync(2, sentData, TIMEOUT)), IPCUserException, hasProperData); + BOOST_CHECK_EXCEPTION((s.callSync(2, clientID, sentData, TIMEOUT)), IPCUserException, hasProperData); +} + +BOOST_AUTO_TEST_CASE(AsyncResult) +{ + const int TEST_ERROR_CODE = -567; + const std::string TEST_ERROR_MESSAGE = "Ooo jooo!"; + + Service s(socketPath); + Client c(socketPath); + auto clientID = connect(s, c); + + auto errorMethodHandler = [&](const PeerID, std::shared_ptr&, MethodResult::Pointer methodResult) { + std::async(std::launch::async, [&, methodResult] { + std::this_thread::sleep_for(std::chrono::milliseconds(SHORT_OPERATION_TIME)); + methodResult->setError(TEST_ERROR_CODE, TEST_ERROR_MESSAGE); + }); + }; + + auto voidMethodHandler = [&](const PeerID, std::shared_ptr&, MethodResult::Pointer methodResult) { + std::async(std::launch::async, [methodResult] { + std::this_thread::sleep_for(std::chrono::milliseconds(SHORT_OPERATION_TIME)); + methodResult->setVoid(); + }); + }; + + auto dataMethodHandler = [&](const PeerID, std::shared_ptr& data, MethodResult::Pointer methodResult) { + std::async(std::launch::async, [data, methodResult] { + std::this_thread::sleep_for(std::chrono::milliseconds(SHORT_OPERATION_TIME)); + methodResult->set(data); + }); + }; + + s.setMethodHandler(1, errorMethodHandler); + s.setMethodHandler(2, voidMethodHandler); + s.setMethodHandler(3, dataMethodHandler); + c.setMethodHandler(1, errorMethodHandler); + c.setMethodHandler(2, voidMethodHandler); + c.setMethodHandler(3, dataMethodHandler); + + std::shared_ptr sentData(new SendData(90)); + + auto hasProperData = [&](const IPCUserException & e) { + return e.getCode() == TEST_ERROR_CODE && e.what() == TEST_ERROR_MESSAGE; + }; + + BOOST_CHECK_EXCEPTION((s.callSync(1, clientID, sentData, TIMEOUT)), IPCUserException, hasProperData); + BOOST_CHECK_EXCEPTION((c.callSync(1, sentData, TIMEOUT)), IPCUserException, hasProperData); + + BOOST_CHECK_NO_THROW((s.callSync(2, clientID, sentData, TIMEOUT))); + BOOST_CHECK_NO_THROW((c.callSync(2, sentData, TIMEOUT))); + std::shared_ptr recvData; + recvData = s.callSync(3, clientID, sentData, TIMEOUT); + BOOST_CHECK_EQUAL(recvData->intVal, sentData->intVal); + recvData = c.callSync(3, sentData, TIMEOUT); + BOOST_CHECK_EQUAL(recvData->intVal, sentData->intVal); } + // BOOST_AUTO_TEST_CASE(ConnectionLimitTest) // { // unsigned oldLimit = ipc::getMaxFDNumber(); -- 2.7.4 From 372fb5a9bc2f1289d2fda7b979796ac442d71ab9 Mon Sep 17 00:00:00 2001 From: Piotr Bartosiewicz Date: Thu, 12 Feb 2015 17:22:01 +0100 Subject: [PATCH 06/16] Code refactor/cleanup [Bug/Feature] N/A [Cause] N/A [Solution] N/A [Verification] Build, run tests Change-Id: I30a1358f9163c78afa44f6ea0731003171f0f9a7 --- server/dynamic-config-scheme.hpp | 51 ++++++++++++++++ server/exception.hpp | 8 +++ server/zone-connection-transport.cpp | 2 + server/zone.cpp | 4 +- server/zones-manager.cpp | 81 ++++++++++++++------------ server/zones-manager.hpp | 6 +- tests/unit_tests/lxc/templates/minimal-dbus.sh | 3 + tests/unit_tests/server/ut-server.cpp | 11 ++-- tests/unit_tests/server/ut-zone-admin.cpp | 9 +-- tests/unit_tests/server/ut-zone.cpp | 9 +-- tests/unit_tests/server/ut-zones-manager.cpp | 12 ++-- 11 files changed, 136 insertions(+), 60 deletions(-) create mode 100644 server/dynamic-config-scheme.hpp diff --git a/server/dynamic-config-scheme.hpp b/server/dynamic-config-scheme.hpp new file mode 100644 index 0000000..90c80d5 --- /dev/null +++ b/server/dynamic-config-scheme.hpp @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * Contact: Piotr Bartosiewicz + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +/** + * @file + * @author Piotr Bartosiewicz (p.bartosiewi@partner.samsung.com) + * @brief Dynamic config helper functions + */ + + +#ifndef SERVER_DYNAMIC_CONFIG_SCHEME_HPP +#define SERVER_DYNAMIC_CONFIG_SCHEME_HPP + +#include + +namespace vasum { + +/** + * Gets db prefix for vasum config + */ +inline std::string getVasumDbPrefix() +{ + return "vasum"; +} + +/** + * Gets db prefix for zone config + */ +inline std::string getZoneDbPrefix(const std::string& id) +{ + return "zone." + id; +} + +} // namespace vasum + +#endif // SERVER_DYNAMIC_CONFIG_SCHEME_HPP diff --git a/server/exception.hpp b/server/exception.hpp index 09eaaef..cb358b1 100644 --- a/server/exception.hpp +++ b/server/exception.hpp @@ -50,6 +50,14 @@ struct ZoneOperationException: public ServerException { }; /** + * Invalid zone id + */ +struct InvalidZoneIdException : public ServerException { + + InvalidZoneIdException(const std::string& error = "") : ServerException(error) {} +}; + +/** * Exception during performing an operation on a zone connection */ struct ZoneConnectionException: public ServerException { diff --git a/server/zone-connection-transport.cpp b/server/zone-connection-transport.cpp index 0757241..0a8f8a0 100644 --- a/server/zone-connection-transport.cpp +++ b/server/zone-connection-transport.cpp @@ -74,6 +74,7 @@ ZoneConnectionTransport::ZoneConnectionTransport(const std::string& runMountPoin LOGE("Initialization failed: could not mount " << runMountPoint); throw ZoneConnectionException("Could not mount: " + runMountPoint); } + LOGI("Mounted: " << runMountPoint); } // if there is no systemd in the zone this dir won't be created automatically @@ -95,6 +96,7 @@ ZoneConnectionTransport::~ZoneConnectionTransport() if (!utils::umount(mRunMountPoint)) { LOGE("Deinitialization failed: could not umount " << mRunMountPoint); } + LOGI("Unmounted: " << mRunMountPoint); } } } diff --git a/server/zone.cpp b/server/zone.cpp index 1617bd6..0c2eca7 100644 --- a/server/zone.cpp +++ b/server/zone.cpp @@ -25,6 +25,7 @@ #include "config.hpp" #include "zone.hpp" +#include "dynamic-config-scheme.hpp" #include "base-exception.hpp" #include "logger/logger.hpp" @@ -48,7 +49,6 @@ typedef std::lock_guard Lock; // TODO: move constants to the config file when default values are implemented there const int RECONNECT_RETRIES = 15; const int RECONNECT_DELAY = 1 * 1000; -const std::string DB_PREFIX = "zone."; } // namespace @@ -77,7 +77,7 @@ Zone::Zone(const utils::Worker::Pointer& worker, const fs::path zonePath = fs::path(zonesPath) / mAdmin->getId(); mRootPath = (zonePath / fs::path("rootfs")).string(); - const std::string dbPrefix = DB_PREFIX + mAdmin->getId(); + const std::string dbPrefix = getZoneDbPrefix(mAdmin->getId()); config::loadFromKVStoreWithJsonFile(dbPath, zoneConfigPath, mDynamicConfig, dbPrefix); mProvision.reset(new ZoneProvision(mRootPath, zoneConfigPath, dbPath, dbPrefix, mConfig.validLinkPrefixes)); diff --git a/server/zones-manager.cpp b/server/zones-manager.cpp index 6acc128..3baa2a2 100644 --- a/server/zones-manager.cpp +++ b/server/zones-manager.cpp @@ -27,6 +27,7 @@ #include "host-dbus-definitions.hpp" #include "common-dbus-definitions.hpp" #include "zone-dbus-definitions.hpp" +#include "dynamic-config-scheme.hpp" #include "zones-manager.hpp" #include "zone-admin.hpp" #include "lxc/cgroup.hpp" @@ -64,7 +65,6 @@ bool regexMatchVector(const std::string& str, const std::vector& v return false; } -const std::string DB_PREFIX = "daemon"; const std::string HOST_ID = "host"; const std::string ENABLED_FILE_NAME = "enabled"; @@ -124,7 +124,10 @@ ZonesManager::ZonesManager(const std::string& configPath) LOGD("Instantiating ZonesManager object..."); config::loadFromJsonFile(configPath, mConfig); - config::loadFromKVStoreWithJsonFile(mConfig.dbPath, configPath, mDynamicConfig, DB_PREFIX); + config::loadFromKVStoreWithJsonFile(mConfig.dbPath, + configPath, + mDynamicConfig, + getVasumDbPrefix()); mProxyCallPolicy.reset(new ProxyCallPolicy(mConfig.proxyCallRules)); @@ -187,7 +190,7 @@ ZonesManager::ZonesManager(const std::string& configPath) this, _1, _2, _3)); for (const auto& zoneConfig : mDynamicConfig.zoneConfigs) { - createZone(utils::createFilePath(mConfig.zoneNewConfigPrefix, zoneConfig)); + insertZone(utils::createFilePath(mConfig.zoneNewConfigPrefix, zoneConfig)); } updateDefaultId(); @@ -233,14 +236,14 @@ Zone& ZonesManager::getZone(const std::string& id) { auto iter = findZone(id); if (iter == mZones.end()) { - throw std::out_of_range("id not found"); + throw InvalidZoneIdException("Zone id not found"); } return get(iter); } void ZonesManager::saveDynamicConfig() { - config::saveToKVStore(mConfig.dbPath, mDynamicConfig, DB_PREFIX); + config::saveToKVStore(mConfig.dbPath, mDynamicConfig, getVasumDbPrefix()); } void ZonesManager::updateDefaultId() @@ -266,7 +269,7 @@ void ZonesManager::updateDefaultId() saveDynamicConfig(); } -void ZonesManager::createZone(const std::string& zoneConfigPath) +void ZonesManager::insertZone(const std::string& zoneConfigPath) { LOGT("Creating Zone " << zoneConfigPath); std::unique_ptr zone(new Zone(mWorker->createSubWorker(), @@ -277,7 +280,10 @@ void ZonesManager::createZone(const std::string& zoneConfigPath) mConfig.runMountPointPrefix)); const std::string id = zone->getId(); if (id == HOST_ID) { - throw ZoneOperationException("Cannot use reserved zone ID"); + throw InvalidZoneIdException("Cannot use reserved zone ID"); + } + if (findZone(id) != mZones.end()) { + throw InvalidZoneIdException("Zone already exists"); } using namespace std::placeholders; @@ -296,11 +302,6 @@ void ZonesManager::createZone(const std::string& zoneConfigPath) zone->setDbusStateChangedCallback(bind(&ZonesManager::handleDbusStateChanged, this, id, _1)); - Lock lock(mMutex); - - if (findZone(id) != mZones.end()) { - throw ZoneOperationException("Zone already exists"); - } mZones.push_back(std::move(zone)); // after zone is created successfully, put a file informing that zones are enabled @@ -319,7 +320,7 @@ void ZonesManager::destroyZone(const std::string& zoneId) auto iter = findZone(zoneId); if (iter == mZones.end()) { LOGE("Failed to destroy zone " << zoneId << ": no such zone"); - throw ZoneOperationException("No such zone"); + throw InvalidZoneIdException("No such zone"); } get(iter).setDestroyOnExit(); @@ -444,7 +445,7 @@ bool ZonesManager::isPaused(const std::string& zoneId) auto iter = findZone(zoneId); if (iter == mZones.end()) { LOGE("No such zone id: " << zoneId); - throw ZoneOperationException("No such zone"); + throw InvalidZoneIdException("No such zone"); } return get(iter).isPaused(); @@ -457,7 +458,7 @@ bool ZonesManager::isRunning(const std::string& zoneId) auto iter = findZone(zoneId); if (iter == mZones.end()) { LOGE("No such zone id: " << zoneId); - throw ZoneOperationException("No such zone"); + throw InvalidZoneIdException("No such zone"); } return get(iter).isRunning(); } @@ -803,7 +804,7 @@ void ZonesManager::handleDeclareFileCall(const std::string& zone, const std::string id = getZone(zone).declareFile(type, path, flags, mode); result->set(g_variant_new("(s)", id.c_str())); - } catch (const std::out_of_range&) { + } catch (const InvalidZoneIdException&) { LOGE("No zone with id=" << zone); result->setError(api::ERROR_INVALID_ID, "No such zone id"); } catch (const config::ConfigException& ex) { @@ -827,7 +828,7 @@ void ZonesManager::handleDeclareMountCall(const std::string& source, const std::string id = getZone(zone).declareMount(source, target, type, flags, data); result->set(g_variant_new("(s)", id.c_str())); - } catch (const std::out_of_range&) { + } catch (const InvalidZoneIdException&) { LOGE("No zone with id=" << zone); result->setError(api::ERROR_INVALID_ID, "No such zone id"); } catch (const config::ConfigException& ex) { @@ -847,7 +848,7 @@ void ZonesManager::handleDeclareLinkCall(const std::string& source, const std::string id = getZone(zone).declareLink(source, target); result->set(g_variant_new("(s)", id.c_str())); - } catch (const std::out_of_range&) { + } catch (const InvalidZoneIdException&) { LOGE("No zone with id=" << zone); result->setError(api::ERROR_INVALID_ID, "No such zone id"); } catch (const config::ConfigException& ex) { @@ -874,7 +875,7 @@ void ZonesManager::handleGetDeclarationsCall(const std::string& zone, out.data(), out.size()); result->set(g_variant_new("(@as)", array)); - } catch (const std::out_of_range&) { + } catch (const InvalidZoneIdException&) { LOGE("No zone with id=" << zone); result->setError(api::ERROR_INVALID_ID, "No such zone id"); } catch (const VasumException& ex) { @@ -895,7 +896,7 @@ void ZonesManager::handleRemoveDeclarationCall(const std::string& zone, getZone(zone).removeDeclaration(declarationId); result->setVoid(); - } catch (const std::out_of_range&) { + } catch (const InvalidZoneIdException&) { LOGE("No zone with id=" << zone); result->setError(api::ERROR_INVALID_ID, "No such zone id"); } catch (const VasumException& ex) { @@ -997,14 +998,12 @@ int ZonesManager::getVTForNewZone() return *candidates.begin(); } -void ZonesManager::handleCreateZoneCall(const std::string& id, - const std::string& templateName, - dbus::MethodResultBuilder::Pointer result) +void ZonesManager::createZone(const std::string& id, + const std::string& templateName) { - if (id.empty()) { + if (id.empty()) { // TODO validate id (no spaces, slashes etc) LOGE("Failed to add zone - invalid name."); - result->setError(api::ERROR_INVALID_ID, "Invalid name"); - return; + throw InvalidZoneIdException("Invalid name"); } LOGI("Creating zone " << id); @@ -1018,8 +1017,7 @@ void ZonesManager::handleCreateZoneCall(const std::string& id, // check if zone does not exist if (findZone(id) != mZones.end()) { LOGE("Cannot create " << id << " zone - already exists!"); - result->setError(api::ERROR_INVALID_ID, "Already exists"); - return; + throw InvalidZoneIdException("Already exists"); } const std::string zonePathStr = utils::createFilePath(mConfig.zonesPath, id, "/"); @@ -1033,8 +1031,7 @@ void ZonesManager::handleCreateZoneCall(const std::string& id, if (!utils::launchAsRoot(copyImageContentsWrapper)) { LOGE("Failed to copy zone image."); - result->setError(api::ERROR_INTERNAL, "Failed to copy zone image."); - return; + throw ZoneOperationException("Failed to copy zone image."); } } @@ -1062,25 +1059,35 @@ void ZonesManager::handleCreateZoneCall(const std::string& id, } catch (VasumException& e) { LOGE("Generate config failed: " << e.what()); utils::launchAsRoot(std::bind(removeAllWrapper, zonePathStr)); - result->setError(api::ERROR_INTERNAL, "Failed to generate config"); - return; + throw e; } LOGT("Creating new zone"); try { - createZone(newConfigPath); + insertZone(newConfigPath); } catch (VasumException& e) { LOGE("Creating new zone failed: " << e.what()); utils::launchAsRoot(std::bind(removeAllWrapper, zonePathStr)); - result->setError(api::ERROR_INTERNAL, "Failed to create zone"); - return; + throw e; } mDynamicConfig.zoneConfigs.push_back(newConfigName); saveDynamicConfig(); updateDefaultId(); +} - result->setVoid(); +void ZonesManager::handleCreateZoneCall(const std::string& id, + const std::string& templateName, + dbus::MethodResultBuilder::Pointer result) +{ + try { + createZone(id, templateName); + result->setVoid(); + } catch (const InvalidZoneIdException& e) { + result->setError(api::ERROR_INVALID_ID, "Existing or invalid zone id"); + } catch (const VasumException& e) { + result->setError(api::ERROR_INTERNAL, "Failed to create zone"); + } } void ZonesManager::handleDestroyZoneCall(const std::string& id, @@ -1091,7 +1098,7 @@ void ZonesManager::handleDestroyZoneCall(const std::string& id, LOGI("Destroying zone " << id); destroyZone(id); - } catch (const ZoneOperationException& e) { + } catch (const InvalidZoneIdException&) { LOGE("Failed to destroy zone - no such zone id: " << id); result->setError(api::ERROR_INVALID_ID, "No such zone id"); } catch (const VasumException& e) { diff --git a/server/zones-manager.hpp b/server/zones-manager.hpp index 99dfa4b..529ef8b 100644 --- a/server/zones-manager.hpp +++ b/server/zones-manager.hpp @@ -49,9 +49,10 @@ public: /** * Create new zone. * - * @param zoneConfigPath config of new zone + * @param zoneId id of new zone + * @param templateName a template name */ - void createZone(const std::string& zoneConfigPath); + void createZone(const std::string& zoneId, const std::string& templateName); /** * Destroy zone. @@ -137,6 +138,7 @@ private: const std::string& templatePath, const std::string& resultPath); int getVTForNewZone(); + void insertZone(const std::string& zoneConfigPath); void notifyActiveZoneHandler(const std::string& caller, const std::string& appliaction, diff --git a/tests/unit_tests/lxc/templates/minimal-dbus.sh b/tests/unit_tests/lxc/templates/minimal-dbus.sh index fb61eb3..a8ff5b9 100755 --- a/tests/unit_tests/lxc/templates/minimal-dbus.sh +++ b/tests/unit_tests/lxc/templates/minimal-dbus.sh @@ -56,6 +56,9 @@ lxc.haltsignal = SIGTERM lxc.pts = 256 lxc.tty = 0 +#lxc.loglevel = TRACE +#lxc.logfile = /tmp/${name}.log + lxc.cgroup.devices.deny = a lxc.mount.auto = proc sys cgroup diff --git a/tests/unit_tests/server/ut-server.cpp b/tests/unit_tests/server/ut-server.cpp index 3ed7319..3cd3e51 100644 --- a/tests/unit_tests/server/ut-server.cpp +++ b/tests/unit_tests/server/ut-server.cpp @@ -35,6 +35,12 @@ #include namespace { + +const std::string CONFIG_DIR = VSM_TEST_CONFIG_INSTALL_DIR "/server/ut-server"; +const std::string TEST_CONFIG_PATH = CONFIG_DIR + "/test-daemon.conf"; +const std::string BUGGY_CONFIG_PATH = CONFIG_DIR + "/buggy-daemon.conf"; +const std::string MISSING_CONFIG_PATH = CONFIG_DIR + "/missing-daemon.conf"; + const std::string ZONES_PATH = "/tmp/ut-zones"; // the same as in daemon.conf const bool AS_ROOT = true; @@ -52,11 +58,6 @@ BOOST_FIXTURE_TEST_SUITE(ServerSuite, Fixture) using namespace vasum; using namespace config; -const std::string TEST_CONFIG_PATH = VSM_TEST_CONFIG_INSTALL_DIR "/server/ut-server/test-daemon.conf"; -const std::string BUGGY_CONFIG_PATH = VSM_TEST_CONFIG_INSTALL_DIR "/server/ut-server/buggy-daemon.conf"; -const std::string MISSING_CONFIG_PATH = "/this/is/a/missing/file/path/missing-daemon.conf"; - - BOOST_AUTO_TEST_CASE(ConstructorDestructorTest) { std::unique_ptr s; diff --git a/tests/unit_tests/server/ut-zone-admin.cpp b/tests/unit_tests/server/ut-zone-admin.cpp index 8dc3eb8..ba21ea9 100644 --- a/tests/unit_tests/server/ut-zone-admin.cpp +++ b/tests/unit_tests/server/ut-zone-admin.cpp @@ -37,10 +37,11 @@ using namespace vasum; namespace { -const std::string TEST_CONFIG_PATH = VSM_TEST_CONFIG_INSTALL_DIR "/server/ut-zone-admin/zones/test.conf"; -const std::string TEST_NO_SHUTDOWN_CONFIG_PATH = VSM_TEST_CONFIG_INSTALL_DIR "/server/ut-zone-admin/zones/test-no-shutdown.conf"; -const std::string BUGGY_CONFIG_PATH = VSM_TEST_CONFIG_INSTALL_DIR "/server/ut-zone-admin/zones/buggy.conf"; -const std::string MISSING_CONFIG_PATH = VSM_TEST_CONFIG_INSTALL_DIR "/server/ut-zone-admin/zones/missing.conf"; +const std::string ZONES_CONFIG_DIR = VSM_TEST_CONFIG_INSTALL_DIR "/server/ut-zone-admin/zones"; +const std::string TEST_CONFIG_PATH = ZONES_CONFIG_DIR + "/test.conf"; +const std::string TEST_NO_SHUTDOWN_CONFIG_PATH = ZONES_CONFIG_DIR + "/test-no-shutdown.conf"; +const std::string BUGGY_CONFIG_PATH = ZONES_CONFIG_DIR + "/buggy.conf"; +const std::string MISSING_CONFIG_PATH = ZONES_CONFIG_DIR + "/missing.conf"; const std::string ZONES_PATH = "/tmp/ut-zones"; const std::string LXC_TEMPLATES_PATH = VSM_TEST_LXC_TEMPLATES_INSTALL_DIR; diff --git a/tests/unit_tests/server/ut-zone.cpp b/tests/unit_tests/server/ut-zone.cpp index 783fbf8..646a0a8 100644 --- a/tests/unit_tests/server/ut-zone.cpp +++ b/tests/unit_tests/server/ut-zone.cpp @@ -45,10 +45,11 @@ using namespace config; namespace { -const std::string TEST_CONFIG_PATH = VSM_TEST_CONFIG_INSTALL_DIR "/server/ut-zone/zones/test.conf"; -const std::string TEST_DBUS_CONFIG_PATH = VSM_TEST_CONFIG_INSTALL_DIR "/server/ut-zone/zones/test-dbus.conf"; -const std::string BUGGY_CONFIG_PATH = VSM_TEST_CONFIG_INSTALL_DIR "/server/ut-zone/zones/buggy.conf"; -const std::string MISSING_CONFIG_PATH = "/this/is/a/missing/file/path/config.conf"; +const std::string ZONES_CONFIG_DIR = VSM_TEST_CONFIG_INSTALL_DIR "/server/ut-zone/zones"; +const std::string TEST_CONFIG_PATH = ZONES_CONFIG_DIR + "/test.conf"; +const std::string TEST_DBUS_CONFIG_PATH = ZONES_CONFIG_DIR + "/test-dbus.conf"; +const std::string BUGGY_CONFIG_PATH = ZONES_CONFIG_DIR + "/buggy.conf"; +const std::string MISSING_CONFIG_PATH = ZONES_CONFIG_DIR + "/missing.conf"; const std::string ZONES_PATH = "/tmp/ut-zones"; const std::string LXC_TEMPLATES_PATH = VSM_TEST_LXC_TEMPLATES_INSTALL_DIR; const std::string DB_PATH = ZONES_PATH + "/vasum.db"; diff --git a/tests/unit_tests/server/ut-zones-manager.cpp b/tests/unit_tests/server/ut-zones-manager.cpp index b0ab2e2..a32aaa7 100644 --- a/tests/unit_tests/server/ut-zones-manager.cpp +++ b/tests/unit_tests/server/ut-zones-manager.cpp @@ -61,12 +61,12 @@ using namespace dbus; namespace { -const std::string TEST_CONFIG_PATH = VSM_TEST_CONFIG_INSTALL_DIR "/server/ut-zones-manager/test-daemon.conf"; -const std::string TEST_DBUS_CONFIG_PATH = VSM_TEST_CONFIG_INSTALL_DIR "/server/ut-zones-manager/test-dbus-daemon.conf"; -const std::string EMPTY_DBUS_CONFIG_PATH = VSM_TEST_CONFIG_INSTALL_DIR "/server/ut-zones-manager/empty-dbus-daemon.conf"; -const std::string BUGGY_CONFIG_PATH = VSM_TEST_CONFIG_INSTALL_DIR "/server/ut-zones-manager/buggy-daemon.conf"; -const std::string TEST_ZONE_CONF_PATH = VSM_TEST_CONFIG_INSTALL_DIR "/server/ut-zones-manager/zones/"; -const std::string MISSING_CONFIG_PATH = "/this/is/a/missing/file/path/missing-daemon.conf"; +const std::string CONFIG_DIR = VSM_TEST_CONFIG_INSTALL_DIR "/server/ut-zones-manager"; +const std::string TEST_CONFIG_PATH = CONFIG_DIR + "/test-daemon.conf"; +const std::string TEST_DBUS_CONFIG_PATH = CONFIG_DIR + "/test-dbus-daemon.conf"; +const std::string EMPTY_DBUS_CONFIG_PATH = CONFIG_DIR + "/empty-dbus-daemon.conf"; +const std::string BUGGY_CONFIG_PATH = CONFIG_DIR + "/buggy-daemon.conf"; +const std::string MISSING_CONFIG_PATH = CONFIG_DIR + "/missing-daemon.conf"; const int EVENT_TIMEOUT = 5000; const int UNEXPECTED_EVENT_TIMEOUT = EVENT_TIMEOUT / 5; const int TEST_DBUS_CONNECTION_ZONES_COUNT = 3; -- 2.7.4 From 9dfee0f5df9bc2a0ef5b97550bb6a1c69cc0176e Mon Sep 17 00:00:00 2001 From: Piotr Bartosiewicz Date: Thu, 12 Feb 2015 10:21:18 +0100 Subject: [PATCH 07/16] Don't store dynamic config in conf files [Bug/Feature] Per-zone mutable config fields (ip, vt and more in the future) goes to dynamic config. [Cause] N/A [Solution] N/A [Verification] Build, run tests Change-Id: I2a59b0292fc326a689e3ff9375da1199dc8b7618 --- server/configs/daemon.conf.in | 3 +- server/configs/templates/default.conf | 3 +- server/server.cpp | 10 - server/zone-admin.cpp | 24 +- server/zone-admin.hpp | 10 +- server/zone-config.hpp | 77 ++++--- server/zone.cpp | 25 +- server/zone.hpp | 7 +- server/zones-manager-config.hpp | 13 +- server/zones-manager.cpp | 119 +++++----- server/zones-manager.hpp | 6 +- tests/unit_tests/client/configs/CMakeLists.txt | 18 +- .../ut-client/templates/console-dbus.conf.in} | 1 - .../configs/ut-client/test-daemon.conf.in} | 5 +- .../configs/ut-client/test-dbus-daemon.conf.in | 25 -- .../configs/ut-client/zones/console1-dbus.conf.in | 18 -- .../configs/ut-client/zones/console2-dbus.conf.in | 18 -- .../configs/ut-client/zones/console3-dbus.conf.in | 18 -- tests/unit_tests/client/ut-client.cpp | 37 +-- tests/unit_tests/server/configs/CMakeLists.txt | 60 ++--- .../server/configs/ut-server/buggy-daemon.conf.in | 18 -- .../{zones/zone1.conf => templates/default.conf} | 1 - .../server/configs/ut-server/test-daemon.conf.in | 7 +- .../server/configs/ut-server/zones/zone3.conf | 18 -- .../ut-zone-admin/{zones => templates}/buggy.conf | 1 - .../{zones => templates}/missing.conf | 1 - .../{zones => templates}/test-no-shutdown.conf | 1 - .../templates/test.conf} | 1 - .../server/configs/ut-zone-admin/zones/test.conf | 18 -- .../ut-zone/{zones => templates}/buggy.conf | 1 - .../ut-zone/{zones => templates}/test-dbus.conf.in | 3 +- .../configs/ut-zone/{zones => templates}/test.conf | 1 - .../configs/ut-zones-manager/buggy-daemon.conf.in | 18 -- .../console-dbus.conf.in} | 3 +- .../console1.conf => templates/console.conf} | 1 - .../configs/ut-zones-manager/test-daemon.conf.in | 14 +- .../ut-zones-manager/test-dbus-daemon.conf.in | 25 -- .../ut-zones-manager/zones/console1-dbus.conf.in | 18 -- .../ut-zones-manager/zones/console2-dbus.conf.in | 18 -- .../configs/ut-zones-manager/zones/console2.conf | 18 -- .../configs/ut-zones-manager/zones/console3.conf | 18 -- tests/unit_tests/server/ut-server.cpp | 26 ++- tests/unit_tests/server/ut-zone-admin.cpp | 24 +- tests/unit_tests/server/ut-zone.cpp | 15 +- tests/unit_tests/server/ut-zones-manager.cpp | 253 ++++++++++++--------- 45 files changed, 394 insertions(+), 625 deletions(-) rename tests/unit_tests/{server/configs/ut-zones-manager/templates/default.conf.in => client/configs/ut-client/templates/console-dbus.conf.in} (96%) rename tests/unit_tests/{server/configs/ut-zones-manager/empty-dbus-daemon.conf.in => client/configs/ut-client/test-daemon.conf.in} (80%) delete mode 100644 tests/unit_tests/client/configs/ut-client/test-dbus-daemon.conf.in delete mode 100644 tests/unit_tests/client/configs/ut-client/zones/console1-dbus.conf.in delete mode 100644 tests/unit_tests/client/configs/ut-client/zones/console2-dbus.conf.in delete mode 100644 tests/unit_tests/client/configs/ut-client/zones/console3-dbus.conf.in delete mode 100644 tests/unit_tests/server/configs/ut-server/buggy-daemon.conf.in rename tests/unit_tests/server/configs/ut-server/{zones/zone1.conf => templates/default.conf} (93%) delete mode 100644 tests/unit_tests/server/configs/ut-server/zones/zone3.conf rename tests/unit_tests/server/configs/ut-zone-admin/{zones => templates}/buggy.conf (92%) rename tests/unit_tests/server/configs/ut-zone-admin/{zones => templates}/missing.conf (92%) rename tests/unit_tests/server/configs/ut-zone-admin/{zones => templates}/test-no-shutdown.conf (92%) rename tests/unit_tests/server/configs/{ut-server/zones/zone2.conf => ut-zone-admin/templates/test.conf} (93%) delete mode 100644 tests/unit_tests/server/configs/ut-zone-admin/zones/test.conf rename tests/unit_tests/server/configs/ut-zone/{zones => templates}/buggy.conf (94%) rename tests/unit_tests/server/configs/ut-zone/{zones => templates}/test-dbus.conf.in (85%) rename tests/unit_tests/server/configs/ut-zone/{zones => templates}/test.conf (94%) delete mode 100644 tests/unit_tests/server/configs/ut-zones-manager/buggy-daemon.conf.in rename tests/unit_tests/server/configs/ut-zones-manager/{zones/console3-dbus.conf.in => templates/console-dbus.conf.in} (83%) rename tests/unit_tests/server/configs/ut-zones-manager/{zones/console1.conf => templates/console.conf} (91%) delete mode 100644 tests/unit_tests/server/configs/ut-zones-manager/test-dbus-daemon.conf.in delete mode 100644 tests/unit_tests/server/configs/ut-zones-manager/zones/console1-dbus.conf.in delete mode 100644 tests/unit_tests/server/configs/ut-zones-manager/zones/console2-dbus.conf.in delete mode 100644 tests/unit_tests/server/configs/ut-zones-manager/zones/console2.conf delete mode 100644 tests/unit_tests/server/configs/ut-zones-manager/zones/console3.conf diff --git a/server/configs/daemon.conf.in b/server/configs/daemon.conf.in index 327e470..a6359fa 100644 --- a/server/configs/daemon.conf.in +++ b/server/configs/daemon.conf.in @@ -1,10 +1,9 @@ { "dbPath" : "/usr/dbspace/vasum.db", - "zoneConfigs" : [], + "zoneIds" : [], "zonesPath" : "${DATA_DIR}/.zones", "zoneImagePath" : "", "zoneTemplateDir" : "/etc/vasum/templates/", - "zoneNewConfigPrefix" : "/var/lib/vasum", "runMountPointPrefix" : "/var/run/zones", "defaultId" : "", "lxcTemplatePrefix" : "/etc/vasum/lxc-templates", diff --git a/server/configs/templates/default.conf b/server/configs/templates/default.conf index 9690a87..2aa7a66 100644 --- a/server/configs/templates/default.conf +++ b/server/configs/templates/default.conf @@ -1,5 +1,4 @@ { - "name" : "~NAME~", "lxcTemplate" : "tizen-common-wayland.sh", "initWithArgs" : [], "ipv4Gateway" : "10.0.~IP~.1", @@ -7,7 +6,7 @@ "cpuQuotaForeground" : -1, "cpuQuotaBackground" : 1000, "privilege" : 10, - "vt" : ~VT~, + "vt" : 0, "switchToDefaultAfterTimeout" : true, "enableDbusIntegration" : true, "runMountPoint" : "~NAME~/run", diff --git a/server/server.cpp b/server/server.cpp index 874b02f..b4e2344 100644 --- a/server/server.cpp +++ b/server/server.cpp @@ -165,16 +165,6 @@ bool Server::prepareEnvironment(const std::string& configPath, bool runAsRoot) } } - // create directory for additional zone data (if needed) - if (!config.zoneNewConfigPrefix.empty()) { - if (!utils::createDir(config.zoneNewConfigPrefix, uid, gid, - fs::perms::owner_all | - fs::perms::group_read | fs::perms::group_exe | - fs::perms::others_read | fs::perms::others_exe)) { - return false; - } - } - // Omit supplementaty group setup and root drop if the user is already switched. // This situation will happen during daemon update triggered by SIGUSR1. if (!runAsRoot && geteuid() == uid) { diff --git a/server/zone-admin.cpp b/server/zone-admin.cpp index 46c4974..32a18d2 100644 --- a/server/zone-admin.cpp +++ b/server/zone-admin.cpp @@ -46,12 +46,14 @@ const int SHUTDOWN_WAIT = 10; const std::uint64_t DEFAULT_CPU_SHARES = 1024; const std::uint64_t DEFAULT_VCPU_PERIOD_MS = 100000; -ZoneAdmin::ZoneAdmin(const std::string& zonesPath, - const std::string& lxcTemplatePrefix, - const ZoneConfig& config) +ZoneAdmin::ZoneAdmin(const std::string& zoneId, + const std::string& zonesPath, + const std::string& lxcTemplatePrefix, + const ZoneConfig& config, + const ZoneDynamicConfig& dynamicConfig) : mConfig(config), - mZone(zonesPath, config.name), - mId(mZone.getName()), + mZone(zonesPath, zoneId), + mId(zoneId), mDetachOnExit(false), mDestroyOnExit(false) { @@ -63,16 +65,16 @@ ZoneAdmin::ZoneAdmin(const std::string& zonesPath, lxcTemplatePrefix); LOGI(mId << ": Creating zone from template: " << lxcTemplate); utils::CStringArrayBuilder args; - if (!config.ipv4Gateway.empty()) { + if (!dynamicConfig.ipv4Gateway.empty()) { args.add("--ipv4-gateway"); - args.add(config.ipv4Gateway.c_str()); + args.add(dynamicConfig.ipv4Gateway.c_str()); } - if (!config.ipv4.empty()) { + if (!dynamicConfig.ipv4.empty()) { args.add("--ipv4"); - args.add(config.ipv4.c_str()); + args.add(dynamicConfig.ipv4.c_str()); } - const std::string vt = std::to_string(config.vt); - if (config.vt > 0) { + const std::string vt = std::to_string(dynamicConfig.vt); + if (dynamicConfig.vt > 0) { args.add("--vt"); args.add(vt.c_str()); } diff --git a/server/zone-admin.hpp b/server/zone-admin.hpp index 1d31ab4..10b7f02 100644 --- a/server/zone-admin.hpp +++ b/server/zone-admin.hpp @@ -44,13 +44,17 @@ public: /** * ZoneAdmin constructor + * @param zoneId zone id * @param zonesPath directory where zones are defined (lxc configs, rootfs etc) * @param lxcTemplatePrefix directory where templates are stored * @param config zones config + * @param dynamicConfig zones dynamic config */ - ZoneAdmin(const std::string& zonesPath, - const std::string& lxcTemplatePrefix, - const ZoneConfig& config); + ZoneAdmin(const std::string& zoneId, + const std::string& zonesPath, + const std::string& lxcTemplatePrefix, + const ZoneConfig& config, + const ZoneDynamicConfig& dynamicConfig); virtual ~ZoneAdmin(); /** diff --git a/server/zone-config.hpp b/server/zone-config.hpp index 02db1c4..da4b570 100644 --- a/server/zone-config.hpp +++ b/server/zone-config.hpp @@ -38,11 +38,6 @@ namespace vasum { struct ZoneConfig { /** - * Zone name - */ - std::string name; - - /** * Lxc template name (relative to lxcTemplatePrefix) */ std::string lxcTemplate; @@ -53,27 +48,12 @@ struct ZoneConfig { std::vector initWithArgs; /** - * IP v4 gateway address - */ - std::string ipv4Gateway; - - /** - * IP v4 address - */ - std::string ipv4; - - /** * Privilege of the zone. * The smaller the value the more important the zone */ int privilege; /** - * Number of virtual terminal used by xserver inside zone - */ - int vt; - - /** * Allow switching to default zone after timeout. * Setting this to false will disable switching to default zone after timeout. */ @@ -96,11 +76,6 @@ struct ZoneConfig { std::int64_t cpuQuotaBackground; /** - * Path to zones dbus unix socket - */ - std::string runMountPoint; - - /** * When you move a file out of the zone (by move request) * its path must match at least one of the regexps in this vector. */ @@ -119,27 +94,57 @@ struct ZoneConfig { CONFIG_REGISTER ( - name, lxcTemplate, initWithArgs, - ipv4Gateway, - ipv4, - privilege, - vt, - switchToDefaultAfterTimeout, + privilege, // TODO not needed? + switchToDefaultAfterTimeout, // TODO move to dynamic and add an API to change enableDbusIntegration, cpuQuotaForeground, cpuQuotaBackground, - runMountPoint, - permittedToSend, - permittedToRecv, + permittedToSend, // TODO move to dynamic and add an API to change + permittedToRecv, // TODO move to dynamic and add an API to change validLinkPrefixes ) }; struct ZoneDynamicConfig { - //TODO a place for zone dynamic config (other than provisioning which has its own struct) - CONFIG_REGISTER_EMPTY + + /** + * IP v4 gateway address + */ + std::string ipv4Gateway; + + /** + * IP v4 address + */ + std::string ipv4; + + /** + * Number of virtual terminal used by xserver inside zone + */ + int vt; + + /** + * Path to zones dbus unix socket + */ + std::string runMountPoint; + + CONFIG_REGISTER + ( + ipv4Gateway, + ipv4, + vt, + runMountPoint + ) +}; + +struct ZoneTemplatePathConfig { + /** + * A path to zone template config (containing default values) + */ + std::string zoneTemplatePath; + + CONFIG_REGISTER(zoneTemplatePath) }; } // namespace vasum diff --git a/server/zone.cpp b/server/zone.cpp index 0c2eca7..e8580e1 100644 --- a/server/zone.cpp +++ b/server/zone.cpp @@ -53,14 +53,17 @@ const int RECONNECT_DELAY = 1 * 1000; } // namespace Zone::Zone(const utils::Worker::Pointer& worker, + const std::string& zoneId, const std::string& zonesPath, - const std::string& zoneConfigPath, + const std::string& zoneTemplatePath, const std::string& dbPath, const std::string& lxcTemplatePrefix, const std::string& baseRunMountPointPath) : mWorker(worker) { - config::loadFromJsonFile(zoneConfigPath, mConfig); + const std::string dbPrefix = getZoneDbPrefix(zoneId); + config::loadFromKVStoreWithJsonFile(dbPath, zoneTemplatePath, mConfig, dbPrefix); + config::loadFromKVStoreWithJsonFile(dbPath, zoneTemplatePath, mDynamicConfig, dbPrefix); for (std::string r: mConfig.permittedToSend) { mPermittedToSend.push_back(boost::regex(r)); @@ -69,18 +72,16 @@ Zone::Zone(const utils::Worker::Pointer& worker, mPermittedToRecv.push_back(boost::regex(r)); } - if (!mConfig.runMountPoint.empty()) { - mRunMountPoint = fs::absolute(mConfig.runMountPoint, baseRunMountPointPath).string(); + if (!mDynamicConfig.runMountPoint.empty()) { + mRunMountPoint = fs::absolute(mDynamicConfig.runMountPoint, baseRunMountPointPath).string(); } - mAdmin.reset(new ZoneAdmin(zonesPath, lxcTemplatePrefix, mConfig)); + mAdmin.reset(new ZoneAdmin(zoneId, zonesPath, lxcTemplatePrefix, mConfig, mDynamicConfig)); - const fs::path zonePath = fs::path(zonesPath) / mAdmin->getId(); + const fs::path zonePath = fs::path(zonesPath) / zoneId; mRootPath = (zonePath / fs::path("rootfs")).string(); - const std::string dbPrefix = getZoneDbPrefix(mAdmin->getId()); - config::loadFromKVStoreWithJsonFile(dbPath, zoneConfigPath, mDynamicConfig, dbPrefix); - mProvision.reset(new ZoneProvision(mRootPath, zoneConfigPath, dbPath, dbPrefix, mConfig.validLinkPrefixes)); + mProvision.reset(new ZoneProvision(mRootPath, zoneTemplatePath, dbPath, dbPrefix, mConfig.validLinkPrefixes)); } Zone::~Zone() @@ -187,7 +188,7 @@ std::string Zone::getDbusAddress() const int Zone::getVT() const { - return mConfig.vt; + return mDynamicConfig.vt; } std::string Zone::getRootPath() const @@ -199,8 +200,8 @@ bool Zone::activateVT() { Lock lock(mReconnectMutex); - if (mConfig.vt >= 0) { - return utils::activateVT(mConfig.vt); + if (mDynamicConfig.vt >= 0) { + return utils::activateVT(mDynamicConfig.vt); } return true; diff --git a/server/zone.hpp b/server/zone.hpp index dbffc22..b708811 100644 --- a/server/zone.hpp +++ b/server/zone.hpp @@ -47,14 +47,17 @@ class Zone { public: /** * Zone constructor + * @param zoneId zone id * @param zonesPath directory where zones are defined (lxc configs, rootfs etc) - * @param zoneConfigPath path for zones config + * @param zoneTemplatePath path for zones config template + * @param dbPath path to dynamic config db file * @param lxcTemplatePrefix directory where templates are stored * @param baseRunMountPointPath base directory for run mount point */ Zone(const utils::Worker::Pointer& worker, + const std::string& zoneId, const std::string& zonesPath, - const std::string& zoneConfigPath, + const std::string& zoneTemplatePath, const std::string& dbPath, const std::string& lxcTemplatePrefix, const std::string& baseRunMountPointPath); diff --git a/server/zones-manager-config.hpp b/server/zones-manager-config.hpp index 3ae6e5a..bfc1b25 100644 --- a/server/zones-manager-config.hpp +++ b/server/zones-manager-config.hpp @@ -60,11 +60,6 @@ struct ZonesManagerConfig { std::string zoneTemplateDir; /** - * Prefix added to a path for new zone configuration files - */ - std::string zoneNewConfigPrefix; - - /** * Path prefix for lxc templates */ std::string lxcTemplatePrefix; @@ -95,7 +90,6 @@ struct ZonesManagerConfig { zonesPath, zoneImagePath, zoneTemplateDir, - zoneNewConfigPrefix, lxcTemplatePrefix, availableVTs, inputConfig, @@ -107,10 +101,9 @@ struct ZonesManagerConfig { struct ZonesManagerDynamicConfig { /** - * List of zones' configs that we manage. - * File paths can be relative to the ZoneManager config file. + * A list of created zones. */ - std::vector zoneConfigs; + std::vector zoneIds; /** * An ID of default zone. @@ -119,7 +112,7 @@ struct ZonesManagerDynamicConfig { CONFIG_REGISTER ( - zoneConfigs, + zoneIds, defaultId ) }; diff --git a/server/zones-manager.cpp b/server/zones-manager.cpp index 3baa2a2..bccfd21 100644 --- a/server/zones-manager.cpp +++ b/server/zones-manager.cpp @@ -70,15 +70,9 @@ const std::string ENABLED_FILE_NAME = "enabled"; const boost::regex ZONE_NAME_REGEX("~NAME~"); const boost::regex ZONE_IP_THIRD_OCTET_REGEX("~IP~"); -const boost::regex ZONE_VT_REGEX("~VT~"); const unsigned int ZONE_IP_BASE_THIRD_OCTET = 100; -std::string getConfigName(const std::string& zoneId) -{ - return "zones/" + zoneId + ".conf"; -} - template void remove(std::vector& v, const T& item) { @@ -189,8 +183,8 @@ ZonesManager::ZonesManager(const std::string& configPath) mHostConnection.setRevokeDeviceCallback(bind(&ZonesManager::handleRevokeDeviceCall, this, _1, _2, _3)); - for (const auto& zoneConfig : mDynamicConfig.zoneConfigs) { - insertZone(utils::createFilePath(mConfig.zoneNewConfigPrefix, zoneConfig)); + for (const auto& zoneId : mDynamicConfig.zoneIds) { + insertZone(zoneId, getTemplatePathForExistingZone(zoneId)); } updateDefaultId(); @@ -269,38 +263,46 @@ void ZonesManager::updateDefaultId() saveDynamicConfig(); } -void ZonesManager::insertZone(const std::string& zoneConfigPath) +std::string ZonesManager::getTemplatePathForExistingZone(const std::string& id) { - LOGT("Creating Zone " << zoneConfigPath); + ZoneTemplatePathConfig config; + config::loadFromKVStore(mConfig.dbPath, config, getZoneDbPrefix(id)); + return config.zoneTemplatePath; +} + +void ZonesManager::insertZone(const std::string& zoneId, const std::string& zoneTemplatePath) +{ + if (zoneId == HOST_ID) { + throw InvalidZoneIdException("Cannot use reserved zone ID"); + } + if (findZone(zoneId) != mZones.end()) { + throw InvalidZoneIdException("Zone already exists"); + } + + LOGT("Creating Zone " << zoneId); std::unique_ptr zone(new Zone(mWorker->createSubWorker(), + zoneId, mConfig.zonesPath, - zoneConfigPath, + zoneTemplatePath, mConfig.dbPath, mConfig.lxcTemplatePrefix, mConfig.runMountPointPrefix)); - const std::string id = zone->getId(); - if (id == HOST_ID) { - throw InvalidZoneIdException("Cannot use reserved zone ID"); - } - if (findZone(id) != mZones.end()) { - throw InvalidZoneIdException("Zone already exists"); - } using namespace std::placeholders; zone->setNotifyActiveZoneCallback(bind(&ZonesManager::notifyActiveZoneHandler, - this, id, _1, _2)); + this, zoneId, _1, _2)); zone->setDisplayOffCallback(bind(&ZonesManager::displayOffHandler, - this, id)); + this, zoneId)); zone->setFileMoveRequestCallback(bind(&ZonesManager::handleZoneMoveFileRequest, - this, id, _1, _2, _3)); + this, zoneId, _1, _2, _3)); zone->setProxyCallCallback(bind(&ZonesManager::handleProxyCall, - this, id, _1, _2, _3, _4, _5, _6, _7)); + this, zoneId, _1, _2, _3, _4, _5, _6, _7)); zone->setDbusStateChangedCallback(bind(&ZonesManager::handleDbusStateChanged, - this, id, _1)); + this, zoneId, _1)); mZones.push_back(std::move(zone)); @@ -333,7 +335,7 @@ void ZonesManager::destroyZone(const std::string& zoneId) } // update dynamic config - remove(mDynamicConfig.zoneConfigs, getConfigName(zoneId)); + remove(mDynamicConfig.zoneIds, zoneId); saveDynamicConfig(); updateDefaultId(); @@ -932,52 +934,40 @@ void ZonesManager::handleSetActiveZoneCall(const std::string& id, void ZonesManager::generateNewConfig(const std::string& id, - const std::string& templatePath, - const std::string& resultPath) + const std::string& templatePath) { - // TODO Do not store new config at all, use template and dynamic config instead - namespace fs = boost::filesystem; + const std::string dbPrefix = getZoneDbPrefix(id); + ZoneDynamicConfig dynamicConfig; + config::loadFromKVStoreWithJsonFile(mConfig.dbPath, templatePath, dynamicConfig, dbPrefix); - if (fs::exists(resultPath)) { - LOGT(resultPath << " already exists, removing"); - fs::remove(resultPath); - } else { - std::string resultFileDir = utils::dirName(resultPath); - if (!utils::createDirs(resultFileDir, fs::perms::owner_all | - fs::perms::group_read | fs::perms::group_exe | - fs::perms::others_read | fs::perms::others_exe)) { - LOGE("Unable to create directory for new config."); - throw ZoneOperationException("Unable to create directory for new config."); - } - } - - std::string config; - if (!utils::readFileContent(templatePath, config)) { - LOGE("Failed to read template config file."); - throw ZoneOperationException("Failed to read template config file."); - } - - std::string resultConfig = boost::regex_replace(config, ZONE_NAME_REGEX, id); + // update mount point path + dynamicConfig.runMountPoint = boost::regex_replace(dynamicConfig.runMountPoint, + ZONE_NAME_REGEX, + id); // generate first free VT number const int freeVT = getVTForNewZone(); LOGD("VT number: " << freeVT); - resultConfig = boost::regex_replace(resultConfig, ZONE_VT_REGEX, std::to_string(freeVT)); + dynamicConfig.vt = freeVT; // generate third IP octet for network config std::string thirdOctetStr = std::to_string(ZONE_IP_BASE_THIRD_OCTET + freeVT); LOGD("IP third octet: " << thirdOctetStr); - resultConfig = boost::regex_replace(resultConfig, ZONE_IP_THIRD_OCTET_REGEX, thirdOctetStr); + dynamicConfig.ipv4Gateway = boost::regex_replace(dynamicConfig.ipv4Gateway, + ZONE_IP_THIRD_OCTET_REGEX, + thirdOctetStr); + dynamicConfig.ipv4 = boost::regex_replace(dynamicConfig.ipv4, + ZONE_IP_THIRD_OCTET_REGEX, + thirdOctetStr); - if (!utils::saveFileContent(resultPath, resultConfig)) { - LOGE("Faield to save new config file."); - throw ZoneOperationException("Failed to save new config file."); - } + // save dynamic config + config::saveToKVStore(mConfig.dbPath, dynamicConfig, dbPrefix); + + // save zone template path + ZoneTemplatePathConfig templatePathConfig; + templatePathConfig.zoneTemplatePath = templatePath; + config::saveToKVStore(mConfig.dbPath, templatePathConfig, dbPrefix); - // restrict new config file so that only owner (vasum) can write it - fs::permissions(resultPath, fs::perms::owner_read | fs::perms::owner_write | - fs::perms::group_read | - fs::perms::others_read); } int ZonesManager::getVTForNewZone() @@ -1035,10 +1025,6 @@ void ZonesManager::createZone(const std::string& id, } } - // generate paths to new configuration files - std::string newConfigName = getConfigName(id); - std::string newConfigPath = utils::createFilePath(mConfig.zoneNewConfigPrefix, newConfigName); - auto removeAllWrapper = [](const std::string& path) -> bool { try { LOGD("Removing copied data"); @@ -1053,9 +1039,8 @@ void ZonesManager::createZone(const std::string& id, templateName + ".conf"); try { - LOGI("Generating config from " << zoneTemplatePath << " to " << newConfigPath); - generateNewConfig(id, zoneTemplatePath, newConfigPath); - + LOGI("Generating config from " << zoneTemplatePath); + generateNewConfig(id, zoneTemplatePath); } catch (VasumException& e) { LOGE("Generate config failed: " << e.what()); utils::launchAsRoot(std::bind(removeAllWrapper, zonePathStr)); @@ -1064,14 +1049,14 @@ void ZonesManager::createZone(const std::string& id, LOGT("Creating new zone"); try { - insertZone(newConfigPath); + insertZone(id, zoneTemplatePath); } catch (VasumException& e) { LOGE("Creating new zone failed: " << e.what()); utils::launchAsRoot(std::bind(removeAllWrapper, zonePathStr)); throw e; } - mDynamicConfig.zoneConfigs.push_back(newConfigName); + mDynamicConfig.zoneIds.push_back(id); saveDynamicConfig(); updateDefaultId(); } diff --git a/server/zones-manager.hpp b/server/zones-manager.hpp index 529ef8b..6453278 100644 --- a/server/zones-manager.hpp +++ b/server/zones-manager.hpp @@ -135,10 +135,10 @@ private: void refocus(); void switchingSequenceMonitorNotify(); void generateNewConfig(const std::string& id, - const std::string& templatePath, - const std::string& resultPath); + const std::string& templatePath); + std::string getTemplatePathForExistingZone(const std::string& id); int getVTForNewZone(); - void insertZone(const std::string& zoneConfigPath); + void insertZone(const std::string& zoneId, const std::string& templatePath); void notifyActiveZoneHandler(const std::string& caller, const std::string& appliaction, diff --git a/tests/unit_tests/client/configs/CMakeLists.txt b/tests/unit_tests/client/configs/CMakeLists.txt index 8742612..5587d11 100644 --- a/tests/unit_tests/client/configs/CMakeLists.txt +++ b/tests/unit_tests/client/configs/CMakeLists.txt @@ -20,20 +20,16 @@ MESSAGE(STATUS "Installing configs for the Client Unit Tests to " ${VSM_TEST_CONFIG_INSTALL_DIR}) ## Generate #################################################################### -CONFIGURE_FILE(ut-client/test-dbus-daemon.conf.in - ${CMAKE_BINARY_DIR}/ut-client/test-dbus-daemon.conf @ONLY) +CONFIGURE_FILE(ut-client/test-daemon.conf.in + ${CMAKE_BINARY_DIR}/ut-client/test-daemon.conf @ONLY) FILE(GLOB client_manager_CONF_GEN ${CMAKE_BINARY_DIR}/ut-client/*.conf) -CONFIGURE_FILE(ut-client/zones/console1-dbus.conf.in - ${CMAKE_BINARY_DIR}/ut-client/zones/console1-dbus.conf @ONLY) -CONFIGURE_FILE(ut-client/zones/console2-dbus.conf.in - ${CMAKE_BINARY_DIR}/ut-client/zones/console2-dbus.conf @ONLY) -CONFIGURE_FILE(ut-client/zones/console3-dbus.conf.in - ${CMAKE_BINARY_DIR}/ut-client/zones/console3-dbus.conf @ONLY) -FILE(GLOB client_zone_CONF_GEN ${CMAKE_BINARY_DIR}/ut-client/zones/*.conf) +CONFIGURE_FILE(ut-client/templates/console-dbus.conf.in + ${CMAKE_BINARY_DIR}/ut-client/templates/console-dbus.conf @ONLY) +FILE(GLOB client_templates_CONF_GEN ${CMAKE_BINARY_DIR}/ut-client/templates/*.conf) ## Install ##################################################################### INSTALL(FILES ${client_manager_CONF_GEN} DESTINATION ${VSM_TEST_CONFIG_INSTALL_DIR}/client/ut-client) -INSTALL(FILES ${client_zone_CONF_GEN} - DESTINATION ${VSM_TEST_CONFIG_INSTALL_DIR}/client/ut-client/zones) +INSTALL(FILES ${client_templates_CONF_GEN} + DESTINATION ${VSM_TEST_CONFIG_INSTALL_DIR}/client/ut-client/templates) diff --git a/tests/unit_tests/server/configs/ut-zones-manager/templates/default.conf.in b/tests/unit_tests/client/configs/ut-client/templates/console-dbus.conf.in similarity index 96% rename from tests/unit_tests/server/configs/ut-zones-manager/templates/default.conf.in rename to tests/unit_tests/client/configs/ut-client/templates/console-dbus.conf.in index 28879db..0bd0e03 100644 --- a/tests/unit_tests/server/configs/ut-zones-manager/templates/default.conf.in +++ b/tests/unit_tests/client/configs/ut-client/templates/console-dbus.conf.in @@ -1,5 +1,4 @@ { - "name" : "~NAME~", "lxcTemplate" : "minimal-dbus.sh", "initWithArgs" : ["/bin/sh", "-c", "trap exit SIGTERM; /usr/bin/dbus-daemon --config-file=@VSM_TEST_CONFIG_INSTALL_DIR@/server/ut-zones-manager/ut-dbus.conf --fork; read"], "ipv4Gateway" : "", diff --git a/tests/unit_tests/server/configs/ut-zones-manager/empty-dbus-daemon.conf.in b/tests/unit_tests/client/configs/ut-client/test-daemon.conf.in similarity index 80% rename from tests/unit_tests/server/configs/ut-zones-manager/empty-dbus-daemon.conf.in rename to tests/unit_tests/client/configs/ut-client/test-daemon.conf.in index 83b1124..6346df3 100644 --- a/tests/unit_tests/server/configs/ut-zones-manager/empty-dbus-daemon.conf.in +++ b/tests/unit_tests/client/configs/ut-client/test-daemon.conf.in @@ -1,11 +1,10 @@ { "dbPath" : "/tmp/ut-zones/vasum.db", - "zoneConfigs" : [], + "zoneIds" : [], "defaultId" : "", "zonesPath" : "/tmp/ut-zones", "zoneImagePath" : "", - "zoneTemplateDir" : "@VSM_TEST_CONFIG_INSTALL_DIR@/server/ut-zones-manager/templates/", - "zoneNewConfigPrefix" : "/tmp/ut-zones/generated-configs/", + "zoneTemplateDir" : "@VSM_TEST_CONFIG_INSTALL_DIR@/client/ut-client/templates/", "runMountPointPrefix" : "", "lxcTemplatePrefix" : "@VSM_TEST_LXC_TEMPLATES_INSTALL_DIR@", "availableVTs" : [], diff --git a/tests/unit_tests/client/configs/ut-client/test-dbus-daemon.conf.in b/tests/unit_tests/client/configs/ut-client/test-dbus-daemon.conf.in deleted file mode 100644 index b51ee9a..0000000 --- a/tests/unit_tests/client/configs/ut-client/test-dbus-daemon.conf.in +++ /dev/null @@ -1,25 +0,0 @@ -{ - "dbPath" : "/tmp/ut-zones/vasum.db", - "zoneConfigs" : ["zones/console1-dbus.conf", - "zones/console2-dbus.conf", - "zones/console3-dbus.conf"], - "defaultId" : "ut-zones-manager-console1-dbus", - "zonesPath" : "/tmp/ut-zones", - "zoneImagePath" : "", - "zoneTemplateDir" : "no_need_for_templates_in_this_test", - "zoneNewConfigPrefix" : "@VSM_TEST_CONFIG_INSTALL_DIR@/client/ut-client/", - "runMountPointPrefix" : "", - "lxcTemplatePrefix" : "@VSM_TEST_LXC_TEMPLATES_INSTALL_DIR@", - "availableVTs" : [], - "inputConfig" : {"enabled" : false, - "device" : "/dev/doesnotexist", - "code" : 139, - "numberOfEvents" : 2, - "timeWindowMs" : 500}, - "proxyCallRules" : [{"caller" : "*", - "target" : "*", - "targetBusName" : "org.tizen.vasum.tests", - "targetObjectPath" : "*", - "targetInterface" : "*", - "targetMethod" : "*"}] -} diff --git a/tests/unit_tests/client/configs/ut-client/zones/console1-dbus.conf.in b/tests/unit_tests/client/configs/ut-client/zones/console1-dbus.conf.in deleted file mode 100644 index 097480d..0000000 --- a/tests/unit_tests/client/configs/ut-client/zones/console1-dbus.conf.in +++ /dev/null @@ -1,18 +0,0 @@ -{ - "name" : "ut-zones-manager-console1-dbus", - "lxcTemplate" : "minimal-dbus.sh", - "initWithArgs" : ["/bin/sh", "-c", "trap exit SIGTERM; /usr/bin/dbus-daemon --config-file=@VSM_TEST_CONFIG_INSTALL_DIR@/server/ut-zones-manager/ut-dbus.conf --fork; read"], - "ipv4Gateway" : "", - "ipv4" : "", - "privilege" : 20, - "vt" : -1, - "switchToDefaultAfterTimeout" : true, - "enableDbusIntegration" : true, - "cpuQuotaForeground" : -1, - "cpuQuotaBackground" : 1000, - "runMountPoint" : "/tmp/ut-run/ut-zones-manager-console1-dbus", - "provisions" : [], - "permittedToSend" : [ "/tmp/.*", "/etc/secret2" ], - "permittedToRecv" : [ "/tmp/.*" ], - "validLinkPrefixes" : [] -} diff --git a/tests/unit_tests/client/configs/ut-client/zones/console2-dbus.conf.in b/tests/unit_tests/client/configs/ut-client/zones/console2-dbus.conf.in deleted file mode 100644 index 440772b..0000000 --- a/tests/unit_tests/client/configs/ut-client/zones/console2-dbus.conf.in +++ /dev/null @@ -1,18 +0,0 @@ -{ - "name" : "ut-zones-manager-console2-dbus", - "lxcTemplate" : "minimal-dbus.sh", - "initWithArgs" : ["/bin/sh", "-c", "trap exit SIGTERM; /usr/bin/dbus-daemon --config-file=@VSM_TEST_CONFIG_INSTALL_DIR@/server/ut-zones-manager/ut-dbus.conf --fork; read"], - "ipv4Gateway" : "", - "ipv4" : "", - "privilege" : 20, - "vt" : -1, - "switchToDefaultAfterTimeout" : false, - "enableDbusIntegration" : true, - "cpuQuotaForeground" : -1, - "cpuQuotaBackground" : 1000, - "runMountPoint" : "/tmp/ut-run/ut-zones-manager-console2-dbus", - "provisions" : [], - "permittedToSend" : [ "/tmp/.*" ], - "permittedToRecv" : [ "/tmp/.*", "/etc/secret1" ], - "validLinkPrefixes" : [] -} diff --git a/tests/unit_tests/client/configs/ut-client/zones/console3-dbus.conf.in b/tests/unit_tests/client/configs/ut-client/zones/console3-dbus.conf.in deleted file mode 100644 index 2f28ee1..0000000 --- a/tests/unit_tests/client/configs/ut-client/zones/console3-dbus.conf.in +++ /dev/null @@ -1,18 +0,0 @@ -{ - "name" : "ut-zones-manager-console3-dbus", - "lxcTemplate" : "minimal-dbus.sh", - "initWithArgs" : ["/bin/sh", "-c", "trap exit SIGTERM; /usr/bin/dbus-daemon --config-file=@VSM_TEST_CONFIG_INSTALL_DIR@/server/ut-zones-manager/ut-dbus.conf --fork; read"], - "ipv4Gateway" : "", - "ipv4" : "", - "privilege" : 20, - "vt" : -1, - "switchToDefaultAfterTimeout" : true, - "enableDbusIntegration" : true, - "cpuQuotaForeground" : -1, - "cpuQuotaBackground" : 1000, - "runMountPoint" : "/tmp/ut-run/ut-zones-manager-console3-dbus", - "provisions" : [], - "permittedToSend" : [ "/tmp/.*" ], - "permittedToRecv" : [ "/tmp/.*" ], - "validLinkPrefixes" : [] -} diff --git a/tests/unit_tests/client/ut-client.cpp b/tests/unit_tests/client/ut-client.cpp index a188a9d..1c55668 100644 --- a/tests/unit_tests/client/ut-client.cpp +++ b/tests/unit_tests/client/ut-client.cpp @@ -31,6 +31,7 @@ #include "utils/scoped-dir.hpp" #include "zones-manager.hpp" #include "zone-dbus-definitions.hpp" +#include "logger/logger.hpp" #include #include @@ -45,9 +46,10 @@ using namespace vasum::utils; namespace { -const std::string TEST_DBUS_CONFIG_PATH = - VSM_TEST_CONFIG_INSTALL_DIR "/client/ut-client/test-dbus-daemon.conf"; +const std::string TEST_CONFIG_PATH = + VSM_TEST_CONFIG_INSTALL_DIR "/client/ut-client/test-daemon.conf"; const std::string ZONES_PATH = "/tmp/ut-zones"; // the same as in daemon.conf +const std::string TEMPLATE_NAME = "console-dbus"; struct Loop { Loop() @@ -70,25 +72,34 @@ struct Fixture { Fixture() : mZonesPathGuard(ZONES_PATH) , mRunGuard("/tmp/ut-run") - , cm(TEST_DBUS_CONFIG_PATH) + , cm(TEST_CONFIG_PATH) { + cm.createZone("zone1", TEMPLATE_NAME); + cm.createZone("zone2", TEMPLATE_NAME); + cm.createZone("zone3", TEMPLATE_NAME); cm.startAll(); + LOGI("------- setup complete --------"); + } + + ~Fixture() + { + LOGI("------- cleanup --------"); } }; const int EVENT_TIMEOUT = 5000; ///< ms const std::map EXPECTED_DBUSES_STARTED = { { - "ut-zones-manager-console1-dbus", - "unix:path=/tmp/ut-run/ut-zones-manager-console1-dbus/dbus/system_bus_socket" + "zone1", + "unix:path=/tmp/ut-run/zone1/dbus/system_bus_socket" }, { - "ut-zones-manager-console2-dbus", - "unix:path=/tmp/ut-run/ut-zones-manager-console2-dbus/dbus/system_bus_socket" + "zone2", + "unix:path=/tmp/ut-run/zone2/dbus/system_bus_socket" }, { - "ut-zones-manager-console3-dbus", - "unix:path=/tmp/ut-run/ut-zones-manager-console3-dbus/dbus/system_bus_socket" + "zone3", + "unix:path=/tmp/ut-run/zone3/dbus/system_bus_socket" } }; @@ -212,7 +223,7 @@ BOOST_AUTO_TEST_CASE(GetActiveZoneIdTest) BOOST_AUTO_TEST_CASE(SetActiveZoneTest) { - const std::string newActiveZoneId = "ut-zones-manager-console2-dbus"; + const std::string newActiveZoneId = "zone2"; BOOST_REQUIRE_NE(newActiveZoneId, cm.getRunningForegroundZoneId()); @@ -239,7 +250,7 @@ BOOST_AUTO_TEST_CASE(CreateZoneTest) BOOST_AUTO_TEST_CASE(StartShutdownZoneTest) { - const std::string newActiveZoneId = "ut-zones-manager-console1-dbus"; + const std::string newActiveZoneId = "zone1"; VsmClient client = vsm_client_create(); VsmStatus status = vsm_connect(client); @@ -253,7 +264,7 @@ BOOST_AUTO_TEST_CASE(StartShutdownZoneTest) BOOST_AUTO_TEST_CASE(LockUnlockZoneTest) { - const std::string newActiveZoneId = "ut-zones-manager-console2-dbus"; + const std::string newActiveZoneId = "zone2"; VsmClient client = vsm_client_create(); VsmStatus status = vsm_connect(client); @@ -374,7 +385,7 @@ BOOST_AUTO_TEST_CASE(GetZoneIdByPidTest2) BOOST_AUTO_TEST_CASE(GrantRevokeTest) { - const std::string zoneId = "ut-zones-manager-console2-dbus"; + const std::string zoneId = "zone2"; const std::string dev = "tty3"; VsmClient client = vsm_client_create(); diff --git a/tests/unit_tests/server/configs/CMakeLists.txt b/tests/unit_tests/server/configs/CMakeLists.txt index fca8500..6c8a1af 100644 --- a/tests/unit_tests/server/configs/CMakeLists.txt +++ b/tests/unit_tests/server/configs/CMakeLists.txt @@ -20,17 +20,17 @@ MESSAGE(STATUS "Installing configs for the Server Unit Tests to " ${VSM_TEST_CONFIG_INSTALL_DIR}) FILE(GLOB server_manager_CONF ut-server/*.conf) -FILE(GLOB server_zone_CONF ut-server/zones/*.conf) +FILE(GLOB server_templates_CONF ut-server/templates/*.conf) FILE(GLOB manager_manager_CONF ut-zones-manager/*.conf) -FILE(GLOB manager_zone_CONF ut-zones-manager/zones/*.conf) +FILE(GLOB manager_templates_CONF ut-zones-manager/templates/*.conf) FILE(GLOB zone_CONF ut-zone/*.conf) -FILE(GLOB zone_zone_CONF ut-zone/zones/*.conf) +FILE(GLOB zone_templates_CONF ut-zone/templates/*.conf) FILE(GLOB zone_provision_CONF ut-zone-provision/*.conf) -FILE(GLOB admin_zone_CONF ut-zone-admin/zones/*.conf) +FILE(GLOB admin_templates_CONF ut-zone-admin/templates/*.conf) FILE(GLOB connection_CONF ut-zone-connection/*.conf) @@ -38,35 +38,19 @@ FILE(GLOB connection_CONF ut-zone-connection/*.conf) ## Generate #################################################################### CONFIGURE_FILE(ut-server/test-daemon.conf.in ${CMAKE_BINARY_DIR}/ut-server/test-daemon.conf @ONLY) -CONFIGURE_FILE(ut-server/buggy-daemon.conf.in - ${CMAKE_BINARY_DIR}/ut-server/buggy-daemon.conf @ONLY) FILE(GLOB server_manager_CONF_GEN ${CMAKE_BINARY_DIR}/ut-server/*.conf) -CONFIGURE_FILE(ut-zone/zones/test-dbus.conf.in - ${CMAKE_BINARY_DIR}/ut-zone/zones/test-dbus.conf @ONLY) -FILE(GLOB zone_zone_CONF_GEN ${CMAKE_BINARY_DIR}/ut-zone/zones/*.conf) +CONFIGURE_FILE(ut-zone/templates/test-dbus.conf.in + ${CMAKE_BINARY_DIR}/ut-zone/templates/test-dbus.conf @ONLY) +FILE(GLOB zone_templates_CONF_GEN ${CMAKE_BINARY_DIR}/ut-zone/templates/*.conf) CONFIGURE_FILE(ut-zones-manager/test-daemon.conf.in ${CMAKE_BINARY_DIR}/ut-zones-manager/test-daemon.conf @ONLY) -CONFIGURE_FILE(ut-zones-manager/buggy-daemon.conf.in - ${CMAKE_BINARY_DIR}/ut-zones-manager/buggy-daemon.conf @ONLY) -CONFIGURE_FILE(ut-zones-manager/test-dbus-daemon.conf.in - ${CMAKE_BINARY_DIR}/ut-zones-manager/test-dbus-daemon.conf @ONLY) -CONFIGURE_FILE(ut-zones-manager/empty-dbus-daemon.conf.in - ${CMAKE_BINARY_DIR}/ut-zones-manager/empty-dbus-daemon.conf @ONLY) FILE(GLOB manager_manager_CONF_GEN ${CMAKE_BINARY_DIR}/ut-zones-manager/*.conf) -CONFIGURE_FILE(ut-zones-manager/zones/console1-dbus.conf.in - ${CMAKE_BINARY_DIR}/ut-zones-manager/zones/console1-dbus.conf @ONLY) -CONFIGURE_FILE(ut-zones-manager/zones/console2-dbus.conf.in - ${CMAKE_BINARY_DIR}/ut-zones-manager/zones/console2-dbus.conf @ONLY) -CONFIGURE_FILE(ut-zones-manager/zones/console3-dbus.conf.in - ${CMAKE_BINARY_DIR}/ut-zones-manager/zones/console3-dbus.conf @ONLY) -FILE(GLOB manager_zone_CONF_GEN ${CMAKE_BINARY_DIR}/ut-zones-manager/zones/*.conf) - -CONFIGURE_FILE(ut-zones-manager/templates/default.conf.in - ${CMAKE_BINARY_DIR}/ut-zones-manager/templates/default.conf @ONLY) -FILE(GLOB manager_zone_TEMPLATE_GEN ${CMAKE_BINARY_DIR}/ut-zones-manager/templates/*.conf) +CONFIGURE_FILE(ut-zones-manager/templates/console-dbus.conf.in + ${CMAKE_BINARY_DIR}/ut-zones-manager/templates/console-dbus.conf @ONLY) +FILE(GLOB manager_templates_CONF_GEN ${CMAKE_BINARY_DIR}/ut-zones-manager/templates/*.conf) ## Install ##################################################################### @@ -74,32 +58,30 @@ INSTALL(FILES ${server_manager_CONF} DESTINATION ${VSM_TEST_CONFIG_INSTALL_DIR}/server/ut-server) INSTALL(FILES ${server_manager_CONF_GEN} DESTINATION ${VSM_TEST_CONFIG_INSTALL_DIR}/server/ut-server) -INSTALL(FILES ${server_zone_CONF} - DESTINATION ${VSM_TEST_CONFIG_INSTALL_DIR}/server/ut-server/zones) +INSTALL(FILES ${server_templates_CONF} + DESTINATION ${VSM_TEST_CONFIG_INSTALL_DIR}/server/ut-server/templates) INSTALL(FILES ${manager_manager_CONF} DESTINATION ${VSM_TEST_CONFIG_INSTALL_DIR}/server/ut-zones-manager) INSTALL(FILES ${manager_manager_CONF_GEN} DESTINATION ${VSM_TEST_CONFIG_INSTALL_DIR}/server/ut-zones-manager) -INSTALL(FILES ${manager_zone_CONF} - DESTINATION ${VSM_TEST_CONFIG_INSTALL_DIR}/server/ut-zones-manager/zones) -INSTALL(FILES ${manager_zone_CONF_GEN} - DESTINATION ${VSM_TEST_CONFIG_INSTALL_DIR}/server/ut-zones-manager/zones) -INSTALL(FILES ${manager_zone_TEMPLATE_GEN} +INSTALL(FILES ${manager_templates_CONF} + DESTINATION ${VSM_TEST_CONFIG_INSTALL_DIR}/server/ut-zones-manager/templates) +INSTALL(FILES ${manager_templates_CONF_GEN} DESTINATION ${VSM_TEST_CONFIG_INSTALL_DIR}/server/ut-zones-manager/templates) INSTALL(FILES ${zone_CONF} DESTINATION ${VSM_TEST_CONFIG_INSTALL_DIR}/server/ut-zone) -INSTALL(FILES ${zone_zone_CONF} - DESTINATION ${VSM_TEST_CONFIG_INSTALL_DIR}/server/ut-zone/zones) -INSTALL(FILES ${zone_zone_CONF_GEN} - DESTINATION ${VSM_TEST_CONFIG_INSTALL_DIR}/server/ut-zone/zones) +INSTALL(FILES ${zone_templates_CONF} + DESTINATION ${VSM_TEST_CONFIG_INSTALL_DIR}/server/ut-zone/templates) +INSTALL(FILES ${zone_templates_CONF_GEN} + DESTINATION ${VSM_TEST_CONFIG_INSTALL_DIR}/server/ut-zone/templates) INSTALL(FILES ${zone_provision_CONF} DESTINATION ${VSM_TEST_CONFIG_INSTALL_DIR}/server/ut-zone-provision) -INSTALL(FILES ${admin_zone_CONF} - DESTINATION ${VSM_TEST_CONFIG_INSTALL_DIR}/server/ut-zone-admin/zones) +INSTALL(FILES ${admin_templates_CONF} + DESTINATION ${VSM_TEST_CONFIG_INSTALL_DIR}/server/ut-zone-admin/templates) INSTALL(FILES ${connection_CONF} DESTINATION ${VSM_TEST_CONFIG_INSTALL_DIR}/server/ut-zone-connection) diff --git a/tests/unit_tests/server/configs/ut-server/buggy-daemon.conf.in b/tests/unit_tests/server/configs/ut-server/buggy-daemon.conf.in deleted file mode 100644 index a39bcb4..0000000 --- a/tests/unit_tests/server/configs/ut-server/buggy-daemon.conf.in +++ /dev/null @@ -1,18 +0,0 @@ -{ - "dbPath" : "/tmp/ut-zones/vasum.db", - "zoneConfigs" : ["zones/zone1.conf", "missing/file/path/missing.conf", "zones/zone3.conf"], - "zonesPath" : "/tmp/ut-zones", - "zoneImagePath" : "", - "zoneTemplateDir" : "no_need_for_templates_in_this_test", - "zoneNewConfigPrefix" : "@VSM_TEST_CONFIG_INSTALL_DIR@/server/ut-server/", - "runMountPointPrefix" : "", - "defaultId" : "ut-server-zone1", - "lxcTemplatePrefix" : "@VSM_TEST_LXC_TEMPLATES_INSTALL_DIR@", - "availableVTs" : [], - "inputConfig" : {"enabled" : false, - "device" : "/dev/doesnotexist", - "code" : 139, - "numberOfEvents" : 2, - "timeWindowMs" : 500}, - "proxyCallRules" : [] -} diff --git a/tests/unit_tests/server/configs/ut-server/zones/zone1.conf b/tests/unit_tests/server/configs/ut-server/templates/default.conf similarity index 93% rename from tests/unit_tests/server/configs/ut-server/zones/zone1.conf rename to tests/unit_tests/server/configs/ut-server/templates/default.conf index 432adc6..875cdc4 100644 --- a/tests/unit_tests/server/configs/ut-server/zones/zone1.conf +++ b/tests/unit_tests/server/configs/ut-server/templates/default.conf @@ -1,5 +1,4 @@ { - "name" : "ut-server-zone1", "lxcTemplate" : "minimal.sh", "initWithArgs" : ["/bin/sh", "-c", "trap exit SIGTERM; read"], "ipv4Gateway" : "", diff --git a/tests/unit_tests/server/configs/ut-server/test-daemon.conf.in b/tests/unit_tests/server/configs/ut-server/test-daemon.conf.in index 932ee89..8fb9ee2 100644 --- a/tests/unit_tests/server/configs/ut-server/test-daemon.conf.in +++ b/tests/unit_tests/server/configs/ut-server/test-daemon.conf.in @@ -1,12 +1,11 @@ { "dbPath" : "/tmp/ut-zones/vasum.db", - "zoneConfigs" : ["zones/zone1.conf", "zones/zone2.conf", "zones/zone3.conf"], + "zoneIds" : [], "zonesPath" : "/tmp/ut-zones", "zoneImagePath" : "", - "zoneTemplateDir" : "no_need_for_templates_in_this_test", - "zoneNewConfigPrefix" : "@VSM_TEST_CONFIG_INSTALL_DIR@/server/ut-server/", + "zoneTemplateDir" : "@VSM_TEST_CONFIG_INSTALL_DIR@/server/ut-server/templates/", "runMountPointPrefix" : "", - "defaultId" : "ut-server-zone1", + "defaultId" : "", "lxcTemplatePrefix" : "@VSM_TEST_LXC_TEMPLATES_INSTALL_DIR@", "availableVTs" : [], "inputConfig" : {"enabled" : false, diff --git a/tests/unit_tests/server/configs/ut-server/zones/zone3.conf b/tests/unit_tests/server/configs/ut-server/zones/zone3.conf deleted file mode 100644 index dfc4a04..0000000 --- a/tests/unit_tests/server/configs/ut-server/zones/zone3.conf +++ /dev/null @@ -1,18 +0,0 @@ -{ - "name" : "ut-server-zone3", - "lxcTemplate" : "minimal.sh", - "initWithArgs" : ["/bin/sh", "-c", "trap exit SIGTERM; read"], - "ipv4Gateway" : "", - "ipv4" : "", - "privilege" : 15, - "vt" : -1, - "switchToDefaultAfterTimeout" : true, - "enableDbusIntegration" : false, - "cpuQuotaForeground" : -1, - "cpuQuotaBackground" : 1000, - "runMountPoint" : "", - "provisions" : [], - "permittedToSend" : [], - "permittedToRecv" : [], - "validLinkPrefixes" : [] -} diff --git a/tests/unit_tests/server/configs/ut-zone-admin/zones/buggy.conf b/tests/unit_tests/server/configs/ut-zone-admin/templates/buggy.conf similarity index 92% rename from tests/unit_tests/server/configs/ut-zone-admin/zones/buggy.conf rename to tests/unit_tests/server/configs/ut-zone-admin/templates/buggy.conf index fa7bd6b..07569fe 100644 --- a/tests/unit_tests/server/configs/ut-zone-admin/zones/buggy.conf +++ b/tests/unit_tests/server/configs/ut-zone-admin/templates/buggy.conf @@ -1,5 +1,4 @@ { - "name" : "ut-zone-admin-test", "lxcTemplate" : "minimal.sh", "initWithArgs" : ["/foo"], "ipv4Gateway" : "", diff --git a/tests/unit_tests/server/configs/ut-zone-admin/zones/missing.conf b/tests/unit_tests/server/configs/ut-zone-admin/templates/missing.conf similarity index 92% rename from tests/unit_tests/server/configs/ut-zone-admin/zones/missing.conf rename to tests/unit_tests/server/configs/ut-zone-admin/templates/missing.conf index 5cb9524..e0b5e4a 100644 --- a/tests/unit_tests/server/configs/ut-zone-admin/zones/missing.conf +++ b/tests/unit_tests/server/configs/ut-zone-admin/templates/missing.conf @@ -1,5 +1,4 @@ { - "name" : "ut-zone-admin-test", "lxcTemplate" : "missing.sh", "initWithArgs" : ["/bin/sh", "-c", "trap exit SIGTERM; read"], "ipv4Gateway" : "", diff --git a/tests/unit_tests/server/configs/ut-zone-admin/zones/test-no-shutdown.conf b/tests/unit_tests/server/configs/ut-zone-admin/templates/test-no-shutdown.conf similarity index 92% rename from tests/unit_tests/server/configs/ut-zone-admin/zones/test-no-shutdown.conf rename to tests/unit_tests/server/configs/ut-zone-admin/templates/test-no-shutdown.conf index 7ab5df7..1579851 100644 --- a/tests/unit_tests/server/configs/ut-zone-admin/zones/test-no-shutdown.conf +++ b/tests/unit_tests/server/configs/ut-zone-admin/templates/test-no-shutdown.conf @@ -1,5 +1,4 @@ { - "name" : "ut-zone-admin-test", "lxcTemplate" : "minimal.sh", "initWithArgs" : ["/bin/sh"], "ipv4Gateway" : "", diff --git a/tests/unit_tests/server/configs/ut-server/zones/zone2.conf b/tests/unit_tests/server/configs/ut-zone-admin/templates/test.conf similarity index 93% rename from tests/unit_tests/server/configs/ut-server/zones/zone2.conf rename to tests/unit_tests/server/configs/ut-zone-admin/templates/test.conf index 2126b8f..d74f221 100644 --- a/tests/unit_tests/server/configs/ut-server/zones/zone2.conf +++ b/tests/unit_tests/server/configs/ut-zone-admin/templates/test.conf @@ -1,5 +1,4 @@ { - "name" : "ut-server-zone2", "lxcTemplate" : "minimal.sh", "initWithArgs" : ["/bin/sh", "-c", "trap exit SIGTERM; read"], "ipv4Gateway" : "", diff --git a/tests/unit_tests/server/configs/ut-zone-admin/zones/test.conf b/tests/unit_tests/server/configs/ut-zone-admin/zones/test.conf deleted file mode 100644 index 215fa4f..0000000 --- a/tests/unit_tests/server/configs/ut-zone-admin/zones/test.conf +++ /dev/null @@ -1,18 +0,0 @@ -{ - "name" : "ut-zone-admin-test", - "lxcTemplate" : "minimal.sh", - "initWithArgs" : ["/bin/sh", "-c", "trap exit SIGTERM; read"], - "ipv4Gateway" : "", - "ipv4" : "", - "privilege" : 10, - "vt" : -1, - "switchToDefaultAfterTimeout" : true, - "enableDbusIntegration" : false, - "cpuQuotaForeground" : -1, - "cpuQuotaBackground" : 1000, - "runMountPoint" : "", - "provisions" : [], - "permittedToSend" : [], - "permittedToRecv" : [], - "validLinkPrefixes" : [] -} diff --git a/tests/unit_tests/server/configs/ut-zone/zones/buggy.conf b/tests/unit_tests/server/configs/ut-zone/templates/buggy.conf similarity index 94% rename from tests/unit_tests/server/configs/ut-zone/zones/buggy.conf rename to tests/unit_tests/server/configs/ut-zone/templates/buggy.conf index d29993c..1b449bc 100644 --- a/tests/unit_tests/server/configs/ut-zone/zones/buggy.conf +++ b/tests/unit_tests/server/configs/ut-zone/templates/buggy.conf @@ -1,5 +1,4 @@ { - "name" : "ut-zone-test", "lxcTemplate" : "/buggy/path", "initWithArgs" : ["/bin/sh", "-c", "trap exit SIGTERM; read"], "ipv4Gateway" : "", diff --git a/tests/unit_tests/server/configs/ut-zone/zones/test-dbus.conf.in b/tests/unit_tests/server/configs/ut-zone/templates/test-dbus.conf.in similarity index 85% rename from tests/unit_tests/server/configs/ut-zone/zones/test-dbus.conf.in rename to tests/unit_tests/server/configs/ut-zone/templates/test-dbus.conf.in index 77a4180..9e9a1f8 100644 --- a/tests/unit_tests/server/configs/ut-zone/zones/test-dbus.conf.in +++ b/tests/unit_tests/server/configs/ut-zone/templates/test-dbus.conf.in @@ -1,5 +1,4 @@ { - "name" : "ut-zone-test-dbus", "lxcTemplate" : "minimal-dbus.sh", "initWithArgs" : ["/bin/sh", "-c", "trap exit SIGTERM; /usr/bin/dbus-daemon --config-file=@VSM_TEST_CONFIG_INSTALL_DIR@/server/ut-zone/ut-dbus.conf --fork; read"], "ipv4Gateway" : "", @@ -10,7 +9,7 @@ "enableDbusIntegration" : true, "cpuQuotaForeground" : -1, "cpuQuotaBackground" : 1000, - "runMountPoint" : "/tmp/ut-run/ut-zone-test-dbus", + "runMountPoint" : "/tmp/ut-run/zoneId", "provisions" : [], "permittedToSend" : [], "permittedToRecv" : [], diff --git a/tests/unit_tests/server/configs/ut-zone/zones/test.conf b/tests/unit_tests/server/configs/ut-zone/templates/test.conf similarity index 94% rename from tests/unit_tests/server/configs/ut-zone/zones/test.conf rename to tests/unit_tests/server/configs/ut-zone/templates/test.conf index 9887e1c..3bc3277 100644 --- a/tests/unit_tests/server/configs/ut-zone/zones/test.conf +++ b/tests/unit_tests/server/configs/ut-zone/templates/test.conf @@ -1,5 +1,4 @@ { - "name" : "ut-zone-test", "lxcTemplate" : "minimal.sh", "initWithArgs" : ["/bin/sh", "-c", "trap exit SIGTERM; read"], "ipv4Gateway" : "", diff --git a/tests/unit_tests/server/configs/ut-zones-manager/buggy-daemon.conf.in b/tests/unit_tests/server/configs/ut-zones-manager/buggy-daemon.conf.in deleted file mode 100644 index 50a95b2..0000000 --- a/tests/unit_tests/server/configs/ut-zones-manager/buggy-daemon.conf.in +++ /dev/null @@ -1,18 +0,0 @@ -{ - "dbPath" : "/tmp/ut-zones/vasum.db", - "zoneConfigs" : ["zones/console1.conf", "missing/file/path/missing.conf", "zones/console3.conf"], - "runMountPointPrefix" : "", - "defaultId" : "ut-zones-manager-console1", - "zonesPath" : "/tmp/ut-zones", - "zoneImagePath" : "", - "zoneTemplateDir" : "@VSM_TEST_CONFIG_INSTALL_DIR@/server/ut-zones-manager/templates/", - "zoneNewConfigPrefix" : "@VSM_TEST_CONFIG_INSTALL_DIR@/server/ut-zones-manager/", - "lxcTemplatePrefix" : "@VSM_TEST_LXC_TEMPLATES_INSTALL_DIR@", - "availableVTs" : [], - "inputConfig" : {"enabled" : false, - "device" : "/dev/doesnotexist", - "code" : 139, - "numberOfEvents" : 2, - "timeWindowMs" : 500}, - "proxyCallRules" : [] -} diff --git a/tests/unit_tests/server/configs/ut-zones-manager/zones/console3-dbus.conf.in b/tests/unit_tests/server/configs/ut-zones-manager/templates/console-dbus.conf.in similarity index 83% rename from tests/unit_tests/server/configs/ut-zones-manager/zones/console3-dbus.conf.in rename to tests/unit_tests/server/configs/ut-zones-manager/templates/console-dbus.conf.in index 2f28ee1..0bd0e03 100644 --- a/tests/unit_tests/server/configs/ut-zones-manager/zones/console3-dbus.conf.in +++ b/tests/unit_tests/server/configs/ut-zones-manager/templates/console-dbus.conf.in @@ -1,5 +1,4 @@ { - "name" : "ut-zones-manager-console3-dbus", "lxcTemplate" : "minimal-dbus.sh", "initWithArgs" : ["/bin/sh", "-c", "trap exit SIGTERM; /usr/bin/dbus-daemon --config-file=@VSM_TEST_CONFIG_INSTALL_DIR@/server/ut-zones-manager/ut-dbus.conf --fork; read"], "ipv4Gateway" : "", @@ -10,7 +9,7 @@ "enableDbusIntegration" : true, "cpuQuotaForeground" : -1, "cpuQuotaBackground" : 1000, - "runMountPoint" : "/tmp/ut-run/ut-zones-manager-console3-dbus", + "runMountPoint" : "/tmp/ut-run/~NAME~", "provisions" : [], "permittedToSend" : [ "/tmp/.*" ], "permittedToRecv" : [ "/tmp/.*" ], diff --git a/tests/unit_tests/server/configs/ut-zones-manager/zones/console1.conf b/tests/unit_tests/server/configs/ut-zones-manager/templates/console.conf similarity index 91% rename from tests/unit_tests/server/configs/ut-zones-manager/zones/console1.conf rename to tests/unit_tests/server/configs/ut-zones-manager/templates/console.conf index 1fd4061..9b3013c 100644 --- a/tests/unit_tests/server/configs/ut-zones-manager/zones/console1.conf +++ b/tests/unit_tests/server/configs/ut-zones-manager/templates/console.conf @@ -1,5 +1,4 @@ { - "name" : "ut-zones-manager-console1", "lxcTemplate" : "minimal.sh", "initWithArgs" : ["/bin/sh", "-c", "trap exit SIGTERM; read"], "ipv4Gateway" : "", diff --git a/tests/unit_tests/server/configs/ut-zones-manager/test-daemon.conf.in b/tests/unit_tests/server/configs/ut-zones-manager/test-daemon.conf.in index d8f1ad4..adea9b6 100644 --- a/tests/unit_tests/server/configs/ut-zones-manager/test-daemon.conf.in +++ b/tests/unit_tests/server/configs/ut-zones-manager/test-daemon.conf.in @@ -1,12 +1,11 @@ { "dbPath" : "/tmp/ut-zones/vasum.db", - "zoneConfigs" : ["zones/console1.conf", "zones/console2.conf", "zones/console3.conf"], - "runMountPointPrefix" : "", - "defaultId" : "ut-zones-manager-console1", + "zoneIds" : [], + "defaultId" : "", "zonesPath" : "/tmp/ut-zones", "zoneImagePath" : "", "zoneTemplateDir" : "@VSM_TEST_CONFIG_INSTALL_DIR@/server/ut-zones-manager/templates/", - "zoneNewConfigPrefix" : "@VSM_TEST_CONFIG_INSTALL_DIR@/server/ut-zones-manager/", + "runMountPointPrefix" : "", "lxcTemplatePrefix" : "@VSM_TEST_LXC_TEMPLATES_INSTALL_DIR@", "availableVTs" : [], "inputConfig" : {"enabled" : false, @@ -14,5 +13,10 @@ "code" : 139, "numberOfEvents" : 2, "timeWindowMs" : 500}, - "proxyCallRules" : [] + "proxyCallRules" : [{"caller" : "*", + "target" : "*", + "targetBusName" : "org.tizen.vasum.tests", + "targetObjectPath" : "*", + "targetInterface" : "*", + "targetMethod" : "*"}] } diff --git a/tests/unit_tests/server/configs/ut-zones-manager/test-dbus-daemon.conf.in b/tests/unit_tests/server/configs/ut-zones-manager/test-dbus-daemon.conf.in deleted file mode 100644 index 4f8f6e8..0000000 --- a/tests/unit_tests/server/configs/ut-zones-manager/test-dbus-daemon.conf.in +++ /dev/null @@ -1,25 +0,0 @@ -{ - "dbPath" : "/tmp/ut-zones/vasum.db", - "zoneConfigs" : ["zones/console1-dbus.conf", - "zones/console2-dbus.conf", - "zones/console3-dbus.conf"], - "defaultId" : "ut-zones-manager-console1-dbus", - "zonesPath" : "/tmp/ut-zones", - "zoneImagePath" : "", - "zoneTemplateDir" : "@VSM_TEST_CONFIG_INSTALL_DIR@/server/ut-zones-manager/templates/", - "zoneNewConfigPrefix" : "@VSM_TEST_CONFIG_INSTALL_DIR@/server/ut-zones-manager/", - "runMountPointPrefix" : "", - "lxcTemplatePrefix" : "@VSM_TEST_LXC_TEMPLATES_INSTALL_DIR@", - "availableVTs" : [], - "inputConfig" : {"enabled" : false, - "device" : "/dev/doesnotexist", - "code" : 139, - "numberOfEvents" : 2, - "timeWindowMs" : 500}, - "proxyCallRules" : [{"caller" : "*", - "target" : "*", - "targetBusName" : "org.tizen.vasum.tests", - "targetObjectPath" : "*", - "targetInterface" : "*", - "targetMethod" : "*"}] -} diff --git a/tests/unit_tests/server/configs/ut-zones-manager/zones/console1-dbus.conf.in b/tests/unit_tests/server/configs/ut-zones-manager/zones/console1-dbus.conf.in deleted file mode 100644 index 097480d..0000000 --- a/tests/unit_tests/server/configs/ut-zones-manager/zones/console1-dbus.conf.in +++ /dev/null @@ -1,18 +0,0 @@ -{ - "name" : "ut-zones-manager-console1-dbus", - "lxcTemplate" : "minimal-dbus.sh", - "initWithArgs" : ["/bin/sh", "-c", "trap exit SIGTERM; /usr/bin/dbus-daemon --config-file=@VSM_TEST_CONFIG_INSTALL_DIR@/server/ut-zones-manager/ut-dbus.conf --fork; read"], - "ipv4Gateway" : "", - "ipv4" : "", - "privilege" : 20, - "vt" : -1, - "switchToDefaultAfterTimeout" : true, - "enableDbusIntegration" : true, - "cpuQuotaForeground" : -1, - "cpuQuotaBackground" : 1000, - "runMountPoint" : "/tmp/ut-run/ut-zones-manager-console1-dbus", - "provisions" : [], - "permittedToSend" : [ "/tmp/.*", "/etc/secret2" ], - "permittedToRecv" : [ "/tmp/.*" ], - "validLinkPrefixes" : [] -} diff --git a/tests/unit_tests/server/configs/ut-zones-manager/zones/console2-dbus.conf.in b/tests/unit_tests/server/configs/ut-zones-manager/zones/console2-dbus.conf.in deleted file mode 100644 index 440772b..0000000 --- a/tests/unit_tests/server/configs/ut-zones-manager/zones/console2-dbus.conf.in +++ /dev/null @@ -1,18 +0,0 @@ -{ - "name" : "ut-zones-manager-console2-dbus", - "lxcTemplate" : "minimal-dbus.sh", - "initWithArgs" : ["/bin/sh", "-c", "trap exit SIGTERM; /usr/bin/dbus-daemon --config-file=@VSM_TEST_CONFIG_INSTALL_DIR@/server/ut-zones-manager/ut-dbus.conf --fork; read"], - "ipv4Gateway" : "", - "ipv4" : "", - "privilege" : 20, - "vt" : -1, - "switchToDefaultAfterTimeout" : false, - "enableDbusIntegration" : true, - "cpuQuotaForeground" : -1, - "cpuQuotaBackground" : 1000, - "runMountPoint" : "/tmp/ut-run/ut-zones-manager-console2-dbus", - "provisions" : [], - "permittedToSend" : [ "/tmp/.*" ], - "permittedToRecv" : [ "/tmp/.*", "/etc/secret1" ], - "validLinkPrefixes" : [] -} diff --git a/tests/unit_tests/server/configs/ut-zones-manager/zones/console2.conf b/tests/unit_tests/server/configs/ut-zones-manager/zones/console2.conf deleted file mode 100644 index 3c37313..0000000 --- a/tests/unit_tests/server/configs/ut-zones-manager/zones/console2.conf +++ /dev/null @@ -1,18 +0,0 @@ -{ - "name" : "ut-zones-manager-console2", - "lxcTemplate" : "minimal.sh", - "initWithArgs" : ["/bin/sh", "-c", "trap exit SIGTERM; read"], - "ipv4Gateway" : "", - "ipv4" : "", - "privilege" : 10, - "vt" : -1, - "switchToDefaultAfterTimeout" : true, - "enableDbusIntegration" : false, - "cpuQuotaForeground" : -1, - "cpuQuotaBackground" : 1000, - "runMountPoint" : "", - "provisions" : [], - "permittedToSend" : [ "/tmp/.*" ], - "permittedToRecv" : [ "/tmp/.*" ], - "validLinkPrefixes" : [] -} diff --git a/tests/unit_tests/server/configs/ut-zones-manager/zones/console3.conf b/tests/unit_tests/server/configs/ut-zones-manager/zones/console3.conf deleted file mode 100644 index 8e54fe6..0000000 --- a/tests/unit_tests/server/configs/ut-zones-manager/zones/console3.conf +++ /dev/null @@ -1,18 +0,0 @@ -{ - "name" : "ut-zones-manager-console3", - "lxcTemplate" : "minimal.sh", - "initWithArgs" : ["/bin/sh", "-c", "trap exit SIGTERM; read"], - "ipv4Gateway" : "", - "ipv4" : "", - "privilege" : 15, - "vt" : -1, - "switchToDefaultAfterTimeout" : true, - "enableDbusIntegration" : false, - "cpuQuotaForeground" : -1, - "cpuQuotaBackground" : 1000, - "runMountPoint" : "", - "provisions" : [], - "permittedToSend" : [ "/tmp/.*" ], - "permittedToRecv" : [ "/tmp/.*" ], - "validLinkPrefixes" : [] -} diff --git a/tests/unit_tests/server/ut-server.cpp b/tests/unit_tests/server/ut-server.cpp index 3cd3e51..c65e652 100644 --- a/tests/unit_tests/server/ut-server.cpp +++ b/tests/unit_tests/server/ut-server.cpp @@ -27,9 +27,12 @@ #include "ut.hpp" #include "server.hpp" +#include "zones-manager.hpp" #include "exception.hpp" #include "config/exception.hpp" +#include "utils/glib-loop.hpp" #include "utils/scoped-dir.hpp" +#include "logger/logger.hpp" #include #include @@ -38,8 +41,8 @@ namespace { const std::string CONFIG_DIR = VSM_TEST_CONFIG_INSTALL_DIR "/server/ut-server"; const std::string TEST_CONFIG_PATH = CONFIG_DIR + "/test-daemon.conf"; -const std::string BUGGY_CONFIG_PATH = CONFIG_DIR + "/buggy-daemon.conf"; const std::string MISSING_CONFIG_PATH = CONFIG_DIR + "/missing-daemon.conf"; +const std::string TEMPLATE_NAME = "default"; const std::string ZONES_PATH = "/tmp/ut-zones"; // the same as in daemon.conf const bool AS_ROOT = true; @@ -49,7 +52,19 @@ struct Fixture { Fixture() : mZonesPathGuard(ZONES_PATH) - {} + { + prepare(); + LOGI("------------ setup complete -----------"); + } + + void prepare() + { + vasum::utils::ScopedGlibLoop loop; + vasum::ZonesManager manager(TEST_CONFIG_PATH); + manager.createZone("zone1", TEMPLATE_NAME); + manager.createZone("zone2", TEMPLATE_NAME); + manager.startAll(); + } }; } // namespace @@ -65,14 +80,9 @@ BOOST_AUTO_TEST_CASE(ConstructorDestructorTest) s.reset(); } -BOOST_AUTO_TEST_CASE(BuggyConfigTest) -{ - BOOST_REQUIRE_THROW(Server(BUGGY_CONFIG_PATH).run(AS_ROOT), ConfigException); -} - BOOST_AUTO_TEST_CASE(MissingConfigTest) { - BOOST_REQUIRE_THROW(Server(MISSING_CONFIG_PATH).run(AS_ROOT), ConfigException); + BOOST_REQUIRE_THROW(Server(MISSING_CONFIG_PATH).run(AS_ROOT), ConfigException);//TODO check message } BOOST_AUTO_TEST_CASE(TerminateTest) diff --git a/tests/unit_tests/server/ut-zone-admin.cpp b/tests/unit_tests/server/ut-zone-admin.cpp index ba21ea9..21cc850 100644 --- a/tests/unit_tests/server/ut-zone-admin.cpp +++ b/tests/unit_tests/server/ut-zone-admin.cpp @@ -37,11 +37,11 @@ using namespace vasum; namespace { -const std::string ZONES_CONFIG_DIR = VSM_TEST_CONFIG_INSTALL_DIR "/server/ut-zone-admin/zones"; -const std::string TEST_CONFIG_PATH = ZONES_CONFIG_DIR + "/test.conf"; -const std::string TEST_NO_SHUTDOWN_CONFIG_PATH = ZONES_CONFIG_DIR + "/test-no-shutdown.conf"; -const std::string BUGGY_CONFIG_PATH = ZONES_CONFIG_DIR + "/buggy.conf"; -const std::string MISSING_CONFIG_PATH = ZONES_CONFIG_DIR + "/missing.conf"; +const std::string TEMPLATES_DIR = VSM_TEST_CONFIG_INSTALL_DIR "/server/ut-zone-admin/templates"; +const std::string TEST_CONFIG_PATH = TEMPLATES_DIR + "/test.conf"; +const std::string TEST_NO_SHUTDOWN_CONFIG_PATH = TEMPLATES_DIR + "/test-no-shutdown.conf"; +const std::string BUGGY_CONFIG_PATH = TEMPLATES_DIR + "/buggy.conf"; +const std::string MISSING_CONFIG_PATH = TEMPLATES_DIR + "/missing.conf"; const std::string ZONES_PATH = "/tmp/ut-zones"; const std::string LXC_TEMPLATES_PATH = VSM_TEST_LXC_TEMPLATES_INSTALL_DIR; @@ -50,6 +50,7 @@ struct Fixture { utils::ScopedDir mZonesPathGuard; ZoneConfig mConfig; + ZoneDynamicConfig mDynamicConfig; Fixture() : mZonesPathGuard(ZONES_PATH) @@ -58,9 +59,12 @@ struct Fixture { std::unique_ptr create(const std::string& configPath) { config::loadFromJsonFile(configPath, mConfig); - return std::unique_ptr(new ZoneAdmin(ZONES_PATH, - LXC_TEMPLATES_PATH, - mConfig)); + config::loadFromJsonFile(configPath, mDynamicConfig); + return std::unique_ptr(new ZoneAdmin("zoneId", + ZONES_PATH, + LXC_TEMPLATES_PATH, + mConfig, + mDynamicConfig)); } void ensureStarted() @@ -83,7 +87,7 @@ BOOST_AUTO_TEST_CASE(ConstructorDestructorTest) BOOST_AUTO_TEST_CASE(MissingConfigTest) { - BOOST_REQUIRE_THROW(create(MISSING_CONFIG_PATH), ZoneOperationException); + BOOST_REQUIRE_THROW(create(MISSING_CONFIG_PATH), ZoneOperationException);//TODO check message } BOOST_AUTO_TEST_CASE(StartTest) @@ -99,7 +103,7 @@ BOOST_AUTO_TEST_CASE(StartTest) BOOST_AUTO_TEST_CASE(StartBuggyTest) { auto admin = create(BUGGY_CONFIG_PATH); - BOOST_REQUIRE_THROW(admin->start(), ZoneOperationException); + BOOST_REQUIRE_THROW(admin->start(), ZoneOperationException);//TODO check message } BOOST_AUTO_TEST_CASE(StopShutdownTest) diff --git a/tests/unit_tests/server/ut-zone.cpp b/tests/unit_tests/server/ut-zone.cpp index 646a0a8..dbdf65a 100644 --- a/tests/unit_tests/server/ut-zone.cpp +++ b/tests/unit_tests/server/ut-zone.cpp @@ -45,11 +45,11 @@ using namespace config; namespace { -const std::string ZONES_CONFIG_DIR = VSM_TEST_CONFIG_INSTALL_DIR "/server/ut-zone/zones"; -const std::string TEST_CONFIG_PATH = ZONES_CONFIG_DIR + "/test.conf"; -const std::string TEST_DBUS_CONFIG_PATH = ZONES_CONFIG_DIR + "/test-dbus.conf"; -const std::string BUGGY_CONFIG_PATH = ZONES_CONFIG_DIR + "/buggy.conf"; -const std::string MISSING_CONFIG_PATH = ZONES_CONFIG_DIR + "/missing.conf"; +const std::string TEMPLATES_DIR = VSM_TEST_CONFIG_INSTALL_DIR "/server/ut-zone/templates"; +const std::string TEST_CONFIG_PATH = TEMPLATES_DIR + "/test.conf"; +const std::string TEST_DBUS_CONFIG_PATH = TEMPLATES_DIR + "/test-dbus.conf"; +const std::string BUGGY_CONFIG_PATH = TEMPLATES_DIR + "/buggy.conf"; +const std::string MISSING_CONFIG_PATH = TEMPLATES_DIR + "/missing.conf"; const std::string ZONES_PATH = "/tmp/ut-zones"; const std::string LXC_TEMPLATES_PATH = VSM_TEST_LXC_TEMPLATES_INSTALL_DIR; const std::string DB_PATH = ZONES_PATH + "/vasum.db"; @@ -66,6 +66,7 @@ struct Fixture { std::unique_ptr create(const std::string& configPath) { return std::unique_ptr(new Zone(utils::Worker::create(), + "zoneId", ZONES_PATH, configPath, DB_PATH, @@ -93,12 +94,12 @@ BOOST_AUTO_TEST_CASE(ConstructorDestructorTest) BOOST_AUTO_TEST_CASE(BuggyConfigTest) { - BOOST_REQUIRE_THROW(create(BUGGY_CONFIG_PATH), ZoneOperationException); + BOOST_REQUIRE_THROW(create(BUGGY_CONFIG_PATH), ZoneOperationException);//TODO check message } BOOST_AUTO_TEST_CASE(MissingConfigTest) { - BOOST_REQUIRE_THROW(create(MISSING_CONFIG_PATH), ConfigException); + BOOST_REQUIRE_THROW(create(MISSING_CONFIG_PATH), ConfigException);//TODO check message } BOOST_AUTO_TEST_CASE(StartStopTest) diff --git a/tests/unit_tests/server/ut-zones-manager.cpp b/tests/unit_tests/server/ut-zones-manager.cpp index a32aaa7..58ac060 100644 --- a/tests/unit_tests/server/ut-zones-manager.cpp +++ b/tests/unit_tests/server/ut-zones-manager.cpp @@ -63,14 +63,10 @@ namespace { const std::string CONFIG_DIR = VSM_TEST_CONFIG_INSTALL_DIR "/server/ut-zones-manager"; const std::string TEST_CONFIG_PATH = CONFIG_DIR + "/test-daemon.conf"; -const std::string TEST_DBUS_CONFIG_PATH = CONFIG_DIR + "/test-dbus-daemon.conf"; -const std::string EMPTY_DBUS_CONFIG_PATH = CONFIG_DIR + "/empty-dbus-daemon.conf"; -const std::string BUGGY_CONFIG_PATH = CONFIG_DIR + "/buggy-daemon.conf"; const std::string MISSING_CONFIG_PATH = CONFIG_DIR + "/missing-daemon.conf"; const int EVENT_TIMEOUT = 5000; -const int UNEXPECTED_EVENT_TIMEOUT = EVENT_TIMEOUT / 5; +//const int UNEXPECTED_EVENT_TIMEOUT = EVENT_TIMEOUT / 5; const int TEST_DBUS_CONNECTION_ZONES_COUNT = 3; -const std::string PREFIX_CONSOLE_NAME = "ut-zones-manager-console"; const std::string TEST_APP_NAME = "testapp"; const std::string TEST_MESSAGE = "testmessage"; const std::string FILE_CONTENT = "File content\n" @@ -78,7 +74,8 @@ const std::string FILE_CONTENT = "File content\n" "Line 2\n"; const std::string NON_EXISTANT_ZONE_ID = "NON_EXISTANT_ZONE_ID"; const std::string ZONES_PATH = "/tmp/ut-zones"; // the same as in daemon.conf -const std::string TEMPLATE_NAME = "default"; +const std::string SIMPLE_TEMPLATE = "console"; +const std::string DBUS_TEMPLATE = "console-dbus"; /** * Currently there is no way to propagate an error from async call @@ -449,8 +446,8 @@ private: if (isHost()) { return "unix:path=/var/run/dbus/system_bus_socket"; } - return "unix:path=/tmp/ut-run/ut-zones-manager-console" + std::to_string(mId) + - "-dbus/dbus/system_bus_socket"; + std::string zoneId = "zone" + std::to_string(mId); + return "unix:path=/tmp/ut-run/" + zoneId + "/dbus/system_bus_socket"; } }; @@ -498,59 +495,70 @@ BOOST_AUTO_TEST_CASE(ConstructorDestructorTest) cm.reset(); } -BOOST_AUTO_TEST_CASE(BuggyConfigTest) -{ - BOOST_REQUIRE_THROW(ZonesManager cm(BUGGY_CONFIG_PATH), ConfigException); -} - BOOST_AUTO_TEST_CASE(MissingConfigTest) { BOOST_REQUIRE_THROW(ZonesManager cm(MISSING_CONFIG_PATH), ConfigException); } -BOOST_AUTO_TEST_CASE(StartAllTest) +BOOST_AUTO_TEST_CASE(CreateTest) { ZonesManager cm(TEST_CONFIG_PATH); - cm.startAll(); - BOOST_CHECK(cm.getRunningForegroundZoneId() == "ut-zones-manager-console1"); + cm.createZone("zone1", SIMPLE_TEMPLATE); + cm.createZone("zone2", SIMPLE_TEMPLATE); } -BOOST_AUTO_TEST_CASE(StopAllTest) +BOOST_AUTO_TEST_CASE(StartStopTest) { ZonesManager cm(TEST_CONFIG_PATH); + cm.createZone("zone1", SIMPLE_TEMPLATE); + cm.createZone("zone2", SIMPLE_TEMPLATE); + cm.startAll(); + BOOST_CHECK_EQUAL(cm.getRunningForegroundZoneId(), "zone1"); cm.stopAll(); - BOOST_CHECK(cm.getRunningForegroundZoneId().empty()); + BOOST_CHECK_EQUAL(cm.getRunningForegroundZoneId(), ""); } BOOST_AUTO_TEST_CASE(DetachOnExitTest) { { ZonesManager cm(TEST_CONFIG_PATH); + cm.createZone("zone1", SIMPLE_TEMPLATE); + cm.createZone("zone2", SIMPLE_TEMPLATE); cm.startAll(); + BOOST_CHECK_EQUAL(cm.getRunningForegroundZoneId(), "zone1"); cm.setZonesDetachOnExit(); } { ZonesManager cm(TEST_CONFIG_PATH); cm.startAll(); + BOOST_CHECK_EQUAL(cm.getRunningForegroundZoneId(), "zone1"); } } BOOST_AUTO_TEST_CASE(FocusTest) { ZonesManager cm(TEST_CONFIG_PATH); + cm.createZone("zone1", SIMPLE_TEMPLATE); + cm.createZone("zone2", SIMPLE_TEMPLATE); + cm.createZone("zone3", SIMPLE_TEMPLATE); cm.startAll(); - cm.focus("ut-zones-manager-console2"); - BOOST_CHECK(cm.getRunningForegroundZoneId() == "ut-zones-manager-console2"); - cm.focus("ut-zones-manager-console1"); - BOOST_CHECK(cm.getRunningForegroundZoneId() == "ut-zones-manager-console1"); - cm.focus("ut-zones-manager-console3"); - BOOST_CHECK(cm.getRunningForegroundZoneId() == "ut-zones-manager-console3"); + + BOOST_CHECK(cm.getRunningForegroundZoneId() == "zone1"); + cm.focus("zone2"); + BOOST_CHECK(cm.getRunningForegroundZoneId() == "zone2"); + cm.focus("zone1"); + BOOST_CHECK(cm.getRunningForegroundZoneId() == "zone1"); + cm.focus("zone3"); + BOOST_CHECK(cm.getRunningForegroundZoneId() == "zone3"); } BOOST_AUTO_TEST_CASE(NotifyActiveZoneTest) { - ZonesManager cm(TEST_DBUS_CONFIG_PATH); + ZonesManager cm(TEST_CONFIG_PATH); + cm.createZone("zone1", DBUS_TEMPLATE); + cm.createZone("zone2", DBUS_TEMPLATE); + cm.createZone("zone3", DBUS_TEMPLATE); cm.startAll(); Latch signalReceivedLatch; @@ -617,7 +625,10 @@ BOOST_AUTO_TEST_CASE(NotifyActiveZoneTest) BOOST_AUTO_TEST_CASE(DisplayOffTest) { - ZonesManager cm(TEST_DBUS_CONFIG_PATH); + ZonesManager cm(TEST_CONFIG_PATH); + cm.createZone("zone1", DBUS_TEMPLATE); + cm.createZone("zone2", DBUS_TEMPLATE); + cm.createZone("zone3", DBUS_TEMPLATE); cm.startAll(); std::vector> clients; @@ -629,14 +640,14 @@ BOOST_AUTO_TEST_CASE(DisplayOffTest) client->setName(fake_power_manager_api::BUS_NAME); } - auto cond = [&cm]() -> bool { - return cm.getRunningForegroundZoneId() == "ut-zones-manager-console1-dbus"; + auto isDefaultFocused = [&cm]() -> bool { + return cm.getRunningForegroundZoneId() == "zone1"; }; for (auto& client : clients) { // TEST SWITCHING TO DEFAULT ZONE // focus non-default zone - cm.focus("ut-zones-manager-console3-dbus"); + cm.focus("zone3"); // emit signal from dbus connection client->emitSignal(fake_power_manager_api::OBJECT_PATH, @@ -645,13 +656,16 @@ BOOST_AUTO_TEST_CASE(DisplayOffTest) nullptr); // check if default zone has focus - BOOST_CHECK(spinWaitFor(EVENT_TIMEOUT, cond)); + BOOST_CHECK(spinWaitFor(EVENT_TIMEOUT, isDefaultFocused)); } } BOOST_AUTO_TEST_CASE(MoveFileTest) { - ZonesManager cm(TEST_DBUS_CONFIG_PATH); + ZonesManager cm(TEST_CONFIG_PATH); + cm.createZone("zone1", DBUS_TEMPLATE); + cm.createZone("zone2", DBUS_TEMPLATE); + cm.createZone("zone3", DBUS_TEMPLATE); cm.startAll(); Latch notificationLatch; @@ -694,8 +708,8 @@ BOOST_AUTO_TEST_CASE(MoveFileTest) const std::string NO_PATH = "path_doesnt_matter_here"; const std::string BUGGY_PATH = TMP + "/this_file_does_not_exist"; const std::string BUGGY_ZONE = "this-zone-does-not-exist"; - const std::string ZONE1 = "ut-zones-manager-console1-dbus"; - const std::string ZONE2 = "ut-zones-manager-console2-dbus"; + const std::string ZONE1 = "zone1"; + const std::string ZONE2 = "zone2"; const std::string ZONE1PATH = TMP + "/" + ZONE1 + TMP; const std::string ZONE2PATH = TMP + "/" + ZONE2 + TMP; @@ -715,9 +729,10 @@ BOOST_AUTO_TEST_CASE(MoveFileTest) BOOST_CHECK(notificationLatch.empty()); // no permission to receive - BOOST_CHECK_EQUAL(dbuses.at(1)->callMethodMove(ZONE2, "/etc/secret2"), - api::zone::FILE_MOVE_NO_PERMISSIONS_RECEIVE); - BOOST_CHECK(notificationLatch.empty()); + // TODO uncomment this after adding an api to change 'permittedTo*' config + //BOOST_CHECK_EQUAL(dbuses.at(1)->callMethodMove(ZONE2, "/etc/secret2"), + // api::zone::FILE_MOVE_NO_PERMISSIONS_RECEIVE); + //BOOST_CHECK(notificationLatch.empty()); // non existing file BOOST_CHECK_EQUAL(dbuses.at(1)->callMethodMove(ZONE2, BUGGY_PATH), @@ -749,7 +764,10 @@ BOOST_AUTO_TEST_CASE(MoveFileTest) BOOST_AUTO_TEST_CASE(AllowSwitchToDefaultTest) { - ZonesManager cm(TEST_DBUS_CONFIG_PATH); + ZonesManager cm(TEST_CONFIG_PATH); + cm.createZone("zone1", DBUS_TEMPLATE); + cm.createZone("zone2", DBUS_TEMPLATE); + cm.createZone("zone3", DBUS_TEMPLATE); cm.startAll(); std::vector> clients; @@ -761,13 +779,13 @@ BOOST_AUTO_TEST_CASE(AllowSwitchToDefaultTest) client->setName(fake_power_manager_api::BUS_NAME); } - auto cond = [&cm]() -> bool { - return cm.getRunningForegroundZoneId() == "ut-zones-manager-console1-dbus"; + auto isDefaultFocused = [&cm]() -> bool { + return cm.getRunningForegroundZoneId() == "zone1"; }; for (auto& client : clients) { // focus non-default zone with allowed switching - cm.focus("ut-zones-manager-console3-dbus"); + cm.focus("zone3"); // emit signal from dbus connection client->emitSignal(fake_power_manager_api::OBJECT_PATH, @@ -776,10 +794,10 @@ BOOST_AUTO_TEST_CASE(AllowSwitchToDefaultTest) nullptr); // check if default zone has focus - BOOST_CHECK(spinWaitFor(EVENT_TIMEOUT, cond)); + BOOST_CHECK(spinWaitFor(EVENT_TIMEOUT, isDefaultFocused)); // focus non-default zone with disabled switching - cm.focus("ut-zones-manager-console2-dbus"); + cm.focus("zone2"); // emit signal from dbus connection client->emitSignal(fake_power_manager_api::OBJECT_PATH, @@ -788,13 +806,17 @@ BOOST_AUTO_TEST_CASE(AllowSwitchToDefaultTest) nullptr); // now default zone should not be focused - BOOST_CHECK(!spinWaitFor(UNEXPECTED_EVENT_TIMEOUT, cond)); + // TODO uncomment this after adding an api to change 'switchToDefaultAfterTimeout' + //BOOST_CHECK(!spinWaitFor(UNEXPECTED_EVENT_TIMEOUT, isDefaultFocused)); } } BOOST_AUTO_TEST_CASE(ProxyCallTest) { - ZonesManager cm(TEST_DBUS_CONFIG_PATH); + ZonesManager cm(TEST_CONFIG_PATH); + cm.createZone("zone1", DBUS_TEMPLATE); + cm.createZone("zone2", DBUS_TEMPLATE); + cm.createZone("zone3", DBUS_TEMPLATE); cm.startAll(); std::map> dbuses; @@ -819,7 +841,7 @@ BOOST_AUTO_TEST_CASE(ProxyCallTest) // host -> zone2 BOOST_CHECK_EQUAL("reply from 2: param1", - dbuses.at(0)->testApiProxyCall("ut-zones-manager-console2-dbus", + dbuses.at(0)->testApiProxyCall("zone2", "param1")); // host -> host @@ -834,12 +856,12 @@ BOOST_AUTO_TEST_CASE(ProxyCallTest) // zone1 -> zone2 BOOST_CHECK_EQUAL("reply from 2: param4", - dbuses.at(1)->testApiProxyCall("ut-zones-manager-console2-dbus", + dbuses.at(1)->testApiProxyCall("zone2", "param4")); // zone2 -> zone2 BOOST_CHECK_EQUAL("reply from 2: param5", - dbuses.at(2)->testApiProxyCall("ut-zones-manager-console2-dbus", + dbuses.at(2)->testApiProxyCall("zone2", "param5")); // host -> unknown @@ -864,46 +886,48 @@ BOOST_AUTO_TEST_CASE(ProxyCallTest) } namespace { - const DbusAccessory::Dbuses EXPECTED_DBUSES_NO_DBUS = { - {"ut-zones-manager-console1", ""}, - {"ut-zones-manager-console2", ""}, - {"ut-zones-manager-console3", ""}}; - - const DbusAccessory::Dbuses EXPECTED_DBUSES_STOPPED = { - {"ut-zones-manager-console1-dbus", ""}, - {"ut-zones-manager-console2-dbus", ""}, - {"ut-zones-manager-console3-dbus", ""}}; - - const DbusAccessory::Dbuses EXPECTED_DBUSES_STARTED = { - {"ut-zones-manager-console1-dbus", - "unix:path=/tmp/ut-run/ut-zones-manager-console1-dbus/dbus/system_bus_socket"}, - {"ut-zones-manager-console2-dbus", - "unix:path=/tmp/ut-run/ut-zones-manager-console2-dbus/dbus/system_bus_socket"}, - {"ut-zones-manager-console3-dbus", - "unix:path=/tmp/ut-run/ut-zones-manager-console3-dbus/dbus/system_bus_socket"}}; + const DbusAccessory::Dbuses EXPECTED_DBUSES_NONE = { + {"zone1", ""}, + {"zone2", ""}, + {"zone3", ""}}; + + const DbusAccessory::Dbuses EXPECTED_DBUSES_ALL = { + {"zone1", + "unix:path=/tmp/ut-run/zone1/dbus/system_bus_socket"}, + {"zone2", + "unix:path=/tmp/ut-run/zone2/dbus/system_bus_socket"}, + {"zone3", + "unix:path=/tmp/ut-run/zone3/dbus/system_bus_socket"}}; } // namespace BOOST_AUTO_TEST_CASE(GetZoneDbusesTest) { DbusAccessory host(DbusAccessory::HOST_ID); - ZonesManager cm(TEST_DBUS_CONFIG_PATH); + ZonesManager cm(TEST_CONFIG_PATH); + cm.createZone("zone1", DBUS_TEMPLATE); + cm.createZone("zone2", DBUS_TEMPLATE); + cm.createZone("zone3", DBUS_TEMPLATE); - BOOST_CHECK(EXPECTED_DBUSES_STOPPED == host.callMethodGetZoneDbuses()); + BOOST_CHECK(EXPECTED_DBUSES_NONE == host.callMethodGetZoneDbuses()); cm.startAll(); - BOOST_CHECK(EXPECTED_DBUSES_STARTED == host.callMethodGetZoneDbuses()); + BOOST_CHECK(EXPECTED_DBUSES_ALL == host.callMethodGetZoneDbuses()); cm.stopAll(); - BOOST_CHECK(EXPECTED_DBUSES_STOPPED == host.callMethodGetZoneDbuses()); + BOOST_CHECK(EXPECTED_DBUSES_NONE == host.callMethodGetZoneDbuses()); } BOOST_AUTO_TEST_CASE(GetZoneDbusesNoDbusTest) { DbusAccessory host(DbusAccessory::HOST_ID); ZonesManager cm(TEST_CONFIG_PATH); - BOOST_CHECK(EXPECTED_DBUSES_NO_DBUS == host.callMethodGetZoneDbuses()); + cm.createZone("zone1", SIMPLE_TEMPLATE); + cm.createZone("zone2", SIMPLE_TEMPLATE); + cm.createZone("zone3", SIMPLE_TEMPLATE); + + BOOST_CHECK(EXPECTED_DBUSES_NONE == host.callMethodGetZoneDbuses()); cm.startAll(); - BOOST_CHECK(EXPECTED_DBUSES_NO_DBUS == host.callMethodGetZoneDbuses()); + BOOST_CHECK(EXPECTED_DBUSES_NONE == host.callMethodGetZoneDbuses()); cm.stopAll(); - BOOST_CHECK(EXPECTED_DBUSES_NO_DBUS == host.callMethodGetZoneDbuses()); + BOOST_CHECK(EXPECTED_DBUSES_NONE == host.callMethodGetZoneDbuses()); } BOOST_AUTO_TEST_CASE(ZoneDbusesSignalsTest) @@ -934,7 +958,10 @@ BOOST_AUTO_TEST_CASE(ZoneDbusesSignalsTest) host.signalSubscribe(onSignal); { - ZonesManager cm(TEST_DBUS_CONFIG_PATH); + ZonesManager cm(TEST_CONFIG_PATH); + cm.createZone("zone1", DBUS_TEMPLATE); + cm.createZone("zone2", DBUS_TEMPLATE); + cm.createZone("zone3", DBUS_TEMPLATE); BOOST_CHECK(signalLatch.empty()); BOOST_CHECK(collectedDbuses.empty()); @@ -943,25 +970,28 @@ BOOST_AUTO_TEST_CASE(ZoneDbusesSignalsTest) BOOST_REQUIRE(signalLatch.waitForN(TEST_DBUS_CONNECTION_ZONES_COUNT, EVENT_TIMEOUT)); BOOST_CHECK(signalLatch.empty()); - BOOST_CHECK(EXPECTED_DBUSES_STARTED == collectedDbuses); + BOOST_CHECK(EXPECTED_DBUSES_ALL == collectedDbuses); collectedDbuses.clear(); } BOOST_CHECK(signalLatch.waitForN(TEST_DBUS_CONNECTION_ZONES_COUNT, EVENT_TIMEOUT)); BOOST_CHECK(signalLatch.empty()); - BOOST_CHECK(EXPECTED_DBUSES_STOPPED == collectedDbuses); + BOOST_CHECK(EXPECTED_DBUSES_NONE == collectedDbuses); } BOOST_AUTO_TEST_CASE(GetZoneIdsTest) { - ZonesManager cm(TEST_DBUS_CONFIG_PATH); + ZonesManager cm(TEST_CONFIG_PATH); + cm.createZone("zone1", SIMPLE_TEMPLATE); + cm.createZone("zone2", SIMPLE_TEMPLATE); + cm.createZone("zone3", SIMPLE_TEMPLATE); DbusAccessory dbus(DbusAccessory::HOST_ID); - std::vector zoneIds = {"ut-zones-manager-console1-dbus", - "ut-zones-manager-console2-dbus", - "ut-zones-manager-console3-dbus"}; + std::vector zoneIds = {"zone1", + "zone2", + "zone3"}; std::vector returnedIds = dbus.callMethodGetZoneIds(); BOOST_CHECK(returnedIds == zoneIds);// order should be preserved @@ -969,16 +999,19 @@ BOOST_AUTO_TEST_CASE(GetZoneIdsTest) BOOST_AUTO_TEST_CASE(GetActiveZoneIdTest) { - ZonesManager cm(TEST_DBUS_CONFIG_PATH); + ZonesManager cm(TEST_CONFIG_PATH); + cm.createZone("zone1", SIMPLE_TEMPLATE); + cm.createZone("zone2", SIMPLE_TEMPLATE); + cm.createZone("zone3", SIMPLE_TEMPLATE); cm.startAll(); DbusAccessory dbus(DbusAccessory::HOST_ID); - std::vector zoneIds = {"ut-zones-manager-console1-dbus", - "ut-zones-manager-console2-dbus", - "ut-zones-manager-console3-dbus"}; + std::vector zoneIds = {"zone1", + "zone2", + "zone3"}; - for (std::string& zoneId: zoneIds){ + for (const std::string& zoneId: zoneIds){ cm.focus(zoneId); BOOST_CHECK(dbus.callMethodGetActiveZoneId() == zoneId); } @@ -989,16 +1022,19 @@ BOOST_AUTO_TEST_CASE(GetActiveZoneIdTest) BOOST_AUTO_TEST_CASE(SetActiveZoneTest) { - ZonesManager cm(TEST_DBUS_CONFIG_PATH); + ZonesManager cm(TEST_CONFIG_PATH); + cm.createZone("zone1", SIMPLE_TEMPLATE); + cm.createZone("zone2", SIMPLE_TEMPLATE); + cm.createZone("zone3", SIMPLE_TEMPLATE); cm.startAll(); DbusAccessory dbus(DbusAccessory::HOST_ID); - std::vector zoneIds = {"ut-zones-manager-console1-dbus", - "ut-zones-manager-console2-dbus", - "ut-zones-manager-console3-dbus"}; + std::vector zoneIds = {"zone1", + "zone2", + "zone3"}; - for (std::string& zoneId: zoneIds){ + for (const std::string& zoneId: zoneIds){ dbus.callMethodSetActiveZone(zoneId); BOOST_CHECK(dbus.callMethodGetActiveZoneId() == zoneId); } @@ -1007,7 +1043,7 @@ BOOST_AUTO_TEST_CASE(SetActiveZoneTest) DbusException); cm.stopAll(); - BOOST_REQUIRE_THROW(dbus.callMethodSetActiveZone("ut-zones-manager-console1-dbus"), + BOOST_REQUIRE_THROW(dbus.callMethodSetActiveZone("zone1"), DbusException); } @@ -1017,7 +1053,7 @@ BOOST_AUTO_TEST_CASE(CreateDestroyZoneTest) const std::string zone2 = "test2"; const std::string zone3 = "test3"; - ZonesManager cm(EMPTY_DBUS_CONFIG_PATH); + ZonesManager cm(TEST_CONFIG_PATH); cm.startAll(); BOOST_CHECK_EQUAL(cm.getRunningForegroundZoneId(), ""); @@ -1030,15 +1066,15 @@ BOOST_AUTO_TEST_CASE(CreateDestroyZoneTest) DbusAccessory dbus(DbusAccessory::HOST_ID); // create zone1 - dbus.callAsyncMethodCreateZone(zone1, TEMPLATE_NAME, resultCallback); + dbus.callAsyncMethodCreateZone(zone1, SIMPLE_TEMPLATE, resultCallback); BOOST_REQUIRE(callDone.wait(EVENT_TIMEOUT)); // create zone2 - dbus.callAsyncMethodCreateZone(zone2, TEMPLATE_NAME, resultCallback); + dbus.callAsyncMethodCreateZone(zone2, SIMPLE_TEMPLATE, resultCallback); BOOST_REQUIRE(callDone.wait(EVENT_TIMEOUT)); // create zone3 - dbus.callAsyncMethodCreateZone(zone3, TEMPLATE_NAME, resultCallback); + dbus.callAsyncMethodCreateZone(zone3, SIMPLE_TEMPLATE, resultCallback); BOOST_REQUIRE(callDone.wait(EVENT_TIMEOUT)); cm.startAll(); @@ -1073,7 +1109,7 @@ BOOST_AUTO_TEST_CASE(CreateDestroyZonePersistenceTest) }; auto getZoneIds = []() -> std::vector { - ZonesManager cm(EMPTY_DBUS_CONFIG_PATH); + ZonesManager cm(TEST_CONFIG_PATH); cm.startAll(); DbusAccessory dbus(DbusAccessory::HOST_ID); @@ -1084,9 +1120,9 @@ BOOST_AUTO_TEST_CASE(CreateDestroyZonePersistenceTest) // create zone { - ZonesManager cm(EMPTY_DBUS_CONFIG_PATH); + ZonesManager cm(TEST_CONFIG_PATH); DbusAccessory dbus(DbusAccessory::HOST_ID); - dbus.callAsyncMethodCreateZone(zone, TEMPLATE_NAME, resultCallback); + dbus.callAsyncMethodCreateZone(zone, SIMPLE_TEMPLATE, resultCallback); BOOST_REQUIRE(callDone.wait(EVENT_TIMEOUT)); } @@ -1098,7 +1134,7 @@ BOOST_AUTO_TEST_CASE(CreateDestroyZonePersistenceTest) // destroy zone { - ZonesManager cm(EMPTY_DBUS_CONFIG_PATH); + ZonesManager cm(TEST_CONFIG_PATH); DbusAccessory dbus(DbusAccessory::HOST_ID); dbus.callAsyncMethodDestroyZone(zone, resultCallback); BOOST_REQUIRE(callDone.wait(EVENT_TIMEOUT)); @@ -1109,10 +1145,12 @@ BOOST_AUTO_TEST_CASE(CreateDestroyZonePersistenceTest) BOOST_AUTO_TEST_CASE(StartShutdownZoneTest) { - const std::string zone1 = "ut-zones-manager-console1-dbus"; - const std::string zone2 = "ut-zones-manager-console2-dbus"; + const std::string zone1 = "zone1"; + const std::string zone2 = "zone2"; - ZonesManager cm(TEST_DBUS_CONFIG_PATH); + ZonesManager cm(TEST_CONFIG_PATH); + cm.createZone(zone1, DBUS_TEMPLATE); + cm.createZone(zone2, DBUS_TEMPLATE); Latch callDone; auto resultCallback = [&]() { @@ -1147,14 +1185,17 @@ BOOST_AUTO_TEST_CASE(StartShutdownZoneTest) BOOST_AUTO_TEST_CASE(LockUnlockZoneTest) { - ZonesManager cm(TEST_DBUS_CONFIG_PATH); + ZonesManager cm(TEST_CONFIG_PATH); + cm.createZone("zone1", DBUS_TEMPLATE); + cm.createZone("zone2", DBUS_TEMPLATE); + cm.createZone("zone3", DBUS_TEMPLATE); cm.startAll(); DbusAccessory dbus(DbusAccessory::HOST_ID); - std::vector zoneIds = {"ut-zones-manager-console1-dbus", - "ut-zones-manager-console2-dbus", - "ut-zones-manager-console3-dbus"}; + std::vector zoneIds = {"zone1", + "zone2", + "zone3"}; for (const std::string& zoneId: zoneIds){ dbus.callMethodLockZone(zoneId); @@ -1169,9 +1210,9 @@ BOOST_AUTO_TEST_CASE(LockUnlockZoneTest) DbusException); cm.stopAll(); - BOOST_REQUIRE_THROW(dbus.callMethodLockZone("ut-zones-manager-console1-dbus"), + BOOST_REQUIRE_THROW(dbus.callMethodLockZone("zone1"), DbusException); - BOOST_REQUIRE_THROW(dbus.callMethodUnlockZone("ut-zones-manager-console1-dbus"), + BOOST_REQUIRE_THROW(dbus.callMethodUnlockZone("zone1"), DbusException); } -- 2.7.4 From 0e5b6d8ee9b7cd3acf56b232f54254d5c46e0c3d Mon Sep 17 00:00:00 2001 From: Mateusz Malicki Date: Tue, 17 Feb 2015 15:49:35 +0100 Subject: [PATCH 08/16] GVariant visitor test [Bug/Feature] GVariant visitor test [Cause] N/A [Solution] Test convert to and from GVariant [Verification] Build, run tests: vasum-server-unit-tests -t ConfigurationSuite Change-Id: I8e7573bc3d44724b17560bfaa9a040922530ff40 --- tests/unit_tests/config/ut-configuration.cpp | 51 ++++++++++++++++++++++++++-- 1 file changed, 48 insertions(+), 3 deletions(-) diff --git a/tests/unit_tests/config/ut-configuration.cpp b/tests/unit_tests/config/ut-configuration.cpp index 2e3b487..8049975 100644 --- a/tests/unit_tests/config/ut-configuration.cpp +++ b/tests/unit_tests/config/ut-configuration.cpp @@ -52,7 +52,7 @@ struct Fixture { BOOST_FIXTURE_TEST_SUITE(ConfigurationSuite, Fixture) -BOOST_AUTO_TEST_CASE(FromStringTest) +BOOST_AUTO_TEST_CASE(FromJsonStringTest) { TestConfig testConfig; @@ -96,10 +96,28 @@ BOOST_AUTO_TEST_CASE(FromStringTest) BOOST_CHECK_EQUAL(4, testConfig.subVector[0].intVector[1]); BOOST_CHECK_EQUAL(6, testConfig.subVector[1].intVector[1]); + BOOST_CHECK(testConfig.union1.is()); + BOOST_CHECK_EQUAL(2, testConfig.union1.as()); + + BOOST_CHECK(testConfig.union2.is()); + BOOST_CHECK_EQUAL(54321, testConfig.union2.as().intVal); + BOOST_REQUIRE_EQUAL(1, testConfig.union2.as().intVector.size()); + BOOST_CHECK_EQUAL(1, testConfig.union2.as().intVector[0]); + BOOST_CHECK_EQUAL(234, testConfig.union2.as().subSubObj.intVal); + + BOOST_REQUIRE_EQUAL(2, testConfig.unions.size()); + BOOST_CHECK(testConfig.unions[0].is()); + BOOST_CHECK_EQUAL(2, testConfig.unions[0].as()); + + BOOST_CHECK(testConfig.unions[1].is()); + BOOST_CHECK_EQUAL(54321, testConfig.unions[1].as().intVal); + BOOST_REQUIRE_EQUAL(1, testConfig.unions[1].as().intVector.size()); + BOOST_CHECK_EQUAL(1, testConfig.unions[1].as().intVector[0]); + BOOST_CHECK_EQUAL(234, testConfig.unions[1].as().subSubObj.intVal); } -BOOST_AUTO_TEST_CASE(ToStringTest) +BOOST_AUTO_TEST_CASE(ToJsonStringTest) { TestConfig testConfig; BOOST_REQUIRE_NO_THROW(loadFromJsonString(jsonTestString, testConfig)); @@ -135,7 +153,7 @@ struct UnionConfig { } // namespace loadErrorsTest -BOOST_AUTO_TEST_CASE(LoadErrorsTest) +BOOST_AUTO_TEST_CASE(JsonLoadErrorsTest) { using namespace loadErrorsTest; @@ -351,6 +369,14 @@ BOOST_AUTO_TEST_CASE(PartialConfigTest) partialConfig.intVector = {7}; config::saveToKVStore(DB_PATH, partialConfig, DB_PREFIX); } + + // from gvariant (partial is not supported!) + { + PartialTestConfig partialConfig; + std::unique_ptr v(saveToGVariant(config), + g_variant_unref); + BOOST_CHECK_THROW(loadFromGVariant(v.get(), partialConfig), ConfigException); + } } BOOST_AUTO_TEST_CASE(ConfigUnionTest) @@ -399,4 +425,23 @@ BOOST_AUTO_TEST_CASE(ConfigUnionTest) BOOST_CHECK_EQUAL(out, jsonTestString); } + +BOOST_AUTO_TEST_CASE(GVariantVisitorTest) +{ + TestConfig testConfig; + BOOST_REQUIRE_NO_THROW(loadFromJsonString(jsonTestString, testConfig)); + std::unique_ptr v(saveToGVariant(testConfig), + g_variant_unref); + TestConfig testConfig2; + loadFromGVariant(v.get(), testConfig2); + std::string out = saveToJsonString(testConfig2); + BOOST_CHECK_EQUAL(out, jsonTestString); + + PartialTestConfig partialConfig; + partialConfig.stringVal = testConfig.stringVal; + partialConfig.intVector = testConfig.intVector; + v.reset(saveToGVariant(partialConfig)); + BOOST_CHECK_THROW(loadFromGVariant(v.get(), testConfig), ConfigException); +} + BOOST_AUTO_TEST_SUITE_END() -- 2.7.4 From b094b5574e100d45577a7271f827f057a947c81e Mon Sep 17 00:00:00 2001 From: Mateusz Malicki Date: Thu, 12 Feb 2015 11:43:56 +0100 Subject: [PATCH 09/16] Stubs for creating netdev [Feature] Stubs (cli, client, server) for creating netdev [Cause] N/A [Solution] N/A [Verification] Build, run cli commnads Change-Id: Ibf2631d0f6e42823793d3f5bd971586348811891 --- cli/command-line-interface.cpp | 59 ++++++++++++++++++++++++++++++++++ cli/command-line-interface.hpp | 20 ++++++++++++ cli/main.cpp | 30 +++++++++++++++++ client/vasum-client-impl.cpp | 55 +++++++++++++++++++++----------- client/vasum-client-impl.hpp | 27 ++++++++++++---- client/vasum-client.cpp | 29 ++++++++++++----- client/vasum-client.h | 48 ++++++++++++++++++++-------- common/base-exception.cpp | 7 +++- common/base-exception.hpp | 1 + server/host-connection.cpp | 46 +++++++++++++++++++++++++++ server/host-connection.hpp | 33 +++++++++++++++++++ server/host-dbus-definitions.hpp | 64 +++++++++++++++++++++++-------------- server/zone-admin.cpp | 17 ++++++++++ server/zone-admin.hpp | 18 +++++++++++ server/zone.cpp | 21 ++++++++++++ server/zone.hpp | 18 +++++++++++ server/zones-manager.cpp | 69 ++++++++++++++++++++++++++++++++++++++++ server/zones-manager.hpp | 12 +++++++ 18 files changed, 503 insertions(+), 71 deletions(-) diff --git a/cli/command-line-interface.cpp b/cli/command-line-interface.cpp index 06be364..a189a92 100644 --- a/cli/command-line-interface.cpp +++ b/cli/command-line-interface.cpp @@ -37,6 +37,7 @@ #include #include #include +#include using namespace std; @@ -150,6 +151,22 @@ ostream& operator<<(ostream& out, const Table& table) return out; } +enum macvlan_mode macvlanFromString(const std::string& mode) { + if (mode == "private") { + return MACVLAN_MODE_PRIVATE; + } + if (mode == "vepa") { + return MACVLAN_MODE_VEPA; + } + if (mode == "bridge") { + return MACVLAN_MODE_BRIDGE; + } + if (mode == "passthru") { + return MACVLAN_MODE_PASSTHRU; + } + throw runtime_error("Unsupported macvlan mode"); +} + } // namespace void CommandLineInterface::printUsage(std::ostream& out) const @@ -335,5 +352,47 @@ void revoke_device(int pos, int argc, const char** argv) one_shot(bind(vsm_revoke_device, _1, argv[pos + 1], argv[pos + 2])); } +void create_netdev_veth(int pos, int argc, const char** argv) +{ + using namespace std::placeholders; + + if (argc <= pos + 3) { + throw runtime_error("Not enough parameters"); + } + one_shot(bind(vsm_create_netdev_veth, + _1, + argv[pos + 1], + argv[pos + 2], + argv[pos + 3])); +} + +void create_netdev_macvlan(int pos, int argc, const char** argv) +{ + using namespace std::placeholders; + + if (argc <= pos + 4) { + throw runtime_error("Not enough parameters"); + } + one_shot(bind(vsm_create_netdev_macvlan, + _1, + argv[pos + 1], + argv[pos + 2], + argv[pos + 3], + macvlanFromString(argv[pos + 4]))); +} + +void create_netdev_phys(int pos, int argc, const char** argv) +{ + using namespace std::placeholders; + + if (argc <= pos + 2) { + throw runtime_error("Not enough parameters"); + } + one_shot(bind(vsm_create_netdev_phys, + _1, + argv[pos + 1], + argv[pos + 2])); +} + } // namespace cli } // namespace vasum diff --git a/cli/command-line-interface.hpp b/cli/command-line-interface.hpp index 055bb1e..34ac013 100644 --- a/cli/command-line-interface.hpp +++ b/cli/command-line-interface.hpp @@ -187,6 +187,26 @@ void grant_device(int pos, int argc, const char** argv); */ void revoke_device(int pos, int argc, const char** argv); +/** + * Parses command line arguments and call vsm_create_netdev_veth + * + * @see vsm_create_netdev_veth + */ +void create_netdev_veth(int pos, int argc, const char** argv); + +/** + * Parses command line arguments and call vsm_create_netdev_macvlan + * + * @see vsm_create_netdev_macvlan + */ +void create_netdev_macvlan(int pos, int argc, const char** argv); + +/** + * Parses command line arguments and call vsm_create_netdev_phys + * + * @see vsm_create_netdev_phys + */ +void create_netdev_phys(int pos, int argc, const char** argv); } // namespace cli } // namespace vasum diff --git a/cli/main.cpp b/cli/main.cpp index d003d10..38a8ae5 100644 --- a/cli/main.cpp +++ b/cli/main.cpp @@ -140,6 +140,36 @@ std::map commands = { {{"zone_id", "id zone name"}, {"device_name", " device name"}} } + }, + { + "create_netdev_veth", { + create_netdev_veth, + "create_netdev_veth zone_id zoneDev hostDev", + "Create netdev in zone", + {{"zone_id", "id zone name"}, + {"zoneDev", "network device id"}, + {"hostDev", "host bridge id"}} + } + }, + { + "create_netdev_macvlan", { + create_netdev_macvlan, + "create_netdev_macvlan zone_id zoneDev hostDev mode", + "Create netdev in zone", + {{"zone_id", "id zone name"}, + {"zoneDev", "network device id"}, + {"hostDev", "host bridge id"}, + {"mode", "macvlan mode (private, vepa, bridge, passthru)"}} + } + }, + { + "create_netdev_phys", { + create_netdev_phys, + "create_netdev_phys zone_id devId", + "Create/move netdev to zone", + {{"zone_id", "id zone name"}, + {"devId", "network device id"}} + } } }; diff --git a/client/vasum-client-impl.cpp b/client/vasum-client-impl.cpp index d27fad3..d6f4217 100644 --- a/client/vasum-client-impl.cpp +++ b/client/vasum-client-impl.cpp @@ -152,7 +152,7 @@ void toArray(GVariant* in, T** scArray) *scArray = ids; } -VsmStatus toStatus(const std::exception& ex) +VsmStatus toStatus(const exception& ex) { if (typeid(DbusCustomException) == typeid(ex)) { return VSMCLIENT_CUSTOM_ERROR; @@ -168,14 +168,14 @@ VsmStatus toStatus(const std::exception& ex) return VSMCLIENT_OTHER_ERROR; } -bool readFirstLineOfFile(const std::string& path, std::string& ret) +bool readFirstLineOfFile(const string& path, string& ret) { - std::ifstream file(path); + ifstream file(path); if (!file) { return false; } - std::getline(file, ret); + getline(file, ret); return true; } @@ -209,7 +209,7 @@ Client::Status::Status() { } -Client::Status::Status(VsmStatus status, const std::string& msg) +Client::Status::Status(VsmStatus status, const string& msg) : mVsmStatus(status), mMsg(msg) { } @@ -272,10 +272,10 @@ VsmStatus Client::signalSubscribe(const DbusInterfaceInfo& info, SignalCallback signalCallback, VsmSubscriptionId* subscriptionId) { - auto onSignal = [=](const std::string& /*senderBusName*/, - const std::string & objectPath, - const std::string & interface, - const std::string & signalName, + auto onSignal = [=](const string& /*senderBusName*/, + const string & objectPath, + const string & interface, + const string & signalName, GVariant * parameters) { if (objectPath == info.objectPath && interface == info.interface && @@ -290,7 +290,7 @@ VsmStatus Client::signalSubscribe(const DbusInterfaceInfo& info, *subscriptionId = id; } mStatus = Status(); - } catch (const std::exception& ex) { + } catch (const exception& ex) { mStatus = Status(toStatus(ex), ex.what()); } return vsm_get_status(); @@ -301,7 +301,7 @@ VsmStatus Client::signalUnsubscribe(VsmSubscriptionId id) try { mConnection->signalUnsubscribe(id); mStatus = Status(); - } catch (const std::exception& ex) { + } catch (const exception& ex) { mStatus = Status(toStatus(ex), ex.what()); } return vsm_get_status(); @@ -385,15 +385,15 @@ VsmStatus Client::vsm_lookup_zone_by_pid(int pid, VsmString* id) noexcept { assert(id); - const std::string path = "/proc/" + std::to_string(pid) + "/cpuset"; + const string path = "/proc/" + to_string(pid) + "/cpuset"; - std::string cpuset; + string cpuset; if (!readFirstLineOfFile(path, cpuset)) { mStatus = Status(VSMCLIENT_INVALID_ARGUMENT, "Process not found"); return vsm_get_status(); } - std::string zoneId; + string zoneId; if (!parseZoneIdFromCpuSet(cpuset, zoneId)) { mStatus = Status(VSMCLIENT_OTHER_ERROR, "unknown format of cpuset"); return vsm_get_status(); @@ -560,19 +560,36 @@ VsmStatus Client::vsm_netdev_set_ipv6_addr(const char*, const char*, struct in6_ return vsm_get_status(); } -VsmStatus Client::vsm_create_netdev(const char*, VsmNetdevType, const char*, const char*) noexcept +VsmStatus Client::vsm_create_netdev_veth(const char* zone, + const char* zoneDev, + const char* hostDev) noexcept { - mStatus = Status(VSMCLIENT_OTHER_ERROR, "Not implemented"); - return vsm_get_status(); + GVariant* args_in = g_variant_new("(sss)", zone, zoneDev, hostDev); + return callMethod(HOST_INTERFACE, api::host::METHOD_CREATE_NETDEV_VETH, args_in); } -VsmStatus Client::vsm_destroy_netdev(const char*, const char*) noexcept +VsmStatus Client::vsm_create_netdev_macvlan(const char* zone, + const char* zoneDev, + const char* hostDev, + enum macvlan_mode mode) noexcept +{ + GVariant* args_in = g_variant_new("(sssu)", zone, zoneDev, hostDev, mode); + return callMethod(HOST_INTERFACE, api::host::METHOD_CREATE_NETDEV_MACVLAN, args_in); +} + +VsmStatus Client::vsm_create_netdev_phys(const char* zone, const char* devId) noexcept +{ + GVariant* args_in = g_variant_new("(ss)", zone, devId); + return callMethod(HOST_INTERFACE, api::host::METHOD_CREATE_NETDEV_PHYS, args_in); +} + +VsmStatus Client::vsm_lookup_netdev_by_name(const char*, const char*, VsmNetdev*) noexcept { mStatus = Status(VSMCLIENT_OTHER_ERROR, "Not implemented"); return vsm_get_status(); } -VsmStatus Client::vsm_lookup_netdev_by_name(const char*, const char*, VsmNetdev*) noexcept +VsmStatus Client::vsm_destroy_netdev(const char*, const char*) noexcept { mStatus = Status(VSMCLIENT_OTHER_ERROR, "Not implemented"); return vsm_get_status(); diff --git a/client/vasum-client-impl.hpp b/client/vasum-client-impl.hpp index b5acee7..193f140 100644 --- a/client/vasum-client-impl.hpp +++ b/client/vasum-client-impl.hpp @@ -29,6 +29,7 @@ #include "vasum-client.h" #include #include +#include /** * Structure which defines the dbus interface. @@ -228,17 +229,24 @@ public: int prefix) noexcept; /** - * @see ::vsm_create_netdev + * @see ::vsm_create_netdev_veth */ - VsmStatus vsm_create_netdev(const char* zone, - VsmNetdevType netdevType, - const char* target, - const char* netdevId) noexcept; + VsmStatus vsm_create_netdev_veth(const char* zone, + const char* zoneDev, + const char* hostDev) noexcept; /** - * @see ::vsm_destroy_netdev + * @see ::vsm_create_netdev_macvlan + */ + VsmStatus vsm_create_netdev_macvlan(const char* zone, + const char* zoneDev, + const char* hostDev, + enum macvlan_mode mode) noexcept; + + /** + * @see ::vsm_create_netdev_phys */ - VsmStatus vsm_destroy_netdev(const char* zone, const char* netdevId) noexcept; + VsmStatus vsm_create_netdev_phys(const char* zone, const char* devId) noexcept; /** * @see ::vsm_lookup_netdev_by_name @@ -248,6 +256,11 @@ public: VsmNetdev* netdev) noexcept; /** + * @see ::vsm_destroy_netdev + */ + VsmStatus vsm_destroy_netdev(const char* zone, const char* devId) noexcept; + + /** * @see ::vsm_declare_file */ VsmStatus vsm_declare_file(const char* zone, diff --git a/client/vasum-client.cpp b/client/vasum-client.cpp index 5310b42..1f011c1 100644 --- a/client/vasum-client.cpp +++ b/client/vasum-client.cpp @@ -250,18 +250,26 @@ API VsmStatus vsm_netdev_set_ipv6_addr(VsmClient client, return getClient(client).vsm_netdev_set_ipv6_addr(zone, netdevId, addr, prefix); } -API VsmStatus vsm_create_netdev(VsmClient client, - const char* zone, - VsmNetdevType netdevType, - const char* target, - const char* netdevId) +API VsmStatus vsm_create_netdev_veth(VsmClient client, + const char* zone, + const char* zoneDev, + const char* hostDev) +{ + return getClient(client).vsm_create_netdev_veth(zone, zoneDev, hostDev); +} + +API VsmStatus vsm_create_netdev_macvlan(VsmClient client, + const char* zone, + const char* zoneDev, + const char* hostDev, + enum macvlan_mode mode) { - return getClient(client).vsm_create_netdev(zone, netdevType, target, netdevId); + return getClient(client).vsm_create_netdev_macvlan(zone, zoneDev, hostDev, mode); } -API VsmStatus vsm_destroy_netdev(VsmClient client, const char* zone, const char* netdevId) +API VsmStatus vsm_create_netdev_phys(VsmClient client, const char* zone, const char* devId) { - return getClient(client).vsm_destroy_netdev(zone, netdevId); + return getClient(client).vsm_create_netdev_phys(zone, devId); } API VsmStatus vsm_lookup_netdev_by_name(VsmClient client, @@ -272,6 +280,11 @@ API VsmStatus vsm_lookup_netdev_by_name(VsmClient client, return getClient(client).vsm_lookup_netdev_by_name(zone, netdevId, netdev); } +API VsmStatus vsm_destroy_netdev(VsmClient client, const char* zone, const char* devId) +{ + return getClient(client).vsm_destroy_netdev(zone, devId); +} + API VsmStatus vsm_declare_file(VsmClient client, const char* zone, VsmFileType type, diff --git a/client/vasum-client.h b/client/vasum-client.h index ba21449..1fb48b1 100644 --- a/client/vasum-client.h +++ b/client/vasum-client.h @@ -81,6 +81,7 @@ finish: #include #include #include +#include #ifdef __cplusplus extern "C" @@ -551,30 +552,41 @@ VsmStatus vsm_netdev_set_ipv6_addr(VsmClient client, int prefix); /** - * Create netdev in zone + * Create veth netdev in zone * * @param[in] client vasum-server's client * @param[in] zone zone name - * @param[in] netdevType netdev type - * @param[in] target TODO: this is taken form zone-control - * @param[in] netdevId network device id + * @param[in] zoneDev in host network device id + * @param[in] hostDev in zone network device id * @return status of this function call */ -VsmStatus vsm_create_netdev(VsmClient client, - const char* zone, - VsmNetdevType netdevType, - const char* target, - const char* netdevId); - +VsmStatus vsm_create_netdev_veth(VsmClient client, + const char* zone, + const char* zoneDev, + const char* hostDev); /** - * Remove netdev from zone + * Create macvlab in zone * * @param[in] client vasum-server's client * @param[in] zone zone name - * @param[in] netdevId network device id + * @param[in] zoneDev in host network device id + * @param[in] hostDev in zone network device id + * @return status of this function call + */ +VsmStatus vsm_create_netdev_macvlan(VsmClient client, + const char* zone, + const char* zoneDev, + const char* hostDev, + enum macvlan_mode mode); +/** + * Create/move phys netdev in/to zone + * + * @param[in] client vasum-server's client + * @param[in] zone zone name + * @param[in] devId network device id * @return status of this function call */ -VsmStatus vsm_destroy_netdev(VsmClient client, const char* zone, const char* netdevId); +VsmStatus vsm_create_netdev_phys(VsmClient client, const char* zone, const char* devId); /** * Get netdev informations @@ -592,6 +604,16 @@ VsmStatus vsm_lookup_netdev_by_name(VsmClient client, VsmNetdev* netdev); /** + * Remove netdev from zone + * + * @param[in] client vasum-server's client + * @param[in] zone zone name + * @param[in] devId network device id + * @return status of this function call + */ +VsmStatus vsm_destroy_netdev(VsmClient client, const char* zone, const char* devId); + +/** * Create file, directory or pipe in zone * * Declare file, directory or pipe that will be created while zone startup diff --git a/common/base-exception.cpp b/common/base-exception.cpp index bcfe600..628296d 100644 --- a/common/base-exception.cpp +++ b/common/base-exception.cpp @@ -34,8 +34,13 @@ const int ERROR_MESSAGE_BUFFER_CAPACITY = 256; std::string getSystemErrorMessage() { + return getSystemErrorMessage(errno); +} + +std::string getSystemErrorMessage(int err) +{ char buf[ERROR_MESSAGE_BUFFER_CAPACITY]; - return strerror_r(errno, buf, sizeof(buf)); + return strerror_r(err, buf, sizeof(buf)); } } // namespace vasum diff --git a/common/base-exception.hpp b/common/base-exception.hpp index 3969404..5637e76 100644 --- a/common/base-exception.hpp +++ b/common/base-exception.hpp @@ -46,6 +46,7 @@ struct VasumException: public std::runtime_error { * it is wrapper for strerror_r */ std::string getSystemErrorMessage(); +std::string getSystemErrorMessage(int err); } // namespace vasum diff --git a/server/host-connection.cpp b/server/host-connection.cpp index 4a8a2ac..75c4433 100644 --- a/server/host-connection.cpp +++ b/server/host-connection.cpp @@ -130,6 +130,21 @@ void HostConnection::setGetZoneInfoCallback(const GetZoneInfoCallback& callback) mGetZoneInfoCallback = callback; } +void HostConnection::setCreateNetdevVethCallback(const CreateNetdevVethCallback& callback) +{ + mCreateNetdevVethCallback = callback; +} + +void HostConnection::setCreateNetdevMacvlanCallback(const CreateNetdevMacvlanCallback& callback) +{ + mCreateNetdevMacvlanCallback = callback; +} + +void HostConnection::setCreateNetdevPhysCallback(const CreateNetdevPhysCallback& callback) +{ + mCreateNetdevPhysCallback = callback; +} + void HostConnection::setDeclareFileCallback(const DeclareFileCallback& callback) { mDeclareFileCallback = callback; @@ -281,6 +296,37 @@ void HostConnection::onMessageCall(const std::string& objectPath, return; } + if (methodName == api::host::METHOD_CREATE_NETDEV_VETH) { + const gchar* id = NULL; + const gchar* zoneDev = NULL; + const gchar* hostDev = NULL; + g_variant_get(parameters, "(&s&s&s)", &id, &zoneDev, &hostDev); + if (mCreateNetdevVethCallback) { + mCreateNetdevVethCallback(id, zoneDev, hostDev, result); + } + return; + } + + if (methodName == api::host::METHOD_CREATE_NETDEV_MACVLAN) { + const gchar* id = NULL; + const gchar* zoneDev = NULL; + const gchar* hostDev = NULL; + guint32 mode; + g_variant_get(parameters, "(&s&s&su)", &id, &zoneDev, &hostDev, &mode); + if (mCreateNetdevMacvlanCallback) { + mCreateNetdevMacvlanCallback(id, zoneDev, hostDev, mode, result); + } + } + + if (methodName == api::host::METHOD_CREATE_NETDEV_PHYS) { + const gchar* id = NULL; + const gchar* devId = NULL; + g_variant_get(parameters, "(&s&s)", &id, &devId); + if (mCreateNetdevPhysCallback) { + mCreateNetdevPhysCallback(id, devId, result); + } + } + if (methodName == api::host::METHOD_DECLARE_FILE) { const gchar* zone; int32_t type; diff --git a/server/host-connection.hpp b/server/host-connection.hpp index 2d029c1..649ed15 100644 --- a/server/host-connection.hpp +++ b/server/host-connection.hpp @@ -60,6 +60,21 @@ public: typedef std::function GetZoneInfoCallback; + typedef std::function CreateNetdevVethCallback; + typedef std::function CreateNetdevMacvlanCallback; + typedef std::function CreateNetdevPhysCallback; typedef std::function" " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " " " " " " " diff --git a/server/zone-admin.cpp b/server/zone-admin.cpp index 32a18d2..fa465bc 100644 --- a/server/zone-admin.cpp +++ b/server/zone-admin.cpp @@ -297,5 +297,22 @@ std::int64_t ZoneAdmin::getSchedulerQuota() return 0; } +void ZoneAdmin::createNetdevVeth(const std::string& /* zoneDev */, + const std::string& /* hostDev */) +{ + throw ZoneOperationException("Not implemented"); +} + +void ZoneAdmin::createNetdevMacvlan(const std::string& /* zoneDev */, + const std::string& /* hostDev */, + const uint32_t& /* mode */) +{ + throw ZoneOperationException("Not implemented"); +} + +void ZoneAdmin::moveNetdev(const std::string& /* devId */) +{ + throw ZoneOperationException("Not implemented"); +} } // namespace vasum diff --git a/server/zone-admin.hpp b/server/zone-admin.hpp index 10b7f02..9125a6d 100644 --- a/server/zone-admin.hpp +++ b/server/zone-admin.hpp @@ -130,6 +130,24 @@ public: */ std::int64_t getSchedulerQuota(); + /** + * Create veth network device + */ + void createNetdevVeth(const std::string& zoneDev, + const std::string& hostDev); + + /** + * Create macvlan network device + */ + void createNetdevMacvlan(const std::string& zoneDev, + const std::string& hostDev, + const uint32_t& mode); + + /** + * Move network device to zone + */ + void moveNetdev(const std::string& devId); + private: const ZoneConfig& mConfig; lxc::LxcZone mZone; diff --git a/server/zone.cpp b/server/zone.cpp index e8580e1..5c15f21 100644 --- a/server/zone.cpp +++ b/server/zone.cpp @@ -207,6 +207,27 @@ bool Zone::activateVT() return true; } +void Zone::createNetdevVeth(const std::string& zoneDev, + const std::string& hostDev) +{ + Lock lock(mReconnectMutex); + mAdmin->createNetdevVeth(zoneDev, hostDev); +} + +void Zone::createNetdevMacvlan(const std::string& zoneDev, + const std::string& hostDev, + const uint32_t& mode) +{ + Lock lock(mReconnectMutex); + mAdmin->createNetdevMacvlan(zoneDev, hostDev, mode); +} + +void Zone::moveNetdev(const std::string& devId) +{ + Lock lock(mReconnectMutex); + mAdmin->moveNetdev(devId); +} + void Zone::goForeground() { Lock lock(mReconnectMutex); diff --git a/server/zone.hpp b/server/zone.hpp index b708811..759faa3 100644 --- a/server/zone.hpp +++ b/server/zone.hpp @@ -267,6 +267,24 @@ public: */ std::string getRootPath() const; + /** + * Create veth network device + */ + void createNetdevVeth(const std::string& zoneDev, + const std::string& hostDev); + + /** + * Create macvlan network device + */ + void createNetdevMacvlan(const std::string& zoneDev, + const std::string& hostDev, + const uint32_t& mode); + + /** + * Move network device to zone + */ + void moveNetdev(const std::string& devId); + private: utils::Worker::Pointer mWorker; ZoneConfig mConfig; diff --git a/server/zones-manager.cpp b/server/zones-manager.cpp index bccfd21..fd8501f 100644 --- a/server/zones-manager.cpp +++ b/server/zones-manager.cpp @@ -141,6 +141,15 @@ ZonesManager::ZonesManager(const std::string& configPath) mHostConnection.setGetZoneInfoCallback(bind(&ZonesManager::handleGetZoneInfoCall, this, _1, _2)); + mHostConnection.setCreateNetdevVethCallback(bind(&ZonesManager::handleCreateNetdevVethCall, + this, _1, _2, _3, _4)); + + mHostConnection.setCreateNetdevMacvlanCallback(bind(&ZonesManager::handleCreateNetdevMacvlanCall, + this, _1, _2, _3, _4, _5)); + + mHostConnection.setCreateNetdevPhysCallback(bind(&ZonesManager::handleCreateNetdevPhysCall, + this, _1, _2, _3)); + mHostConnection.setDeclareFileCallback(bind(&ZonesManager::handleDeclareFileCall, this, _1, _2, _3, _4, _5, _6)); @@ -792,6 +801,66 @@ void ZonesManager::handleGetZoneInfoCall(const std::string& id, zone.getRootPath().c_str())); } +void ZonesManager::handleCreateNetdevVethCall(const std::string& zone, + const std::string& zoneDev, + const std::string& hostDev, + dbus::MethodResultBuilder::Pointer result) +{ + LOGI("CreateNetdevVeth call"); + try { + Lock lock(mMutex); + + getZone(zone).createNetdevVeth(zoneDev, hostDev); + result->setVoid(); + } catch (const std::out_of_range&) { + LOGE("No zone with id=" << zone); + result->setError(api::ERROR_INVALID_ID, "No such zone id"); + } catch (const VasumException& ex) { + LOGE("Can't create veth: " << ex.what()); + result->setError(api::ERROR_INTERNAL, ex.what()); + } +} + +void ZonesManager::handleCreateNetdevMacvlanCall(const std::string& zone, + const std::string& zoneDev, + const std::string& hostDev, + const uint32_t& mode, + dbus::MethodResultBuilder::Pointer result) +{ + LOGI("CreateNetdevMacvlan call"); + try { + Lock lock(mMutex); + + getZone(zone).createNetdevMacvlan(zoneDev, hostDev, mode); + result->setVoid(); + } catch (const std::out_of_range&) { + LOGE("No zone with id=" << zone); + result->setError(api::ERROR_INVALID_ID, "No such zone id"); + } catch (const VasumException& ex) { + LOGE("Can't create macvlan: " << ex.what()); + result->setError(api::ERROR_INTERNAL, ex.what()); + } +} + +void ZonesManager::handleCreateNetdevPhysCall(const std::string& zone, + const std::string& devId, + dbus::MethodResultBuilder::Pointer result) +{ + LOGI("CreateNetdevPhys call"); + try { + Lock lock(mMutex); + + getZone(zone).moveNetdev(devId); + result->setVoid(); + } catch (const std::out_of_range&) { + LOGE("No zone with id=" << zone); + result->setError(api::ERROR_INVALID_ID, "No such zone id"); + } catch (const VasumException& ex) { + LOGE("Can't create netdev: " << ex.what()); + result->setError(api::ERROR_INTERNAL, ex.what()); + } +} + void ZonesManager::handleDeclareFileCall(const std::string& zone, const int32_t& type, const std::string& path, diff --git a/server/zones-manager.hpp b/server/zones-manager.hpp index 6453278..df5e12b 100644 --- a/server/zones-manager.hpp +++ b/server/zones-manager.hpp @@ -161,6 +161,18 @@ private: void handleGetZoneIdsCall(dbus::MethodResultBuilder::Pointer result); void handleGetActiveZoneIdCall(dbus::MethodResultBuilder::Pointer result); void handleGetZoneInfoCall(const std::string& id, dbus::MethodResultBuilder::Pointer result); + void handleCreateNetdevVethCall(const std::string& zone, + const std::string& zoneDev, + const std::string& hostDev, + dbus::MethodResultBuilder::Pointer result); + void handleCreateNetdevMacvlanCall(const std::string& zone, + const std::string& zoneDev, + const std::string& hostDev, + const uint32_t& mode, + dbus::MethodResultBuilder::Pointer result); + void handleCreateNetdevPhysCall(const std::string& zone, + const std::string& devId, + dbus::MethodResultBuilder::Pointer result); void handleDeclareFileCall(const std::string& zone, const int32_t& type, const std::string& path, -- 2.7.4 From 3099bfee950f1f9d83e9262326031295fbc70692 Mon Sep 17 00:00:00 2001 From: Piotr Bartosiewicz Date: Wed, 18 Feb 2015 16:16:43 +0100 Subject: [PATCH 10/16] Better exception testing [Bug/Feature] N/A [Cause] N/A [Solution] N/A [Verification] Run tests Change-Id: I814deebc0f8e4fdecd5760eb2b1dce1fe6e7df15 --- common/base-exception.hpp | 2 +- common/utils/exception.hpp | 2 +- common/utils/fs.cpp | 2 +- common/utils/value-latch.hpp | 6 ++-- server/exception.hpp | 12 +++---- server/input-monitor.cpp | 12 +++---- tests/unit_tests/dbus/ut-connection.cpp | 7 ++-- tests/unit_tests/log/ut-logger.cpp | 6 ++-- tests/unit_tests/lxc/ut-zone.cpp | 2 +- tests/unit_tests/server/ut-input-monitor.cpp | 18 +++++----- tests/unit_tests/server/ut-server.cpp | 4 ++- tests/unit_tests/server/ut-zone-admin.cpp | 12 ++++--- tests/unit_tests/server/ut-zone-connection.cpp | 21 ++++-------- tests/unit_tests/server/ut-zone-provision.cpp | 10 ++---- tests/unit_tests/server/ut-zone.cpp | 8 +++-- tests/unit_tests/server/ut-zones-manager.cpp | 47 +++++++++++++------------- tests/unit_tests/ut.hpp | 23 +++++++++++++ tests/unit_tests/utils/ut-fs.cpp | 7 ++-- tests/unit_tests/utils/ut-value-latch.cpp | 12 +++++-- zone-daemon/exception.hpp | 2 +- 20 files changed, 122 insertions(+), 93 deletions(-) diff --git a/common/base-exception.hpp b/common/base-exception.hpp index 5637e76..89b79bc 100644 --- a/common/base-exception.hpp +++ b/common/base-exception.hpp @@ -38,7 +38,7 @@ namespace vasum { */ struct VasumException: public std::runtime_error { - VasumException(const std::string& error = "") : std::runtime_error(error) {} + VasumException(const std::string& error) : std::runtime_error(error) {} }; /** diff --git a/common/utils/exception.hpp b/common/utils/exception.hpp index 56fd0bd..32f416c 100644 --- a/common/utils/exception.hpp +++ b/common/utils/exception.hpp @@ -37,7 +37,7 @@ namespace vasum { */ struct UtilsException: public VasumException { - UtilsException(const std::string& error = "") : VasumException(error) {} + UtilsException(const std::string& error) : VasumException(error) {} }; diff --git a/common/utils/fs.cpp b/common/utils/fs.cpp index b2260cc..d7ae2dd 100644 --- a/common/utils/fs.cpp +++ b/common/utils/fs.cpp @@ -53,7 +53,7 @@ std::string readFileContent(const std::string& path) { std::string result; if (!readFileContent(path, result)) { - throw UtilsException(); + throw UtilsException("Read failed"); } return result; } diff --git a/common/utils/value-latch.hpp b/common/utils/value-latch.hpp index 72c7873..0e06f6f 100644 --- a/common/utils/value-latch.hpp +++ b/common/utils/value-latch.hpp @@ -78,7 +78,7 @@ void ValueLatch::set(const T& value) { std::unique_lock lock(mMutex); if (mValue) { - throw UtilsException("Cannot set ValueLatch multiple times!"); + throw UtilsException("Cannot set value multiple times"); } mValue.reset(new T(value)); mCondition.notify_one(); @@ -89,7 +89,7 @@ void ValueLatch::set(T&& value) { std::unique_lock lock(mMutex); if (mValue) { - throw UtilsException("Cannot set ValueLatch multiple times!"); + throw UtilsException("Cannot set value multiple times"); } mValue.reset(new T(std::move(value))); mCondition.notify_one(); @@ -116,7 +116,7 @@ T ValueLatch::get(const unsigned int timeoutMs) std::unique_ptr retValue(std::move(mValue)); return T(std::move(*retValue)); } else { - throw UtilsException("Timeout occured."); + throw UtilsException("Timeout occured"); } } diff --git a/server/exception.hpp b/server/exception.hpp index cb358b1..bf5a106 100644 --- a/server/exception.hpp +++ b/server/exception.hpp @@ -37,7 +37,7 @@ namespace vasum { */ struct ServerException: public VasumException { - ServerException(const std::string& error = "") : VasumException(error) {} + ServerException(const std::string& error) : VasumException(error) {} }; /** @@ -46,7 +46,7 @@ struct ServerException: public VasumException { */ struct ZoneOperationException: public ServerException { - ZoneOperationException(const std::string& error = "") : ServerException(error) {} + ZoneOperationException(const std::string& error) : ServerException(error) {} }; /** @@ -54,7 +54,7 @@ struct ZoneOperationException: public ServerException { */ struct InvalidZoneIdException : public ServerException { - InvalidZoneIdException(const std::string& error = "") : ServerException(error) {} + InvalidZoneIdException(const std::string& error) : ServerException(error) {} }; /** @@ -62,7 +62,7 @@ struct InvalidZoneIdException : public ServerException { */ struct ZoneConnectionException: public ServerException { - ZoneConnectionException(const std::string& error = "") : ServerException(error) {} + ZoneConnectionException(const std::string& error) : ServerException(error) {} }; /** @@ -70,7 +70,7 @@ struct ZoneConnectionException: public ServerException { */ struct HostConnectionException: public ServerException { - HostConnectionException(const std::string& error = "") : ServerException(error) {} + HostConnectionException(const std::string& error) : ServerException(error) {} }; /** @@ -79,7 +79,7 @@ struct HostConnectionException: public ServerException { */ struct InputMonitorException: public ServerException { - InputMonitorException(const std::string& error = "") : ServerException(error) {} + InputMonitorException(const std::string& error) : ServerException(error) {} }; diff --git a/server/input-monitor.cpp b/server/input-monitor.cpp index 7937840..68e63c0 100644 --- a/server/input-monitor.cpp +++ b/server/input-monitor.cpp @@ -71,12 +71,12 @@ InputMonitor::InputMonitor(const InputConfig& inputConfig, { if (mConfig.timeWindowMs > MAX_TIME_WINDOW_SEC * 1000L) { LOGE("Time window exceeds maximum: " << MAX_TIME_WINDOW_SEC); - throw InputMonitorException(); + throw InputMonitorException("Time window exceeds maximum"); } if (mConfig.numberOfEvents > MAX_NUMBER_OF_EVENTS) { LOGE("Number of events exceeds maximum: " << MAX_NUMBER_OF_EVENTS); - throw InputMonitorException(); + throw InputMonitorException("Number of events exceeds maximum"); } std::string devicePath = getDevicePath(); @@ -168,7 +168,7 @@ std::string InputMonitor::getDevicePath() const if (it == end) { LOGE("None of the files under '" << DEVICE_DIR << "' represents device named: " << device); - throw InputMonitorException(); + throw InputMonitorException("Cannot find a device"); } return it->path().string(); @@ -183,7 +183,7 @@ void InputMonitor::createGIOChannel(const std::string& devicePath) if (fd < 0) { LOGE("Cannot create input monitor channel. Device file: " << devicePath << " doesn't exist"); - throw InputMonitorException(); + throw InputMonitorException("Device does not exist"); } mChannelPtr = g_io_channel_unix_new(fd); @@ -193,7 +193,7 @@ void InputMonitor::createGIOChannel(const std::string& devicePath) NULL, NULL) != G_IO_STATUS_NORMAL) { LOGE("Cannot set encoding for input monitor channel "); - throw InputMonitorException(); + throw InputMonitorException("Cannot set encoding"); } using namespace std::placeholders; @@ -207,7 +207,7 @@ void InputMonitor::createGIOChannel(const std::string& devicePath) &utils::deleteCallbackWrapper); if (!mSourceId) { LOGE("Cannot add watch on device input file"); - throw InputMonitorException(); + throw InputMonitorException("Cannot add watch"); } } diff --git a/tests/unit_tests/dbus/ut-connection.cpp b/tests/unit_tests/dbus/ut-connection.cpp index 94b02b7..5182225 100644 --- a/tests/unit_tests/dbus/ut-connection.cpp +++ b/tests/unit_tests/dbus/ut-connection.cpp @@ -574,10 +574,9 @@ BOOST_AUTO_TEST_CASE(DbusApiTest) BOOST_CHECK_EQUAL("Processed: arg", client.process("arg")); BOOST_CHECK_NO_THROW(client.throwException(0)); - auto checkException = [](const DbusCustomException& e) { - return e.what() == std::string("Argument: 666"); - }; - BOOST_CHECK_EXCEPTION(client.throwException(666), DbusCustomException, checkException); + BOOST_CHECK_EXCEPTION(client.throwException(666), + DbusCustomException, + WhatEquals("Argument: 666")); } BOOST_AUTO_TEST_CASE(DbusApiNotifyTest) diff --git a/tests/unit_tests/log/ut-logger.cpp b/tests/unit_tests/log/ut-logger.cpp index 74028db..ef3634e 100644 --- a/tests/unit_tests/log/ut-logger.cpp +++ b/tests/unit_tests/log/ut-logger.cpp @@ -33,7 +33,7 @@ #include -BOOST_AUTO_TEST_SUITE(LogSuite) +BOOST_AUTO_TEST_SUITE(LoggerSuite) using namespace logger; @@ -135,7 +135,9 @@ BOOST_AUTO_TEST_CASE(StringLogLevelSetandGet) Logger::setLogLevel("ERROR"); BOOST_CHECK(LogLevel::ERROR == Logger::getLogLevel()); - BOOST_REQUIRE_THROW(Logger::setLogLevel("UNKNOWN"), std::runtime_error); + BOOST_REQUIRE_EXCEPTION(Logger::setLogLevel("UNKNOWN"), + std::runtime_error, + WhatEquals("Invalid LogLevel to parse")); //TODO change message } BOOST_AUTO_TEST_CASE(TestLogsError) diff --git a/tests/unit_tests/lxc/ut-zone.cpp b/tests/unit_tests/lxc/ut-zone.cpp index 6840e31..3b375bd 100644 --- a/tests/unit_tests/lxc/ut-zone.cpp +++ b/tests/unit_tests/lxc/ut-zone.cpp @@ -94,7 +94,7 @@ BOOST_AUTO_TEST_CASE(CreateDestroyTest) BOOST_CHECK(lxc.isDefined()); BOOST_CHECK_EQUAL(lxc.getConfigItem("lxc.rootfs"), LXC_PATH + ZONE_NAME + "/rootfs"); - BOOST_CHECK_THROW(lxc.getConfigItem("xxx"), LxcException); + BOOST_CHECK_EXCEPTION(lxc.getConfigItem("xxx"), LxcException, WhatEquals("Key not found")); BOOST_CHECK(lxc.destroy()); diff --git a/tests/unit_tests/server/ut-input-monitor.cpp b/tests/unit_tests/server/ut-input-monitor.cpp index 241da6c..9b4292f 100644 --- a/tests/unit_tests/server/ut-input-monitor.cpp +++ b/tests/unit_tests/server/ut-input-monitor.cpp @@ -94,23 +94,25 @@ BOOST_FIXTURE_TEST_SUITE(InputMonitorSuite, Fixture) BOOST_AUTO_TEST_CASE(Config_OK) { - BOOST_REQUIRE_NO_THROW(InputMonitor inputMonitor(inputConfig, InputMonitor::NotifyCallback())); + InputMonitor inputMonitor(inputConfig, InputMonitor::NotifyCallback()); } BOOST_AUTO_TEST_CASE(Config_timeWindowMsTooHigh) { inputConfig.timeWindowMs = 50000; - BOOST_REQUIRE_THROW(InputMonitor inputMonitor(inputConfig, InputMonitor::NotifyCallback()), - InputMonitorException); + BOOST_REQUIRE_EXCEPTION(InputMonitor inputMonitor(inputConfig, InputMonitor::NotifyCallback()), + InputMonitorException, + WhatEquals("Time window exceeds maximum")); } BOOST_AUTO_TEST_CASE(Config_deviceFilePathNotExisting) { inputConfig.device = TEST_INPUT_DEVICE + "notExisting"; - BOOST_REQUIRE_THROW(InputMonitor inputMonitor(inputConfig, InputMonitor::NotifyCallback()), - InputMonitorException); + BOOST_REQUIRE_EXCEPTION(InputMonitor inputMonitor(inputConfig, InputMonitor::NotifyCallback()), + InputMonitorException, + WhatEquals("Cannot find a device")); } namespace { @@ -119,8 +121,7 @@ void sendNEvents(Fixture& f, unsigned int noOfEventsToSend) { Latch eventLatch; - std::unique_ptr inputMonitor; - BOOST_REQUIRE_NO_THROW(inputMonitor.reset(new InputMonitor(f.inputConfig, [&] {eventLatch.set();}))); + InputMonitor inputMonitor(f.inputConfig, [&] {eventLatch.set();}); int fd = ::open(TEST_INPUT_DEVICE.c_str(), O_WRONLY); BOOST_REQUIRE(fd >= 0); @@ -166,8 +167,7 @@ void sendNEventsWithPauses(Fixture& f, unsigned int noOfEventsToSend) { Latch eventLatch; - std::unique_ptr inputMonitor; - BOOST_REQUIRE_NO_THROW(inputMonitor.reset(new InputMonitor(f.inputConfig, [&] {eventLatch.set();}))); + InputMonitor inputMonitor(f.inputConfig, [&] {eventLatch.set();}); int fd = ::open(TEST_INPUT_DEVICE.c_str(), O_WRONLY); BOOST_REQUIRE(fd >= 0); diff --git a/tests/unit_tests/server/ut-server.cpp b/tests/unit_tests/server/ut-server.cpp index c65e652..4df5d89 100644 --- a/tests/unit_tests/server/ut-server.cpp +++ b/tests/unit_tests/server/ut-server.cpp @@ -82,7 +82,9 @@ BOOST_AUTO_TEST_CASE(ConstructorDestructorTest) BOOST_AUTO_TEST_CASE(MissingConfigTest) { - BOOST_REQUIRE_THROW(Server(MISSING_CONFIG_PATH).run(AS_ROOT), ConfigException);//TODO check message + BOOST_REQUIRE_EXCEPTION(Server(MISSING_CONFIG_PATH).run(AS_ROOT), + ConfigException, + WhatEquals("Could not load " + MISSING_CONFIG_PATH)); } BOOST_AUTO_TEST_CASE(TerminateTest) diff --git a/tests/unit_tests/server/ut-zone-admin.cpp b/tests/unit_tests/server/ut-zone-admin.cpp index 21cc850..255e75e 100644 --- a/tests/unit_tests/server/ut-zone-admin.cpp +++ b/tests/unit_tests/server/ut-zone-admin.cpp @@ -87,7 +87,9 @@ BOOST_AUTO_TEST_CASE(ConstructorDestructorTest) BOOST_AUTO_TEST_CASE(MissingConfigTest) { - BOOST_REQUIRE_THROW(create(MISSING_CONFIG_PATH), ZoneOperationException);//TODO check message + BOOST_REQUIRE_EXCEPTION(create(MISSING_CONFIG_PATH), + ZoneOperationException, + WhatEquals("Could not create zone")); } BOOST_AUTO_TEST_CASE(StartTest) @@ -103,7 +105,9 @@ BOOST_AUTO_TEST_CASE(StartTest) BOOST_AUTO_TEST_CASE(StartBuggyTest) { auto admin = create(BUGGY_CONFIG_PATH); - BOOST_REQUIRE_THROW(admin->start(), ZoneOperationException);//TODO check message + BOOST_REQUIRE_EXCEPTION(admin->start(), + ZoneOperationException, + WhatEquals("Could not start zone")); } BOOST_AUTO_TEST_CASE(StopShutdownTest) @@ -158,9 +162,9 @@ BOOST_AUTO_TEST_CASE(SuspendResumeTest) // // admin->start(); // ensureStarted(); -// BOOST_REQUIRE_NO_THROW(admin->setSchedulerLevel(SchedulerLevel::FOREGROUND)); +// admin->setSchedulerLevel(SchedulerLevel::FOREGROUND); // BOOST_REQUIRE(admin->getSchedulerQuota() == config.cpuQuotaForeground); -// BOOST_REQUIRE_NO_THROW(admin->setSchedulerLevel(SchedulerLevel::BACKGROUND)); +// admin->setSchedulerLevel(SchedulerLevel::BACKGROUND); // BOOST_REQUIRE(admin->getSchedulerQuota() == config.cpuQuotaBackground); //} diff --git a/tests/unit_tests/server/ut-zone-connection.cpp b/tests/unit_tests/server/ut-zone-connection.cpp index a93b469..6d3e8e4 100644 --- a/tests/unit_tests/server/ut-zone-connection.cpp +++ b/tests/unit_tests/server/ut-zone-connection.cpp @@ -132,7 +132,7 @@ BOOST_AUTO_TEST_CASE(ConstructorDestructorConnectTest) ScopedGlibLoop loop; ScopedDbusDaemon dbus; - BOOST_REQUIRE_NO_THROW(ZoneConnection(dbus.acquireAddress(), nullptr)); + ZoneConnection(dbus.acquireAddress(), nullptr); } BOOST_AUTO_TEST_CASE(NotifyActiveZoneApiTest) @@ -141,16 +141,14 @@ BOOST_AUTO_TEST_CASE(NotifyActiveZoneApiTest) ScopedDbusDaemon dbus; Latch notifyCalled; - std::unique_ptr connection; - - BOOST_REQUIRE_NO_THROW(connection.reset(new ZoneConnection(dbus.acquireAddress(), nullptr))); + ZoneConnection connection(dbus.acquireAddress(), nullptr); auto callback = [&](const std::string& application, const std::string& message) { if (application == "testapp" && message == "testmessage") { notifyCalled.set(); } }; - connection->setNotifyActiveZoneCallback(callback); + connection.setNotifyActiveZoneCallback(callback); DbusConnection::Pointer client = DbusConnection::create(dbus.acquireAddress()); client->callMethod(api::zone::BUS_NAME, @@ -168,9 +166,7 @@ BOOST_AUTO_TEST_CASE(SignalNotificationApiTest) ScopedDbusDaemon dbus; Latch signalEmitted; - std::unique_ptr connection; - - BOOST_REQUIRE_NO_THROW(connection.reset(new ZoneConnection(dbus.acquireAddress(), nullptr))); + ZoneConnection connection(dbus.acquireAddress(), nullptr); DbusConnection::Pointer client = DbusConnection::create(dbus.acquireAddress()); @@ -197,7 +193,7 @@ BOOST_AUTO_TEST_CASE(SignalNotificationApiTest) }; client->signalSubscribe(handler, api::zone::BUS_NAME); - connection->sendNotification("testzone", "testapp", "testmessage"); + connection.sendNotification("testzone", "testapp", "testmessage"); BOOST_CHECK(signalEmitted.wait(EVENT_TIMEOUT)); } @@ -208,10 +204,7 @@ BOOST_AUTO_TEST_CASE(SignalDisplayOffApiTest) ScopedDbusDaemon dbus; Latch displayOffCalled; - std::unique_ptr connection; - - BOOST_REQUIRE_NO_THROW(connection.reset(new ZoneConnection(dbus.acquireAddress(), - nullptr))); + ZoneConnection connection(dbus.acquireAddress(), nullptr); DbusConnection::Pointer client = DbusConnection::create(dbus.acquireAddress()); @@ -219,7 +212,7 @@ BOOST_AUTO_TEST_CASE(SignalDisplayOffApiTest) displayOffCalled.set(); }; - connection->setDisplayOffCallback(callback); + connection.setDisplayOffCallback(callback); client->emitSignal(fake_power_manager_api::OBJECT_PATH, fake_power_manager_api::INTERFACE, diff --git a/tests/unit_tests/server/ut-zone-provision.cpp b/tests/unit_tests/server/ut-zone-provision.cpp index 9038fd4..4109cb2 100644 --- a/tests/unit_tests/server/ut-zone-provision.cpp +++ b/tests/unit_tests/server/ut-zone-provision.cpp @@ -89,12 +89,6 @@ struct Fixture { } }; -std::function expectedMessage(const std::string& message) { - return [=](const std::exception& e) { - return e.what() == message; - }; -} - } // namespace @@ -265,7 +259,7 @@ BOOST_AUTO_TEST_CASE(DeclareMountTest) zoneProvision.declareMount("/fake/path2", "/fake/path2", "tmpfs", 077, "fake"); BOOST_CHECK_EXCEPTION(zoneProvision.declareMount("/fake/path2", "/fake/path2", "tmpfs", 077, "fake"), UtilsException, - expectedMessage("Provision already exists")); + WhatEquals("Provision already exists")); ZoneProvisioningConfig config; load(config); @@ -397,7 +391,7 @@ BOOST_AUTO_TEST_CASE(RemoveTest) zoneProvision.remove("link /fake/path2 /fake/path4"); BOOST_CHECK_EXCEPTION(zoneProvision.remove("link /fake/path_fake /fake/path2"), UtilsException, - expectedMessage("Can't find provision")); + WhatEquals("Can't find provision")); const std::vector provisions = zoneProvision.list(); BOOST_REQUIRE_EQUAL(provisions.size(), expected.size()); diff --git a/tests/unit_tests/server/ut-zone.cpp b/tests/unit_tests/server/ut-zone.cpp index dbdf65a..3cd6031 100644 --- a/tests/unit_tests/server/ut-zone.cpp +++ b/tests/unit_tests/server/ut-zone.cpp @@ -94,12 +94,16 @@ BOOST_AUTO_TEST_CASE(ConstructorDestructorTest) BOOST_AUTO_TEST_CASE(BuggyConfigTest) { - BOOST_REQUIRE_THROW(create(BUGGY_CONFIG_PATH), ZoneOperationException);//TODO check message + BOOST_REQUIRE_EXCEPTION(create(BUGGY_CONFIG_PATH), + ZoneOperationException, + WhatEquals("Could not create zone")); } BOOST_AUTO_TEST_CASE(MissingConfigTest) { - BOOST_REQUIRE_THROW(create(MISSING_CONFIG_PATH), ConfigException);//TODO check message + BOOST_REQUIRE_EXCEPTION(create(MISSING_CONFIG_PATH), + ConfigException, + WhatEquals("Could not load " + MISSING_CONFIG_PATH)); } BOOST_AUTO_TEST_CASE(StartStopTest) diff --git a/tests/unit_tests/server/ut-zones-manager.cpp b/tests/unit_tests/server/ut-zones-manager.cpp index 58ac060..e93ab84 100644 --- a/tests/unit_tests/server/ut-zones-manager.cpp +++ b/tests/unit_tests/server/ut-zones-manager.cpp @@ -451,13 +451,6 @@ private: } }; -std::function expectedMessage(const std::string& message) -{ - return [=](const std::exception& e) { - return e.what() == message; - }; -} - template bool spinWaitFor(int timeoutMs, Predicate pred) { @@ -497,7 +490,9 @@ BOOST_AUTO_TEST_CASE(ConstructorDestructorTest) BOOST_AUTO_TEST_CASE(MissingConfigTest) { - BOOST_REQUIRE_THROW(ZonesManager cm(MISSING_CONFIG_PATH), ConfigException); + BOOST_REQUIRE_EXCEPTION(ZonesManager{MISSING_CONFIG_PATH}, + ConfigException, + WhatEquals("Could not load " + MISSING_CONFIG_PATH)); } BOOST_AUTO_TEST_CASE(CreateTest) @@ -867,12 +862,12 @@ BOOST_AUTO_TEST_CASE(ProxyCallTest) // host -> unknown BOOST_CHECK_EXCEPTION(dbuses.at(0)->testApiProxyCall("unknown", "param"), DbusCustomException, - expectedMessage("Unknown proxy call target")); + WhatEquals("Unknown proxy call target")); // forwarding error BOOST_CHECK_EXCEPTION(dbuses.at(0)->testApiProxyCall("host", ""), DbusCustomException, - expectedMessage("Test error")); + WhatEquals("Test error")); // forbidden call BOOST_CHECK_EXCEPTION(dbuses.at(0)->proxyCall("host", @@ -882,7 +877,7 @@ BOOST_AUTO_TEST_CASE(ProxyCallTest) "foo", g_variant_new("(s)", "arg")), DbusCustomException, - expectedMessage("Proxy call forbidden")); + WhatEquals("Proxy call forbidden")); } namespace { @@ -1039,12 +1034,14 @@ BOOST_AUTO_TEST_CASE(SetActiveZoneTest) BOOST_CHECK(dbus.callMethodGetActiveZoneId() == zoneId); } - BOOST_REQUIRE_THROW(dbus.callMethodSetActiveZone(NON_EXISTANT_ZONE_ID), - DbusException); + BOOST_REQUIRE_EXCEPTION(dbus.callMethodSetActiveZone(NON_EXISTANT_ZONE_ID), + DbusException, + WhatEquals("No such zone id")); cm.stopAll(); - BOOST_REQUIRE_THROW(dbus.callMethodSetActiveZone("zone1"), - DbusException); + BOOST_REQUIRE_EXCEPTION(dbus.callMethodSetActiveZone("zone1"), + DbusException, + WhatEquals("Could not activate stopped or paused zone")); } BOOST_AUTO_TEST_CASE(CreateDestroyZoneTest) @@ -1204,16 +1201,20 @@ BOOST_AUTO_TEST_CASE(LockUnlockZoneTest) BOOST_CHECK(cm.isRunning(zoneId)); } - BOOST_REQUIRE_THROW(dbus.callMethodLockZone(NON_EXISTANT_ZONE_ID), - DbusException); - BOOST_REQUIRE_THROW(dbus.callMethodUnlockZone(NON_EXISTANT_ZONE_ID), - DbusException); + BOOST_REQUIRE_EXCEPTION(dbus.callMethodLockZone(NON_EXISTANT_ZONE_ID), + DbusException, + WhatEquals("No such zone id")); + BOOST_REQUIRE_EXCEPTION(dbus.callMethodUnlockZone(NON_EXISTANT_ZONE_ID), + DbusException, + WhatEquals("No such zone id")); cm.stopAll(); - BOOST_REQUIRE_THROW(dbus.callMethodLockZone("zone1"), - DbusException); - BOOST_REQUIRE_THROW(dbus.callMethodUnlockZone("zone1"), - DbusException); + BOOST_REQUIRE_EXCEPTION(dbus.callMethodLockZone("zone1"), + DbusException, + WhatEquals("Zone is not running")); + BOOST_REQUIRE_EXCEPTION(dbus.callMethodUnlockZone("zone1"), + DbusException, + WhatEquals("Zone is not paused")); } BOOST_AUTO_TEST_SUITE_END() diff --git a/tests/unit_tests/ut.hpp b/tests/unit_tests/ut.hpp index cbc322a..d8b4b94 100644 --- a/tests/unit_tests/ut.hpp +++ b/tests/unit_tests/ut.hpp @@ -28,4 +28,27 @@ #define BOOST_TEST_DYN_LINK #include +#include + +/** + * An exception message checker + * + * Usage example: + * BOOST_CHECK_EXCEPTION(foo(), SomeException, WhatEquals("oops")) + */ +class WhatEquals { +public: + explicit WhatEquals(const std::string& message) + : mMessage(message) {} + + template + bool operator()(const T& e) + { + BOOST_WARN_EQUAL(e.what(), mMessage); // additional failure info + return e.what() == mMessage; + } +private: + std::string mMessage; +}; + #endif // UNIT_TESTS_UT_HPP diff --git a/tests/unit_tests/utils/ut-fs.cpp b/tests/unit_tests/utils/ut-fs.cpp index 63b4f63..365c1e1 100644 --- a/tests/unit_tests/utils/ut-fs.cpp +++ b/tests/unit_tests/utils/ut-fs.cpp @@ -76,7 +76,9 @@ const std::string FILE_NAME_RANDOM_2 = BOOST_AUTO_TEST_CASE(ReadFileContentTest) { BOOST_CHECK_EQUAL(FILE_CONTENT, readFileContent(FILE_PATH)); - BOOST_CHECK_THROW(readFileContent(BUGGY_FILE_PATH), UtilsException); + BOOST_CHECK_EXCEPTION(readFileContent(BUGGY_FILE_PATH), + UtilsException, + WhatEquals("Read failed")); } BOOST_AUTO_TEST_CASE(SaveFileContentTest) @@ -217,8 +219,7 @@ BOOST_AUTO_TEST_CASE(CopyDirContentsTest) BOOST_CHECK_EQUAL(readFileContent(dst_inner2 + "/" + FILE_NAME_RANDOM_1), FILE_CONTENT_3); BOOST_CHECK_EQUAL(readFileContent(dst_inner2 + "/" + FILE_NAME_RANDOM_2), FILE_CONTENT_2); - fs::file_status st; - BOOST_REQUIRE_NO_THROW(st = fs::status(fs::path(dst_inner2))); + fs::file_status st = fs::status(fs::path(dst_inner2)); BOOST_CHECK(fs::owner_read == st.permissions()); } diff --git a/tests/unit_tests/utils/ut-value-latch.cpp b/tests/unit_tests/utils/ut-value-latch.cpp index a16128e..711c8e6 100644 --- a/tests/unit_tests/utils/ut-value-latch.cpp +++ b/tests/unit_tests/utils/ut-value-latch.cpp @@ -105,7 +105,9 @@ BOOST_AUTO_TEST_CASE(TimeoutTest) { ValueLatch testLatch; - BOOST_REQUIRE_THROW(testLatch.get(EXPECTED_TIMEOUT), vasum::UtilsException); + BOOST_REQUIRE_EXCEPTION(testLatch.get(EXPECTED_TIMEOUT), + vasum::UtilsException, + WhatEquals("Timeout occured")); } BOOST_AUTO_TEST_CASE(MultipleSetTest) @@ -113,7 +115,9 @@ BOOST_AUTO_TEST_CASE(MultipleSetTest) ValueLatch testLatch; testLatch.set(3); - BOOST_REQUIRE_THROW(testLatch.set(2), vasum::UtilsException); + BOOST_REQUIRE_EXCEPTION(testLatch.set(2), + vasum::UtilsException, + WhatEquals("Cannot set value multiple times")); } BOOST_AUTO_TEST_CASE(MultipleGetTest) @@ -122,7 +126,9 @@ BOOST_AUTO_TEST_CASE(MultipleGetTest) testLatch.set(3); testLatch.get(TIMEOUT); - BOOST_REQUIRE_THROW(testLatch.get(EXPECTED_TIMEOUT), vasum::UtilsException); + BOOST_REQUIRE_EXCEPTION(testLatch.get(EXPECTED_TIMEOUT), + vasum::UtilsException, + WhatEquals("Timeout occured")); } BOOST_AUTO_TEST_SUITE_END() diff --git a/zone-daemon/exception.hpp b/zone-daemon/exception.hpp index a281910..5fcf54d 100644 --- a/zone-daemon/exception.hpp +++ b/zone-daemon/exception.hpp @@ -37,7 +37,7 @@ namespace zone_daemon { */ struct ZoneDaemonException: public VasumException { - ZoneDaemonException(const std::string& error = "") : VasumException(error) {} + ZoneDaemonException(const std::string& error) : VasumException(error) {} }; -- 2.7.4 From cce992d41fef71d7725b3dbebc54a24db61f1f7e Mon Sep 17 00:00:00 2001 From: Piotr Bartosiewicz Date: Thu, 19 Feb 2015 12:28:27 +0100 Subject: [PATCH 11/16] Unify unit tests cleanup [Bug/Feature] N/A [Cause] N/A [Solution] N/A [Verification] Run tests Change-Id: I2a49450b3991355656028194b14f9eae5a222456 --- .../dbus/configs/ut-connection/ut-dbus.conf | 2 +- tests/unit_tests/dbus/test-common.hpp | 5 +- tests/unit_tests/dbus/ut-connection.cpp | 7 +- tests/unit_tests/ipc/ut-ipc.cpp | 105 +++++++------- .../server/configs/ut-zone-connection/ut-dbus.conf | 2 +- tests/unit_tests/server/ut-input-monitor.cpp | 15 +- tests/unit_tests/server/ut-zone-connection.cpp | 42 +++--- tests/unit_tests/utils/ut-fs.cpp | 160 ++++++++++----------- 8 files changed, 162 insertions(+), 176 deletions(-) diff --git a/tests/unit_tests/dbus/configs/ut-connection/ut-dbus.conf b/tests/unit_tests/dbus/configs/ut-connection/ut-dbus.conf index f3bf58c..d6091a2 100644 --- a/tests/unit_tests/dbus/configs/ut-connection/ut-dbus.conf +++ b/tests/unit_tests/dbus/configs/ut-connection/ut-dbus.conf @@ -5,7 +5,7 @@ custom - unix:path=/tmp/zone_socket + unix:path=/tmp/ut-dbus/test-socket diff --git a/tests/unit_tests/dbus/test-common.hpp b/tests/unit_tests/dbus/test-common.hpp index ae76d82..7b6262b 100644 --- a/tests/unit_tests/dbus/test-common.hpp +++ b/tests/unit_tests/dbus/test-common.hpp @@ -31,8 +31,9 @@ namespace vasum { -const std::string DBUS_SOCKET_FILE = "/tmp/zone_socket"; -const std::string DBUS_ADDRESS = "unix:path=" + DBUS_SOCKET_FILE; +const std::string DBUS_SOCKET_DIR = "/tmp/ut-dbus"; +const std::string DBUS_SOCKET_PATH = DBUS_SOCKET_DIR + "/test-socket"; +const std::string DBUS_ADDRESS = "unix:path=" + DBUS_SOCKET_PATH; const std::string TESTAPI_BUS_NAME = "org.tizen.tests"; const std::string TESTAPI_OBJECT_PATH = "/org/tizen/tests"; diff --git a/tests/unit_tests/dbus/ut-connection.cpp b/tests/unit_tests/dbus/ut-connection.cpp index 5182225..4948cd7 100644 --- a/tests/unit_tests/dbus/ut-connection.cpp +++ b/tests/unit_tests/dbus/ut-connection.cpp @@ -28,6 +28,7 @@ #include "dbus/test-client.hpp" #include "dbus/test-common.hpp" #include "utils/scoped-daemon.hpp" +#include "utils/scoped-dir.hpp" #include "dbus/connection.hpp" #include "dbus/exception.hpp" @@ -37,7 +38,6 @@ #include "utils/fs.hpp" #include "logger/logger.hpp" -#include #include #include #include @@ -65,16 +65,17 @@ const int EVENT_TIMEOUT = 1000; class ScopedDbusDaemon { public: ScopedDbusDaemon() + : mTestPathGuard(DBUS_SOCKET_DIR) { - boost::filesystem::remove("/tmp/zone_socket"); mDaemon.start(DBUS_DAEMON_PROC, DBUS_DAEMON_ARGS); - waitForFile(DBUS_SOCKET_FILE, DBUS_DAEMON_TIMEOUT); + waitForFile(DBUS_SOCKET_PATH, DBUS_DAEMON_TIMEOUT); } void stop() { mDaemon.stop(); } private: + ScopedDir mTestPathGuard; ScopedDaemon mDaemon; }; diff --git a/tests/unit_tests/ipc/ut-ipc.cpp b/tests/unit_tests/ipc/ut-ipc.cpp index 56c94cb..193eec9 100644 --- a/tests/unit_tests/ipc/ut-ipc.cpp +++ b/tests/unit_tests/ipc/ut-ipc.cpp @@ -37,6 +37,7 @@ #include "utils/glib-loop.hpp" #include "utils/latch.hpp" #include "utils/value-latch.hpp" +#include "utils/scoped-dir.hpp" #include "config/fields.hpp" #include "logger/logger.hpp" @@ -47,13 +48,11 @@ #include #include #include -#include using namespace vasum; using namespace vasum::ipc; using namespace vasum::utils; using namespace std::placeholders; -namespace fs = boost::filesystem; namespace { @@ -66,16 +65,16 @@ const int SHORT_OPERATION_TIME = TIMEOUT / 100; // Time that will cause "TIMEOUT" methods to throw const int LONG_OPERATION_TIME = 1000 + TIMEOUT; +const std::string TEST_DIR = "/tmp/ut-ipc"; +const std::string SOCKET_PATH = TEST_DIR + "/test.socket"; + struct Fixture { - std::string socketPath; + ScopedDir mTestPathGuard; + std::string SOCKET_PATH; Fixture() - : socketPath(fs::unique_path("/tmp/ipc-%%%%.socket").string()) - { - } - ~Fixture() + : mTestPathGuard(TEST_DIR) { - fs::remove(socketPath); } }; @@ -224,13 +223,13 @@ BOOST_FIXTURE_TEST_SUITE(IPCSuite, Fixture) BOOST_AUTO_TEST_CASE(ConstructorDestructor) { - Service s(socketPath); - Client c(socketPath); + Service s(SOCKET_PATH); + Client c(SOCKET_PATH); } BOOST_AUTO_TEST_CASE(ServiceAddRemoveMethod) { - Service s(socketPath); + Service s(SOCKET_PATH); s.setMethodHandler(1, returnEmptyCallback); s.setMethodHandler(1, returnDataCallback); @@ -239,7 +238,7 @@ BOOST_AUTO_TEST_CASE(ServiceAddRemoveMethod) s.setMethodHandler(1, echoCallback); s.setMethodHandler(2, returnDataCallback); - Client c(socketPath); + Client c(SOCKET_PATH); connect(s, c); testEcho(c, 1); @@ -251,8 +250,8 @@ BOOST_AUTO_TEST_CASE(ServiceAddRemoveMethod) BOOST_AUTO_TEST_CASE(ClientAddRemoveMethod) { - Service s(socketPath); - Client c(socketPath); + Service s(SOCKET_PATH); + Client c(SOCKET_PATH); c.setMethodHandler(1, returnEmptyCallback); c.setMethodHandler(1, returnDataCallback); @@ -271,7 +270,7 @@ BOOST_AUTO_TEST_CASE(ClientAddRemoveMethod) BOOST_AUTO_TEST_CASE(ServiceStartStop) { - Service s(socketPath); + Service s(SOCKET_PATH); s.setMethodHandler(1, returnDataCallback); @@ -286,8 +285,8 @@ BOOST_AUTO_TEST_CASE(ServiceStartStop) BOOST_AUTO_TEST_CASE(ClientStartStop) { - Service s(socketPath); - Client c(socketPath); + Service s(SOCKET_PATH); + Client c(SOCKET_PATH); c.setMethodHandler(1, returnDataCallback); c.start(); @@ -304,11 +303,11 @@ BOOST_AUTO_TEST_CASE(ClientStartStop) BOOST_AUTO_TEST_CASE(SyncClientToServiceEcho) { - Service s(socketPath); + Service s(SOCKET_PATH); s.setMethodHandler(1, echoCallback); s.setMethodHandler(2, echoCallback); - Client c(socketPath); + Client c(SOCKET_PATH); connect(s, c); testEcho(c, 1); @@ -317,12 +316,12 @@ BOOST_AUTO_TEST_CASE(SyncClientToServiceEcho) BOOST_AUTO_TEST_CASE(Restart) { - Service s(socketPath); + Service s(SOCKET_PATH); s.setMethodHandler(1, echoCallback); s.start(); s.setMethodHandler(2, echoCallback); - Client c(socketPath); + Client c(SOCKET_PATH); c.start(); testEcho(c, 1); testEcho(c, 2); @@ -342,8 +341,8 @@ BOOST_AUTO_TEST_CASE(Restart) BOOST_AUTO_TEST_CASE(SyncServiceToClientEcho) { - Service s(socketPath); - Client c(socketPath); + Service s(SOCKET_PATH); + Client c(SOCKET_PATH); c.setMethodHandler(1, echoCallback); PeerID peerID = connect(s, c); @@ -359,10 +358,10 @@ BOOST_AUTO_TEST_CASE(AsyncClientToServiceEcho) ValueLatch> recvDataLatch; // Setup Service and Client - Service s(socketPath); + Service s(SOCKET_PATH); s.setMethodHandler(1, echoCallback); s.start(); - Client c(socketPath); + Client c(SOCKET_PATH); c.start(); //Async call @@ -381,8 +380,8 @@ BOOST_AUTO_TEST_CASE(AsyncServiceToClientEcho) std::shared_ptr sentData(new SendData(56)); ValueLatch> recvDataLatch; - Service s(socketPath); - Client c(socketPath); + Service s(SOCKET_PATH); + Client c(SOCKET_PATH); c.setMethodHandler(1, echoCallback); PeerID peerID = connect(s, c); @@ -401,10 +400,10 @@ BOOST_AUTO_TEST_CASE(AsyncServiceToClientEcho) BOOST_AUTO_TEST_CASE(SyncTimeout) { - Service s(socketPath); + Service s(SOCKET_PATH); s.setMethodHandler(1, longEchoCallback); - Client c(socketPath); + Client c(SOCKET_PATH); connect(s, c); std::shared_ptr sentData(new SendData(78)); @@ -413,10 +412,10 @@ BOOST_AUTO_TEST_CASE(SyncTimeout) BOOST_AUTO_TEST_CASE(SerializationError) { - Service s(socketPath); + Service s(SOCKET_PATH); s.setMethodHandler(1, echoCallback); - Client c(socketPath); + Client c(SOCKET_PATH); connect(s, c); std::shared_ptr throwingData(new ThrowOnAcceptData()); @@ -427,11 +426,11 @@ BOOST_AUTO_TEST_CASE(SerializationError) BOOST_AUTO_TEST_CASE(ParseError) { - Service s(socketPath); + Service s(SOCKET_PATH); s.setMethodHandler(1, echoCallback); s.start(); - Client c(socketPath); + Client c(SOCKET_PATH); c.start(); std::shared_ptr sentData(new SendData(78)); @@ -441,7 +440,7 @@ BOOST_AUTO_TEST_CASE(ParseError) BOOST_AUTO_TEST_CASE(DisconnectedPeerError) { ValueLatch> retStatusLatch; - Service s(socketPath); + Service s(SOCKET_PATH); auto method = [](const PeerID, std::shared_ptr&, MethodResult::Pointer methodResult) { auto resultData = std::make_shared(1); @@ -452,7 +451,7 @@ BOOST_AUTO_TEST_CASE(DisconnectedPeerError) s.setMethodHandler(1, method); s.start(); - Client c(socketPath); + Client c(SOCKET_PATH); c.start(); auto dataBack = [&retStatusLatch](Result && r) { @@ -474,14 +473,14 @@ BOOST_AUTO_TEST_CASE(DisconnectedPeerError) BOOST_AUTO_TEST_CASE(ReadTimeout) { - Service s(socketPath); + Service s(SOCKET_PATH); auto longEchoCallback = [](const PeerID, std::shared_ptr& data, MethodResult::Pointer methodResult) { auto resultData = std::make_shared(data->intVal, LONG_OPERATION_TIME); methodResult->set(resultData); }; s.setMethodHandler(1, longEchoCallback); - Client c(socketPath); + Client c(SOCKET_PATH); connect(s, c); // Test timeout on read @@ -492,11 +491,11 @@ BOOST_AUTO_TEST_CASE(ReadTimeout) BOOST_AUTO_TEST_CASE(WriteTimeout) { - Service s(socketPath); + Service s(SOCKET_PATH); s.setMethodHandler(1, echoCallback); s.start(); - Client c(socketPath); + Client c(SOCKET_PATH); c.start(); // Test echo with a minimal timeout @@ -516,8 +515,8 @@ BOOST_AUTO_TEST_CASE(AddSignalInRuntime) ValueLatch> recvDataLatchA; ValueLatch> recvDataLatchB; - Service s(socketPath); - Client c(socketPath); + Service s(SOCKET_PATH); + Client c(SOCKET_PATH); connect(s, c); auto handlerA = [&recvDataLatchA](const PeerID, std::shared_ptr& data) { @@ -552,8 +551,8 @@ BOOST_AUTO_TEST_CASE(AddSignalOffline) ValueLatch> recvDataLatchA; ValueLatch> recvDataLatchB; - Service s(socketPath); - Client c(socketPath); + Service s(SOCKET_PATH); + Client c(SOCKET_PATH); auto handlerA = [&recvDataLatchA](const PeerID, std::shared_ptr& data) { recvDataLatchA.set(data); @@ -594,10 +593,10 @@ BOOST_AUTO_TEST_CASE(ServiceGSource) }; IPCGSource::Pointer serviceGSource; - Service s(socketPath); + Service s(SOCKET_PATH); s.setMethodHandler(1, echoCallback); - Client c(socketPath); + Client c(SOCKET_PATH); s.setSignalHandler(2, signalHandler); connectServiceGSource(s, c); @@ -620,11 +619,11 @@ BOOST_AUTO_TEST_CASE(ClientGSource) l.set(); }; - Service s(socketPath); + Service s(SOCKET_PATH); s.start(); IPCGSource::Pointer clientGSource; - Client c(socketPath); + Client c(SOCKET_PATH); c.setMethodHandler(1, echoCallback); c.setSignalHandler(2, signalHandler); @@ -643,8 +642,8 @@ BOOST_AUTO_TEST_CASE(UsersError) const int TEST_ERROR_CODE = -234; const std::string TEST_ERROR_MESSAGE = "Ay, caramba!"; - Service s(socketPath); - Client c(socketPath); + Service s(SOCKET_PATH); + Client c(SOCKET_PATH); auto clientID = connect(s, c); auto throwingMethodHandler = [&](const PeerID, std::shared_ptr&, MethodResult::Pointer) { @@ -677,8 +676,8 @@ BOOST_AUTO_TEST_CASE(AsyncResult) const int TEST_ERROR_CODE = -567; const std::string TEST_ERROR_MESSAGE = "Ooo jooo!"; - Service s(socketPath); - Client c(socketPath); + Service s(SOCKET_PATH); + Client c(SOCKET_PATH); auto clientID = connect(s, c); auto errorMethodHandler = [&](const PeerID, std::shared_ptr&, MethodResult::Pointer methodResult) { @@ -734,14 +733,14 @@ BOOST_AUTO_TEST_CASE(AsyncResult) // ipc::setMaxFDNumber(50); // // Setup Service and many Clients -// Service s(socketPath); +// Service s(SOCKET_PATH); // s.setMethodHandler(1, echoCallback); // s.start(); // std::list clients; // for (int i = 0; i < 100; ++i) { // try { -// clients.push_back(Client(socketPath)); +// clients.push_back(Client(SOCKET_PATH)); // clients.back().start(); // } catch (...) {} // } diff --git a/tests/unit_tests/server/configs/ut-zone-connection/ut-dbus.conf b/tests/unit_tests/server/configs/ut-zone-connection/ut-dbus.conf index d60e774..66ee3f9 100644 --- a/tests/unit_tests/server/configs/ut-zone-connection/ut-dbus.conf +++ b/tests/unit_tests/server/configs/ut-zone-connection/ut-dbus.conf @@ -5,7 +5,7 @@ custom - unix:path=/tmp/ut-zone-connection/dbus/system_bus_socket + unix:path=/tmp/ut-zones/mount-point/dbus/system_bus_socket diff --git a/tests/unit_tests/server/ut-input-monitor.cpp b/tests/unit_tests/server/ut-input-monitor.cpp index 9b4292f..3560b40 100644 --- a/tests/unit_tests/server/ut-input-monitor.cpp +++ b/tests/unit_tests/server/ut-input-monitor.cpp @@ -32,6 +32,7 @@ #include "utils/glib-loop.hpp" #include "utils/latch.hpp" +#include "utils/scoped-dir.hpp" #include #include @@ -39,7 +40,6 @@ #include #include -#include #include #include #include @@ -50,8 +50,8 @@ using namespace vasum::utils; namespace { -std::string TEST_INPUT_DEVICE = - boost::filesystem::unique_path("/tmp/testInputDevice-%%%%").string(); +const std::string TEST_DIR = "/tmp/ut-input-monitor"; +const std::string TEST_INPUT_DEVICE = TEST_DIR + "/input-device"; const int EVENT_TYPE = 1; const int EVENT_CODE = 139; @@ -61,11 +61,13 @@ const int EVENT_BUTTON_PRESSED = 1; const int SINGLE_EVENT_TIMEOUT = 1000; struct Fixture { - InputConfig inputConfig; utils::ScopedGlibLoop mLoop; + ScopedDir mTestPathGuard; + InputConfig inputConfig; struct input_event ie; Fixture() + : mTestPathGuard(TEST_DIR) { inputConfig.numberOfEvents = 2; inputConfig.device = TEST_INPUT_DEVICE; @@ -80,13 +82,8 @@ struct Fixture { ie.code = EVENT_CODE; ie.value = EVENT_BUTTON_RELEASED; - ::remove(TEST_INPUT_DEVICE.c_str()); BOOST_CHECK(::mkfifo(TEST_INPUT_DEVICE.c_str(), S_IWUSR | S_IRUSR) >= 0); } - ~Fixture() - { - ::remove(TEST_INPUT_DEVICE.c_str()); - } }; } // namespace diff --git a/tests/unit_tests/server/ut-zone-connection.cpp b/tests/unit_tests/server/ut-zone-connection.cpp index 6d3e8e4..fb6df88 100644 --- a/tests/unit_tests/server/ut-zone-connection.cpp +++ b/tests/unit_tests/server/ut-zone-connection.cpp @@ -39,10 +39,9 @@ #include "utils/glib-loop.hpp" #include "utils/latch.hpp" #include "utils/fs.hpp" +#include "utils/scoped-dir.hpp" -BOOST_AUTO_TEST_SUITE(ZoneConnectionSuite) - using namespace vasum; using namespace vasum::utils; using namespace dbus; @@ -57,13 +56,15 @@ const char* const DBUS_DAEMON_ARGS[] = { NULL }; -const std::string TRANSPORT_MOUNT_POINT = "/tmp/ut-zone-connection"; +const std::string ZONES_PATH = "/tmp/ut-zones"; +const std::string TRANSPORT_MOUNT_POINT = ZONES_PATH + "/mount-point"; const int EVENT_TIMEOUT = 1000; -class ScopedDbusDaemon { +class Fixture { public: - ScopedDbusDaemon() - : mTransport(TRANSPORT_MOUNT_POINT) + Fixture() + : mZonesPathGuard(ZONES_PATH) + , mTransport(TRANSPORT_MOUNT_POINT) { mDaemon.start(DBUS_DAEMON_PROC, DBUS_DAEMON_ARGS); } @@ -73,6 +74,8 @@ public: return mTransport.acquireAddress(); } private: + ScopedGlibLoop mLoop; + ScopedDir mZonesPathGuard; ZoneConnectionTransport mTransport; ScopedDaemon mDaemon; }; @@ -126,22 +129,17 @@ private: } // namespace +BOOST_FIXTURE_TEST_SUITE(ZoneConnectionSuite, Fixture) BOOST_AUTO_TEST_CASE(ConstructorDestructorConnectTest) { - ScopedGlibLoop loop; - ScopedDbusDaemon dbus; - - ZoneConnection(dbus.acquireAddress(), nullptr); + ZoneConnection(acquireAddress(), nullptr); } BOOST_AUTO_TEST_CASE(NotifyActiveZoneApiTest) { - ScopedGlibLoop loop; - ScopedDbusDaemon dbus; - Latch notifyCalled; - ZoneConnection connection(dbus.acquireAddress(), nullptr); + ZoneConnection connection(acquireAddress(), nullptr); auto callback = [&](const std::string& application, const std::string& message) { if (application == "testapp" && message == "testmessage") { @@ -150,7 +148,7 @@ BOOST_AUTO_TEST_CASE(NotifyActiveZoneApiTest) }; connection.setNotifyActiveZoneCallback(callback); - DbusConnection::Pointer client = DbusConnection::create(dbus.acquireAddress()); + DbusConnection::Pointer client = DbusConnection::create(acquireAddress()); client->callMethod(api::zone::BUS_NAME, api::zone::OBJECT_PATH, api::zone::INTERFACE, @@ -162,13 +160,10 @@ BOOST_AUTO_TEST_CASE(NotifyActiveZoneApiTest) BOOST_AUTO_TEST_CASE(SignalNotificationApiTest) { - ScopedGlibLoop loop; - ScopedDbusDaemon dbus; - Latch signalEmitted; - ZoneConnection connection(dbus.acquireAddress(), nullptr); + ZoneConnection connection(acquireAddress(), nullptr); - DbusConnection::Pointer client = DbusConnection::create(dbus.acquireAddress()); + DbusConnection::Pointer client = DbusConnection::create(acquireAddress()); auto handler = [&](const std::string& /*senderBusName*/, const std::string& objectPath, @@ -200,13 +195,10 @@ BOOST_AUTO_TEST_CASE(SignalNotificationApiTest) BOOST_AUTO_TEST_CASE(SignalDisplayOffApiTest) { - ScopedGlibLoop loop; - ScopedDbusDaemon dbus; - Latch displayOffCalled; - ZoneConnection connection(dbus.acquireAddress(), nullptr); + ZoneConnection connection(acquireAddress(), nullptr); - DbusConnection::Pointer client = DbusConnection::create(dbus.acquireAddress()); + DbusConnection::Pointer client = DbusConnection::create(acquireAddress()); auto callback = [&]() { displayOffCalled.set(); diff --git a/tests/unit_tests/utils/ut-fs.cpp b/tests/unit_tests/utils/ut-fs.cpp index 365c1e1..b2defba 100644 --- a/tests/unit_tests/utils/ut-fs.cpp +++ b/tests/unit_tests/utils/ut-fs.cpp @@ -28,54 +28,53 @@ #include "utils/fs.hpp" #include "utils/exception.hpp" +#include "utils/scoped-dir.hpp" #include #include #include -BOOST_AUTO_TEST_SUITE(UtilsFSSuite) - using namespace vasum; using namespace vasum::utils; namespace { -const std::string FILE_PATH = VSM_TEST_CONFIG_INSTALL_DIR "/utils/ut-fs/file.txt"; -const std::string FILE_CONTENT = "File content\n" - "Line 1\n" - "Line 2\n"; +const std::string TEST_PATH = "/tmp/ut-fsutils"; +const std::string REFERENCE_FILE_PATH = VSM_TEST_CONFIG_INSTALL_DIR "/utils/ut-fs/file.txt"; +const std::string REFERENCE_FILE_CONTENT = "File content\n" + "Line 1\n" + "Line 2\n"; const std::string FILE_CONTENT_2 = "Some other content\n" "Just to see if\n" "everything is copied correctly\n"; const std::string FILE_CONTENT_3 = "More content\n" "More and more content\n" "That's a lot of data to test\n"; -const std::string BUGGY_FILE_PATH = "/some/missing/file/path/file.txt"; -const std::string TMP_PATH = "/tmp"; -const std::string FILE_PATH_RANDOM = - boost::filesystem::unique_path("/tmp/testFile-%%%%").string(); -const std::string MOUNT_POINT_RANDOM_1 = - boost::filesystem::unique_path("/tmp/mountPoint-%%%%").string(); -const std::string MOUNT_POINT_RANDOM_2 = - boost::filesystem::unique_path("/tmp/mountPoint-%%%%").string(); -const std::string FILE_DIR_RANDOM_1 = - boost::filesystem::unique_path("testDir-%%%%").string(); -const std::string FILE_DIR_RANDOM_2 = - boost::filesystem::unique_path("testDir-%%%%").string(); -const std::string FILE_DIR_RANDOM_3 = - boost::filesystem::unique_path("testDir-%%%%").string(); -const std::string FILE_DIR_RANDOM_4 = - boost::filesystem::unique_path("testDir-%%%%").string(); -const std::string FILE_NAME_RANDOM_1 = - boost::filesystem::unique_path("testFile-%%%%").string(); -const std::string FILE_NAME_RANDOM_2 = - boost::filesystem::unique_path("testFile-%%%%").string(); +const std::string BUGGY_FILE_PATH = TEST_PATH + "/missing/file.txt"; +const std::string FILE_PATH = TEST_PATH + "/testFile"; +const std::string MOUNT_POINT_1 = TEST_PATH + "/mountPoint-1"; +const std::string MOUNT_POINT_2 = TEST_PATH + "/mountPoint-2"; +const std::string FILE_DIR_1 = "testDir-1"; +const std::string FILE_DIR_2 = "testDir-2"; +const std::string FILE_DIR_3 = "testDir-3"; +const std::string FILE_DIR_4 = "testDir-4"; +const std::string FILE_NAME_1 = "testFile-1"; +const std::string FILE_NAME_2 = "testFile-2"; + +struct Fixture { + utils::ScopedDir mTestPathGuard; + Fixture() + : mTestPathGuard(TEST_PATH) + {} +}; } // namespace +BOOST_FIXTURE_TEST_SUITE(UtilsFSSuite, Fixture) + BOOST_AUTO_TEST_CASE(ReadFileContentTest) { - BOOST_CHECK_EQUAL(FILE_CONTENT, readFileContent(FILE_PATH)); + BOOST_CHECK_EQUAL(REFERENCE_FILE_CONTENT, readFileContent(REFERENCE_FILE_PATH)); BOOST_CHECK_EXCEPTION(readFileContent(BUGGY_FILE_PATH), UtilsException, WhatEquals("Read failed")); @@ -83,18 +82,15 @@ BOOST_AUTO_TEST_CASE(ReadFileContentTest) BOOST_AUTO_TEST_CASE(SaveFileContentTest) { - BOOST_REQUIRE(saveFileContent(FILE_PATH_RANDOM, FILE_CONTENT)); - BOOST_CHECK_EQUAL(FILE_CONTENT, readFileContent(FILE_PATH)); - - boost::system::error_code ec; - boost::filesystem::remove(FILE_PATH_RANDOM, ec); + BOOST_REQUIRE(saveFileContent(FILE_PATH, REFERENCE_FILE_CONTENT)); + BOOST_CHECK_EQUAL(REFERENCE_FILE_CONTENT, readFileContent(FILE_PATH)); } BOOST_AUTO_TEST_CASE(RemoveFileTest) { - BOOST_REQUIRE(saveFileContent(FILE_PATH_RANDOM, FILE_CONTENT)); - BOOST_REQUIRE(removeFile(FILE_PATH_RANDOM)); - BOOST_REQUIRE(!boost::filesystem::exists(FILE_PATH_RANDOM)); + BOOST_REQUIRE(saveFileContent(FILE_PATH, REFERENCE_FILE_CONTENT)); + BOOST_REQUIRE(removeFile(FILE_PATH)); + BOOST_REQUIRE(!boost::filesystem::exists(FILE_PATH)); } BOOST_AUTO_TEST_CASE(MountPointTest) @@ -103,20 +99,20 @@ BOOST_AUTO_TEST_CASE(MountPointTest) namespace fs = boost::filesystem; boost::system::error_code ec; - BOOST_REQUIRE(fs::create_directory(MOUNT_POINT_RANDOM_1, ec)); - BOOST_REQUIRE(isMountPoint(MOUNT_POINT_RANDOM_1, result)); + BOOST_REQUIRE(fs::create_directory(MOUNT_POINT_1, ec)); + BOOST_REQUIRE(isMountPoint(MOUNT_POINT_1, result)); BOOST_CHECK_EQUAL(result, false); - BOOST_REQUIRE(hasSameMountPoint(TMP_PATH, MOUNT_POINT_RANDOM_1, result)); + BOOST_REQUIRE(hasSameMountPoint(TEST_PATH, MOUNT_POINT_1, result)); BOOST_CHECK_EQUAL(result, true); - BOOST_REQUIRE(mountRun(MOUNT_POINT_RANDOM_1)); - BOOST_REQUIRE(isMountPoint(MOUNT_POINT_RANDOM_1, result)); + BOOST_REQUIRE(mountRun(MOUNT_POINT_1)); + BOOST_REQUIRE(isMountPoint(MOUNT_POINT_1, result)); BOOST_CHECK_EQUAL(result, true); - BOOST_REQUIRE(hasSameMountPoint(TMP_PATH, MOUNT_POINT_RANDOM_1, result)); + BOOST_REQUIRE(hasSameMountPoint(TEST_PATH, MOUNT_POINT_1, result)); BOOST_CHECK_EQUAL(result, false); - BOOST_REQUIRE(umount(MOUNT_POINT_RANDOM_1)); - BOOST_REQUIRE(fs::remove(MOUNT_POINT_RANDOM_1, ec)); + BOOST_REQUIRE(umount(MOUNT_POINT_1)); + BOOST_REQUIRE(fs::remove(MOUNT_POINT_1, ec)); } BOOST_AUTO_TEST_CASE(MoveFileTest) @@ -126,32 +122,32 @@ BOOST_AUTO_TEST_CASE(MoveFileTest) std::string src, dst; // same mount point - src = TMP_PATH + "/" + FILE_NAME_RANDOM_1; - dst = TMP_PATH + "/" + FILE_NAME_RANDOM_2; + src = TEST_PATH + "/" + FILE_NAME_1; + dst = TEST_PATH + "/" + FILE_NAME_2; - BOOST_REQUIRE(saveFileContent(src, FILE_CONTENT)); + BOOST_REQUIRE(saveFileContent(src, REFERENCE_FILE_CONTENT)); BOOST_CHECK(moveFile(src, dst)); BOOST_CHECK(!fs::exists(src)); - BOOST_CHECK_EQUAL(readFileContent(dst), FILE_CONTENT); + BOOST_CHECK_EQUAL(readFileContent(dst), REFERENCE_FILE_CONTENT); BOOST_REQUIRE(fs::remove(dst)); // different mount point - src = TMP_PATH + "/" + FILE_NAME_RANDOM_1; - dst = MOUNT_POINT_RANDOM_2 + "/" + FILE_NAME_RANDOM_2; + src = TEST_PATH + "/" + FILE_NAME_1; + dst = MOUNT_POINT_2 + "/" + FILE_NAME_2; - BOOST_REQUIRE(fs::create_directory(MOUNT_POINT_RANDOM_2, ec)); - BOOST_REQUIRE(mountRun(MOUNT_POINT_RANDOM_2)); - BOOST_REQUIRE(saveFileContent(src, FILE_CONTENT)); + BOOST_REQUIRE(fs::create_directory(MOUNT_POINT_2, ec)); + BOOST_REQUIRE(mountRun(MOUNT_POINT_2)); + BOOST_REQUIRE(saveFileContent(src, REFERENCE_FILE_CONTENT)); BOOST_CHECK(moveFile(src, dst)); BOOST_CHECK(!fs::exists(src)); - BOOST_CHECK_EQUAL(readFileContent(dst), FILE_CONTENT); + BOOST_CHECK_EQUAL(readFileContent(dst), REFERENCE_FILE_CONTENT); BOOST_REQUIRE(fs::remove(dst)); - BOOST_REQUIRE(umount(MOUNT_POINT_RANDOM_2)); - BOOST_REQUIRE(fs::remove(MOUNT_POINT_RANDOM_2, ec)); + BOOST_REQUIRE(umount(MOUNT_POINT_2)); + BOOST_REQUIRE(fs::remove(MOUNT_POINT_2, ec)); } BOOST_AUTO_TEST_CASE(CopyDirContentsTest) @@ -160,24 +156,24 @@ BOOST_AUTO_TEST_CASE(CopyDirContentsTest) std::string src, src_inner, src_inner2, dst, dst_inner, dst_inner2; boost::system::error_code ec; - src = TMP_PATH + "/" + FILE_DIR_RANDOM_1; - src_inner = src + "/" + FILE_DIR_RANDOM_3; - src_inner2 = src + "/" + FILE_DIR_RANDOM_4; + src = TEST_PATH + "/" + FILE_DIR_1; + src_inner = src + "/" + FILE_DIR_3; + src_inner2 = src + "/" + FILE_DIR_4; - dst = TMP_PATH + "/" + FILE_DIR_RANDOM_2; - dst_inner = dst + "/" + FILE_DIR_RANDOM_3; - dst_inner2 = dst + "/" + FILE_DIR_RANDOM_4; + dst = TEST_PATH + "/" + FILE_DIR_2; + dst_inner = dst + "/" + FILE_DIR_3; + dst_inner2 = dst + "/" + FILE_DIR_4; // template dir structure: // |-src - // |-FILE_NAME_RANDOM_1 - // |-FILE_NAME_RANDOM_2 + // |-FILE_NAME_1 + // |-FILE_NAME_2 // |-src_inner (rw directory) - // | |-FILE_NAME_RANDOM_1 + // | |-FILE_NAME_1 // | // |-src_inner2 (ro directory) - // |-FILE_NAME_RANDOM_1 - // |-FILE_NAME_RANDOM_2 + // |-FILE_NAME_1 + // |-FILE_NAME_2 // create entire structure with files BOOST_REQUIRE(fs::create_directory(src, ec)); @@ -187,11 +183,11 @@ BOOST_AUTO_TEST_CASE(CopyDirContentsTest) BOOST_REQUIRE(fs::create_directory(src_inner2, ec)); BOOST_REQUIRE(ec.value() == 0); - BOOST_REQUIRE(saveFileContent(src + "/" + FILE_NAME_RANDOM_1, FILE_CONTENT)); - BOOST_REQUIRE(saveFileContent(src + "/" + FILE_NAME_RANDOM_2, FILE_CONTENT_2)); - BOOST_REQUIRE(saveFileContent(src_inner + "/" + FILE_NAME_RANDOM_1, FILE_CONTENT_3)); - BOOST_REQUIRE(saveFileContent(src_inner2 + "/" + FILE_NAME_RANDOM_1, FILE_CONTENT_3)); - BOOST_REQUIRE(saveFileContent(src_inner2 + "/" + FILE_NAME_RANDOM_2, FILE_CONTENT_2)); + BOOST_REQUIRE(saveFileContent(src + "/" + FILE_NAME_1, REFERENCE_FILE_CONTENT)); + BOOST_REQUIRE(saveFileContent(src + "/" + FILE_NAME_2, FILE_CONTENT_2)); + BOOST_REQUIRE(saveFileContent(src_inner + "/" + FILE_NAME_1, FILE_CONTENT_3)); + BOOST_REQUIRE(saveFileContent(src_inner2 + "/" + FILE_NAME_1, FILE_CONTENT_3)); + BOOST_REQUIRE(saveFileContent(src_inner2 + "/" + FILE_NAME_2, FILE_CONTENT_2)); // change permissions of src_inner2 directory fs::permissions(src_inner2, fs::owner_read, ec); @@ -205,19 +201,19 @@ BOOST_AUTO_TEST_CASE(CopyDirContentsTest) BOOST_CHECK(copyDirContents(src, dst)); // check if copy is successful - BOOST_CHECK(fs::exists(dst + "/" + FILE_NAME_RANDOM_1)); - BOOST_CHECK(fs::exists(dst + "/" + FILE_NAME_RANDOM_2)); + BOOST_CHECK(fs::exists(dst + "/" + FILE_NAME_1)); + BOOST_CHECK(fs::exists(dst + "/" + FILE_NAME_2)); BOOST_CHECK(fs::exists(dst_inner)); - BOOST_CHECK(fs::exists(dst_inner + "/" + FILE_NAME_RANDOM_1)); + BOOST_CHECK(fs::exists(dst_inner + "/" + FILE_NAME_1)); BOOST_CHECK(fs::exists(dst_inner2)); - BOOST_CHECK(fs::exists(dst_inner2 + "/" + FILE_NAME_RANDOM_1)); - BOOST_CHECK(fs::exists(dst_inner2 + "/" + FILE_NAME_RANDOM_2)); - - BOOST_CHECK_EQUAL(readFileContent(dst + "/" + FILE_NAME_RANDOM_1), FILE_CONTENT); - BOOST_CHECK_EQUAL(readFileContent(dst + "/" + FILE_NAME_RANDOM_2), FILE_CONTENT_2); - BOOST_CHECK_EQUAL(readFileContent(dst_inner + "/" + FILE_NAME_RANDOM_1), FILE_CONTENT_3); - BOOST_CHECK_EQUAL(readFileContent(dst_inner2 + "/" + FILE_NAME_RANDOM_1), FILE_CONTENT_3); - BOOST_CHECK_EQUAL(readFileContent(dst_inner2 + "/" + FILE_NAME_RANDOM_2), FILE_CONTENT_2); + BOOST_CHECK(fs::exists(dst_inner2 + "/" + FILE_NAME_1)); + BOOST_CHECK(fs::exists(dst_inner2 + "/" + FILE_NAME_2)); + + BOOST_CHECK_EQUAL(readFileContent(dst + "/" + FILE_NAME_1), REFERENCE_FILE_CONTENT); + BOOST_CHECK_EQUAL(readFileContent(dst + "/" + FILE_NAME_2), FILE_CONTENT_2); + BOOST_CHECK_EQUAL(readFileContent(dst_inner + "/" + FILE_NAME_1), FILE_CONTENT_3); + BOOST_CHECK_EQUAL(readFileContent(dst_inner2 + "/" + FILE_NAME_1), FILE_CONTENT_3); + BOOST_CHECK_EQUAL(readFileContent(dst_inner2 + "/" + FILE_NAME_2), FILE_CONTENT_2); fs::file_status st = fs::status(fs::path(dst_inner2)); BOOST_CHECK(fs::owner_read == st.permissions()); -- 2.7.4 From 61a908d7f44dca36a5e6759e786c2d86abec33c1 Mon Sep 17 00:00:00 2001 From: Lukasz Kostyra Date: Thu, 5 Feb 2015 08:57:28 +0100 Subject: [PATCH 12/16] Add systemd socket support [Feature] Systemd unit files for Vasum socket [Cause] IPC works with Vasum socket [Solution] Add required systemd unit files [Verification] Build, install, run tests Change-Id: I552010681204a61e873d419b430bab8556080345 --- CMakeLists.txt | 1 - common/ipc/internals/utils.cpp | 10 ++-- packaging/vasum.spec | 16 ++++++ server/configs/CMakeLists.txt | 4 +- server/configs/systemd/vasum.service.in | 1 + server/configs/systemd/vasum.socket | 9 +++ tests/CMakeLists.txt | 4 +- tests/unit_tests/CMakeLists.txt | 20 ++++++- tests/unit_tests/ipc/ut-socket.cpp | 51 +++++++++++++++++ .../socket_test_service/configs/CMakeLists.txt | 26 +++++++++ .../configs/systemd/vasum-socket-test.service | 10 ++++ .../configs/systemd/vasum-socket-test.socket | 9 +++ .../unit_tests/socket_test_service/socket-test.cpp | 66 ++++++++++++++++++++++ .../unit_tests/socket_test_service/socket-test.hpp | 39 +++++++++++++ 14 files changed, 257 insertions(+), 9 deletions(-) create mode 100644 server/configs/systemd/vasum.socket create mode 100644 tests/unit_tests/ipc/ut-socket.cpp create mode 100644 tests/unit_tests/socket_test_service/configs/CMakeLists.txt create mode 100644 tests/unit_tests/socket_test_service/configs/systemd/vasum-socket-test.service create mode 100644 tests/unit_tests/socket_test_service/configs/systemd/vasum-socket-test.socket create mode 100644 tests/unit_tests/socket_test_service/socket-test.cpp create mode 100644 tests/unit_tests/socket_test_service/socket-test.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 06a1064..67702a0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -126,7 +126,6 @@ SET(SERVER_FOLDER ${PROJECT_SOURCE_DIR}/server) SET(ZONE_SUPPORT_FOLDER ${PROJECT_SOURCE_DIR}/zone-support) SET(ZONE_DAEMON_FOLDER ${PROJECT_SOURCE_DIR}/zone-daemon) SET(TESTS_FOLDER ${PROJECT_SOURCE_DIR}/tests) -SET(UNIT_TESTS_FOLDER ${TESTS_FOLDER}/unit_tests) SET(CLI_FOLDER ${PROJECT_SOURCE_DIR}/cli) IF(NOT DEFINED SYSCONF_INSTALL_DIR) diff --git a/common/ipc/internals/utils.cpp b/common/ipc/internals/utils.cpp index bd98c1b..cb9c93c 100644 --- a/common/ipc/internals/utils.cpp +++ b/common/ipc/internals/utils.cpp @@ -75,13 +75,15 @@ void waitForEvent(int fd, throw IPCException("Timeout in read"); } + if (fds[0].revents & event) { + // Here Comes the Sun + break; + } + if (fds[0].revents & POLLHUP) { - LOGE("Peer disconnected"); + LOGW("Peer disconnected"); throw IPCException("Peer disconnected"); } - - // Here Comes the Sun - break; } } diff --git a/packaging/vasum.spec b/packaging/vasum.spec index 113348b..db8d6be 100644 --- a/packaging/vasum.spec +++ b/packaging/vasum.spec @@ -48,6 +48,7 @@ between them. A process from inside a zone can request a switch of context %attr(755,root,root) /etc/vasum/lxc-templates/*.sh %config /etc/vasum/templates/*.conf %{_unitdir}/vasum.service +%{_unitdir}/vasum.socket %{_unitdir}/multi-user.target.wants/vasum.service /etc/dbus-1/system.d/org.tizen.vasum.host.conf %dir %{_datadir}/.zones @@ -211,10 +212,23 @@ Requires: boost-test %description tests Unit tests for both: server and client and integration tests. +%post tests +systemctl daemon-reload +systemctl enable vasum-socket-test.socket +systemctl start vasum-socket-test.socket + +%preun tests +systemctl stop vasum-socket-test.socket +systemctl disable vasum-socket-test.socket + +%postun tests +systemctl daemon-reload + %files tests %manifest packaging/vasum-server-tests.manifest %defattr(644,root,root,755) %attr(755,root,root) %{_bindir}/vasum-server-unit-tests +%attr(755,root,root) %{_bindir}/vasum-socket-test %attr(755,root,root) %{script_dir}/vsm_all_tests.py %attr(755,root,root) %{script_dir}/vsm_int_tests.py %attr(755,root,root) %{script_dir}/vsm_launch_test.py @@ -223,3 +237,5 @@ Unit tests for both: server and client and integration tests. %attr(755,root,root) %{_datadir}/vasum/lxc-templates %{python_sitelib}/vsm_integration_tests /etc/dbus-1/system.d/org.tizen.vasum.tests.conf +%{_unitdir}/vasum-socket-test.socket +%{_unitdir}/vasum-socket-test.service diff --git a/server/configs/CMakeLists.txt b/server/configs/CMakeLists.txt index f5f82c5..e34137e 100644 --- a/server/configs/CMakeLists.txt +++ b/server/configs/CMakeLists.txt @@ -49,5 +49,7 @@ INSTALL(PROGRAMS ${admin_CONF} INSTALL(PROGRAMS ${template_CONF} DESTINATION ${VSM_CONFIG_INSTALL_DIR}/templates) -INSTALL(FILES ${CMAKE_BINARY_DIR}/systemd/vasum.service +INSTALL(FILES + ${CMAKE_BINARY_DIR}/systemd/vasum.service + systemd/vasum.socket DESTINATION ${SYSTEMD_UNIT_DIR}) diff --git a/server/configs/systemd/vasum.service.in b/server/configs/systemd/vasum.service.in index 8131ed5..29ebbc8 100644 --- a/server/configs/systemd/vasum.service.in +++ b/server/configs/systemd/vasum.service.in @@ -7,6 +7,7 @@ Type=simple ExecStart=${CMAKE_INSTALL_PREFIX}/bin/vasum-server -r Restart=on-failure ExecReload=/bin/kill -HUP $MAINPID +Sockets=vasum.socket [Install] WantedBy=multi-user.target diff --git a/server/configs/systemd/vasum.socket b/server/configs/systemd/vasum.socket new file mode 100644 index 0000000..792935d --- /dev/null +++ b/server/configs/systemd/vasum.socket @@ -0,0 +1,9 @@ +[Socket] +ListenStream=/run/vasum.socket +SocketMode=0755 +SmackLabelIPIn=* +SmackLabelIPOut=@ +Service=vasum.service + +[Install] +WantedBy=sockets.target diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 60214f9..7b7434b 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -17,7 +17,9 @@ # @author Lukasz Kostyra (l.kostyra@samsung.com) # +SET(UNIT_TESTS_FOLDER ${TESTS_FOLDER}/unit_tests) +SET(SOCKET_TEST_FOLDER ${UNIT_TESTS_FOLDER}/socket_test_service) + ADD_SUBDIRECTORY(scripts) ADD_SUBDIRECTORY(integration_tests) ADD_SUBDIRECTORY(unit_tests) - diff --git a/tests/unit_tests/CMakeLists.txt b/tests/unit_tests/CMakeLists.txt index 96ab943..fc96586 100644 --- a/tests/unit_tests/CMakeLists.txt +++ b/tests/unit_tests/CMakeLists.txt @@ -23,25 +23,34 @@ FILE(GLOB_RECURSE project_SRCS *.cpp *.hpp) FILE(GLOB_RECURSE common_SRCS ${COMMON_FOLDER}/*.cpp ${COMMON_FOLDER}/*.hpp) FILE(GLOB server_SRCS ${SERVER_FOLDER}/*.cpp ${SERVER_FOLDER}/*.hpp) FILE(GLOB client_SRCS ${CLIENT_FOLDER}/*.cpp ${CLIENT_FOLDER}/*.h) +FILE(GLOB socket_test_SRCS ${SOCKET_TEST_FOLDER}/*.cpp ${SOCKET_TEST_FOLDER}/*.hpp) FILE(GLOB main_SRC ${SERVER_FOLDER}/main.cpp) LIST(REMOVE_ITEM server_SRCS ${main_SRC}) +# We must compile socket-test separately, exclude it from unit-test build +LIST(REMOVE_ITEM project_SRCS ${socket_test_SRCS}) + ## Setup target ################################################################ SET(UT_SERVER_CODENAME "${PROJECT_NAME}-server-unit-tests") +SET(SOCKET_TEST_CODENAME "${PROJECT_NAME}-socket-test") ADD_EXECUTABLE(${UT_SERVER_CODENAME} ${project_SRCS} ${common_SRCS} ${server_SRCS} ${client_SRCS}) ## A fake target to test vasum-client C API ADD_EXECUTABLE("vasum-client-c-api-compile-test" client/client-c-api-compile-test.c) +## A stub mini-service to test socket functionality +ADD_EXECUTABLE(${SOCKET_TEST_CODENAME} ${socket_test_SRCS} ${common_SRCS}) + ## Link libraries ############################################################## FIND_PACKAGE (Boost COMPONENTS unit_test_framework system filesystem regex) PKG_CHECK_MODULES(UT_SERVER_DEPS REQUIRED lxc json gio-2.0 libsystemd-daemon libsystemd-journal libcap-ng libLogger libSimpleDbus libConfig) -INCLUDE_DIRECTORIES(${COMMON_FOLDER} ${SERVER_FOLDER} ${UNIT_TESTS_FOLDER} ${CLIENT_FOLDER}) +INCLUDE_DIRECTORIES(${COMMON_FOLDER} ${SERVER_FOLDER} ${UNIT_TESTS_FOLDER} ${CLIENT_FOLDER} + ${SOCKET_TEST_FOLDER}) INCLUDE_DIRECTORIES(SYSTEM ${UT_SERVER_DEPS_INCLUDE_DIRS} ${Boost_INCLUDE_DIRS}) SET_TARGET_PROPERTIES(${UT_SERVER_CODENAME} PROPERTIES @@ -49,8 +58,13 @@ SET_TARGET_PROPERTIES(${UT_SERVER_CODENAME} PROPERTIES LINK_FLAGS "-pthread" ) -TARGET_LINK_LIBRARIES(${UT_SERVER_CODENAME} ${UT_SERVER_DEPS_LIBRARIES} ${Boost_LIBRARIES}) +SET_TARGET_PROPERTIES(${SOCKET_TEST_CODENAME} PROPERTIES + COMPILE_FLAGS "-pthread" + LINK_FLAGS "-pthread" +) +TARGET_LINK_LIBRARIES(${UT_SERVER_CODENAME} ${UT_SERVER_DEPS_LIBRARIES} ${Boost_LIBRARIES}) +TARGET_LINK_LIBRARIES(${SOCKET_TEST_CODENAME} ${UT_SERVER_DEPS_LIBRARIES} ${Boost_LIBRARIES}) ## Subdirectories ############################################################## SET(VSM_TEST_CONFIG_INSTALL_DIR ${VSM_DATA_INSTALL_DIR}/tests) @@ -63,7 +77,9 @@ ADD_SUBDIRECTORY(server/configs) ADD_SUBDIRECTORY(utils/configs) ADD_SUBDIRECTORY(client/configs) ADD_SUBDIRECTORY(lxc/templates) +ADD_SUBDIRECTORY(socket_test_service/configs) ## Install ##################################################################### INSTALL(TARGETS ${UT_SERVER_CODENAME} DESTINATION bin) +INSTALL(TARGETS ${SOCKET_TEST_CODENAME} DESTINATION bin) diff --git a/tests/unit_tests/ipc/ut-socket.cpp b/tests/unit_tests/ipc/ut-socket.cpp new file mode 100644 index 0000000..6f78f90 --- /dev/null +++ b/tests/unit_tests/ipc/ut-socket.cpp @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * Contact: Lukasz Kostyra + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +/** + * @file + * @author Lukasz Kostyra (l.kostyra@samsung.com) + * @brief Socket IPC module tests + */ + +#include "config.hpp" +#include "ut.hpp" + +#include "ipc/internals/socket.hpp" + +#include + +using namespace vasum::ipc; + +BOOST_AUTO_TEST_SUITE(SocketSuite) + +BOOST_AUTO_TEST_CASE(SystemdSocket) +{ + std::string readMessage; + + { + Socket socket = Socket::connectSocket(vasum::socket_test::SOCKET_PATH); + BOOST_REQUIRE_GT(socket.getFD(), -1); + + readMessage.resize(vasum::socket_test::TEST_MESSAGE.size()); + socket.read(&readMessage.front(), readMessage.size()); + } + + BOOST_REQUIRE_EQUAL(readMessage, vasum::socket_test::TEST_MESSAGE); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/tests/unit_tests/socket_test_service/configs/CMakeLists.txt b/tests/unit_tests/socket_test_service/configs/CMakeLists.txt new file mode 100644 index 0000000..17e79b9 --- /dev/null +++ b/tests/unit_tests/socket_test_service/configs/CMakeLists.txt @@ -0,0 +1,26 @@ +# Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# +# @file CMakeLists.txt +# @author Lukasz Kostyra (l.kostyra@samsung.com) +# + +MESSAGE(STATUS "Installing configs for Vasum sycket test service to " ${VSM_TEST_CONFIG_INSTALL_DIR}) + +## Install ##################################################################### +INSTALL(FILES systemd/vasum-socket-test.socket + DESTINATION ${SYSTEMD_UNIT_DIR}) +INSTALL(FILES systemd/vasum-socket-test.service + DESTINATION ${SYSTEMD_UNIT_DIR}) diff --git a/tests/unit_tests/socket_test_service/configs/systemd/vasum-socket-test.service b/tests/unit_tests/socket_test_service/configs/systemd/vasum-socket-test.service new file mode 100644 index 0000000..1d43529 --- /dev/null +++ b/tests/unit_tests/socket_test_service/configs/systemd/vasum-socket-test.service @@ -0,0 +1,10 @@ +[Unit] +Description=Vasum Socket tests mini-service +ConditionVirtualization=no + +[Service] +Type=simple +ExecStart=/usr/bin/vasum-socket-test +Sockets=vasum-socket-test.socket +StartLimitInterval=0 +StartLimitBurst=0 diff --git a/tests/unit_tests/socket_test_service/configs/systemd/vasum-socket-test.socket b/tests/unit_tests/socket_test_service/configs/systemd/vasum-socket-test.socket new file mode 100644 index 0000000..bcaeaa8 --- /dev/null +++ b/tests/unit_tests/socket_test_service/configs/systemd/vasum-socket-test.socket @@ -0,0 +1,9 @@ +[Socket] +ListenStream=/run/vasum-socket-test.socket +SocketMode=0755 +SmackLabelIPIn=* +SmackLabelIPOut=@ +Service=vasum-socket-test.service + +[Install] +WantedBy=sockets.target diff --git a/tests/unit_tests/socket_test_service/socket-test.cpp b/tests/unit_tests/socket_test_service/socket-test.cpp new file mode 100644 index 0000000..609bf87 --- /dev/null +++ b/tests/unit_tests/socket_test_service/socket-test.cpp @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * Contact: Lukasz Kostyra + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +/** + * @file + * @author Lukasz Kostyra (l.kostyra@samsung.com) + * @brief Mini-service for IPC Socket mechanism tests + */ + +#include +#include "socket-test.hpp" + +#include +#include +#include + +#include +#include + +#include +#include + +using namespace vasum::socket_test; +using namespace vasum::ipc; +using namespace logger; + +// NOTE this is a single-usage program, only meant to test vasum::ipc::Socket module. +// It's purpose is to be activated when needed by systemd socket activation mechanism. +int main() +{ + Logger::setLogLevel(LogLevel::TRACE); + Logger::setLogBackend(new SystemdJournalBackend()); + + try { + Socket listeningSocket(Socket::createSocket(SOCKET_PATH)); + if (listeningSocket.getFD() < 0) { + LOGE("Failed to connect to socket!"); + return 1; + } + + std::shared_ptr clientSocket = listeningSocket.accept(); + LOGI("Connected! Emitting message to client."); + clientSocket->write(TEST_MESSAGE.c_str(), TEST_MESSAGE.size()); + LOGI("Message sent through socket! Exiting."); + } catch (const IPCException& e) { + LOGE("IPC exception caught! " << e.what()); + return 1; + } + + return 0; +} diff --git a/tests/unit_tests/socket_test_service/socket-test.hpp b/tests/unit_tests/socket_test_service/socket-test.hpp new file mode 100644 index 0000000..f7a292e --- /dev/null +++ b/tests/unit_tests/socket_test_service/socket-test.hpp @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * Contact: Lukasz Kostyra + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +/** + * @file + * @author Lukasz Kostyra (l.kostyra@samsung.com) + * @brief Mini-service for IPC Socket mechanism tests + */ + +#ifndef TESTS_SOCKET_TEST_SERVICE_HPP +#define TESTS_SOCKET_TEST_SERVICE_HPP + +#include + +namespace vasum { +namespace socket_test { + +const std::string SOCKET_PATH = "/run/vasum-socket-test.socket"; +const std::string TEST_MESSAGE = "Some great messages, ey!"; + +} // namespace socket_test +} // namespace vasum + +#endif // TESTS_SOCKET_TEST_SERVICE_HPP -- 2.7.4 From 3a22b40dee63c508cd6d98911e5b6f1771cc10c2 Mon Sep 17 00:00:00 2001 From: Piotr Bartosiewicz Date: Thu, 26 Feb 2015 16:30:11 +0100 Subject: [PATCH 13/16] Enable cpuQuota options, fix cpuQuota logic [Bug/Feature] Options were disabled after migration from libvirt [Cause] N/A [Solution] N/A [Verification] Run tests, run two containers use 100% cpu on first and switch to second and check total cpu usage in host. Change-Id: I6c79f639f7cf0def3ad0ea73550940d8f5edba9e --- common/lxc/cgroup.cpp | 26 ++++++++++- common/lxc/cgroup.hpp | 6 +++ common/utils/fs.cpp | 16 +++++++ common/utils/fs.hpp | 6 +++ server/zone-admin.cpp | 75 ++++++++++--------------------- server/zone.cpp | 12 +++-- server/zones-manager.cpp | 17 ++++--- tests/unit_tests/server/ut-zone-admin.cpp | 26 ++++++----- 8 files changed, 109 insertions(+), 75 deletions(-) diff --git a/common/lxc/cgroup.cpp b/common/lxc/cgroup.cpp index 62f3184..0ec6da2 100644 --- a/common/lxc/cgroup.cpp +++ b/common/lxc/cgroup.cpp @@ -27,6 +27,7 @@ #include "lxc/cgroup.hpp" #include "logger/logger.hpp" #include "utils/fs.hpp" +#include "utils/paths.hpp" #include #include @@ -54,17 +55,38 @@ std::string flagsToPermissions(bool grant, uint32_t flags) } } +std::string getCgroupPath(const std::string& zoneName, + const std::string& cgroupController, + const std::string& cgroupName) +{ + return utils::createFilePath("/sys/fs/cgroup", + cgroupController, + "lxc", + zoneName, + cgroupName); +} + } // namespace bool setCgroup(const std::string& zoneName, + const std::string& cgroupController, const std::string& cgroupName, const std::string& value) { - const std::string path = "/sys/fs/cgroup/devices/lxc/" + zoneName + "/" + cgroupName; + const std::string path = getCgroupPath(zoneName, cgroupController, cgroupName); LOGD("Set '" << value << "' to " << path); return utils::saveFileContent(path, value); } +bool getCgroup(const std::string& zoneName, + const std::string& cgroupController, + const std::string& cgroupName, + std::string& value) +{ + const std::string path = getCgroupPath(zoneName, cgroupController, cgroupName); + return utils::readFirstLineOfFile(path, value); +} + bool isDevice(const std::string& device) { struct stat devStat; @@ -113,7 +135,7 @@ bool setDeviceAccess(const std::string& zoneName, snprintf(value, sizeof(value), "%c %u:%u %s", type, major, minor, perm.c_str()); std::string name = grant ? "devices.allow" : "devices.deny"; - return setCgroup(zoneName, name, value); + return setCgroup(zoneName, "devices", name, value); } diff --git a/common/lxc/cgroup.hpp b/common/lxc/cgroup.hpp index 2592054..23f0e9b 100644 --- a/common/lxc/cgroup.hpp +++ b/common/lxc/cgroup.hpp @@ -31,9 +31,15 @@ namespace vasum { namespace lxc { bool setCgroup(const std::string& zoneName, + const std::string& cgroupController, const std::string& cgroupName, const std::string& value); +bool getCgroup(const std::string& zoneName, + const std::string& cgroupController, + const std::string& cgroupName, + std::string& value); + bool isDevice(const std::string& device); bool setDeviceAccess(const std::string& zoneName, diff --git a/common/utils/fs.cpp b/common/utils/fs.cpp index d7ae2dd..e3a59b3 100644 --- a/common/utils/fs.cpp +++ b/common/utils/fs.cpp @@ -101,6 +101,22 @@ bool saveFileContent(const std::string& path, const std::string& content) return true; } +bool readFirstLineOfFile(const std::string& path, std::string& ret) +{ + std::ifstream file(path); + if (!file) { + LOGD(path << ": could not open for reading"); + return false; + } + + std::getline(file, ret); + if (!file) { + LOGD(path << ": read error"); + return false; + } + return true; +} + bool removeFile(const std::string& path) { LOGD(path << ": exists, removing."); diff --git a/common/utils/fs.hpp b/common/utils/fs.hpp index b00f95a..b2e05b6 100644 --- a/common/utils/fs.hpp +++ b/common/utils/fs.hpp @@ -50,6 +50,12 @@ bool readFileContent(const std::string& path, std::string& content); bool saveFileContent(const std::string& path, const std::string& content); /** + * Read a line from file + * Its goal is to read a kernel config files (eg. from /proc, /sys/) + */ +bool readFirstLineOfFile(const std::string& path, std::string& ret); + +/** * Remove file */ bool removeFile(const std::string& path); diff --git a/server/zone-admin.cpp b/server/zone-admin.cpp index fa465bc..c5e994d 100644 --- a/server/zone-admin.cpp +++ b/server/zone-admin.cpp @@ -30,8 +30,10 @@ #include "logger/logger.hpp" #include "utils/paths.hpp" #include "utils/c-array.hpp" +#include "lxc/cgroup.hpp" #include +#include namespace vasum { @@ -210,6 +212,8 @@ bool ZoneAdmin::isPaused() void ZoneAdmin::setSchedulerLevel(SchedulerLevel sched) { + assert(isRunning()); + switch (sched) { case SchedulerLevel::FOREGROUND: LOGD(mId << ": Setting SchedulerLevel::FOREGROUND"); @@ -229,27 +233,21 @@ void ZoneAdmin::setSchedulerLevel(SchedulerLevel sched) } -void ZoneAdmin::setSchedulerParams(std::uint64_t, std::uint64_t, std::int64_t) -//void ZoneAdmin::setSchedulerParams(std::uint64_t cpuShares, std::uint64_t vcpuPeriod, std::int64_t vcpuQuota) +void ZoneAdmin::setSchedulerParams(std::uint64_t cpuShares, + std::uint64_t vcpuPeriod, + std::int64_t vcpuQuota) { -// assert(mZone); -// -// int maxParams = 3; -// int numParamsBuff = 0; -// -// std::unique_ptr params(new virTypedParameter[maxParams]); -// -// virTypedParameterPtr paramsTmp = params.get(); -// -// virTypedParamsAddULLong(¶msTmp, &numParamsBuff, &maxParams, VIR_DOMAIN_SCHEDULER_CPU_SHARES, cpuShares); -// virTypedParamsAddULLong(¶msTmp, &numParamsBuff, &maxParams, VIR_DOMAIN_SCHEDULER_VCPU_PERIOD, vcpuPeriod); -// virTypedParamsAddLLong(¶msTmp, &numParamsBuff, &maxParams, VIR_DOMAIN_SCHEDULER_VCPU_QUOTA, vcpuQuota); -// -// if (virDomainSetSchedulerParameters(mZone.get(), params.get(), numParamsBuff) < 0) { -// LOGE(mId << ": Error while setting the zone's scheduler params:\n" -// << libvirt::libvirtFormatError()); -// throw ZoneOperationException(); -// } + assert(vcpuPeriod >= 1000 && vcpuPeriod <= 1000000); + assert(vcpuQuota == -1 || + (vcpuQuota >= 1000 && vcpuQuota <= static_cast(ULLONG_MAX / 1000))); + + if (!lxc::setCgroup(mId, "cpu", "cpu.shares", std::to_string(cpuShares)) || + !lxc::setCgroup(mId, "cpu", "cpu.cfs_period_us", std::to_string(vcpuPeriod)) || + !lxc::setCgroup(mId, "cpu", "cpu.cfs_quota_us", std::to_string(vcpuQuota))) { + + LOGE(mId << ": Error while setting the zone's scheduler params"); + throw ZoneOperationException("Could not set scheduler params"); + } } void ZoneAdmin::setDetachOnExit() @@ -264,37 +262,12 @@ void ZoneAdmin::setDestroyOnExit() std::int64_t ZoneAdmin::getSchedulerQuota() { -// assert(mZone); -// -// int numParamsBuff; -// std::unique_ptr type(virDomainGetSchedulerType(mZone.get(), &numParamsBuff), free); -// -// if (type == NULL || numParamsBuff <= 0 || strcmp(type.get(), "posix") != 0) { -// LOGE(mId << ": Error while getting the zone's scheduler type:\n" -// << libvirt::libvirtFormatError()); -// throw ZoneOperationException(); -// } -// -// std::unique_ptr params(new virTypedParameter[numParamsBuff]); -// -// if (virDomainGetSchedulerParameters(mZone.get(), params.get(), &numParamsBuff) < 0) { -// LOGE(mId << ": Error while getting the zone's scheduler params:\n" -// << libvirt::libvirtFormatError()); -// throw ZoneOperationException(); -// } -// -// long long quota; -// if (virTypedParamsGetLLong(params.get(), -// numParamsBuff, -// VIR_DOMAIN_SCHEDULER_VCPU_QUOTA, -// "a) <= 0) { -// LOGE(mId << ": Error while getting the zone's scheduler quota param:\n" -// << libvirt::libvirtFormatError()); -// throw ZoneOperationException(); -// } -// -// return quota; - return 0; + std::string ret; + if (!lxc::getCgroup(mId, "cpu", "cpu.cfs_quota_us", ret)) { + LOGE(mId << ": Error while getting the zone's scheduler quota param"); + throw ZoneOperationException("Could not get scheduler quota param"); + } + return std::stoll(ret); } void ZoneAdmin::createNetdevVeth(const std::string& /* zoneDev */, diff --git a/server/zone.cpp b/server/zone.cpp index 5c15f21..0607fda 100644 --- a/server/zone.cpp +++ b/server/zone.cpp @@ -125,19 +125,23 @@ void Zone::start() if (mConfig.enableDbusIntegration) { mConnectionTransport.reset(new ZoneConnectionTransport(mRunMountPoint)); } + mAdmin->start(); if (mConfig.enableDbusIntegration) { + // Increase cpu quota before connect, otherwise it'd take ages. + goForeground(); connect(); } - - // Send to the background only after we're connected, otherwise it'd take ages. - LOGD(getId() << ": sending to the background"); - goBackground(); + // refocus in ZonesManager will adjust cpu quota after all } void Zone::stop() { Lock lock(mReconnectMutex); + if (mAdmin->isRunning()) { + // boost stopping + goForeground(); + } disconnect(); mAdmin->stop(); mConnectionTransport.reset(); diff --git a/server/zones-manager.cpp b/server/zones-manager.cpp index fd8501f..5f0dca4 100644 --- a/server/zones-manager.cpp +++ b/server/zones-manager.cpp @@ -392,13 +392,15 @@ void ZonesManager::focusInternal(Zones::iterator iter) } for (auto& zone : mZones) { - std::string id = zone->getId(); - if (id == idToFocus) { - LOGD(id << ": being sent to foreground"); - zone->goForeground(); - } else { - LOGD(id << ": being sent to background"); - zone->goBackground(); + if (zone->isRunning()) { + std::string id = zone->getId(); + if (id == idToFocus) { + LOGD(id << ": being sent to foreground"); + zone->goForeground(); + } else { + LOGD(id << ": being sent to background"); + zone->goBackground(); + } } } mActiveZoneId = idToFocus; @@ -1245,6 +1247,7 @@ void ZonesManager::handleLockZoneCall(const std::string& id, LOGT("Lock zone"); try { + zone.goBackground();// make sure it will be in background after unlock zone.suspend(); refocus(); } catch (ZoneOperationException& e) { diff --git a/tests/unit_tests/server/ut-zone-admin.cpp b/tests/unit_tests/server/ut-zone-admin.cpp index 255e75e..4dd08db 100644 --- a/tests/unit_tests/server/ut-zone-admin.cpp +++ b/tests/unit_tests/server/ut-zone-admin.cpp @@ -156,16 +156,20 @@ BOOST_AUTO_TEST_CASE(SuspendResumeTest) BOOST_CHECK(admin->isRunning()); } -//BOOST_AUTO_TEST_CASE(SchedulerLevelTest) -//{ -// auto admin = create(TEST_CONFIG_PATH); -// -// admin->start(); -// ensureStarted(); -// admin->setSchedulerLevel(SchedulerLevel::FOREGROUND); -// BOOST_REQUIRE(admin->getSchedulerQuota() == config.cpuQuotaForeground); -// admin->setSchedulerLevel(SchedulerLevel::BACKGROUND); -// BOOST_REQUIRE(admin->getSchedulerQuota() == config.cpuQuotaBackground); -//} +BOOST_AUTO_TEST_CASE(SchedulerLevelTest) +{ + BOOST_REQUIRE(mConfig.cpuQuotaForeground != mConfig.cpuQuotaBackground); + + auto admin = create(TEST_CONFIG_PATH); + + admin->start(); + ensureStarted(); + + admin->setSchedulerLevel(SchedulerLevel::FOREGROUND); + BOOST_CHECK_EQUAL(admin->getSchedulerQuota(), mConfig.cpuQuotaForeground); + + admin->setSchedulerLevel(SchedulerLevel::BACKGROUND); + BOOST_CHECK_EQUAL(admin->getSchedulerQuota(), mConfig.cpuQuotaBackground); +} BOOST_AUTO_TEST_SUITE_END() -- 2.7.4 From 633f086ac82e192354b061ffed1682f4fd1d2a1e Mon Sep 17 00:00:00 2001 From: Piotr Bartosiewicz Date: Mon, 23 Feb 2015 18:03:32 +0100 Subject: [PATCH 14/16] Epoll wrapper, epoll dispatchers (glib and threaded) [Bug/Feature] N/A [Cause] N/A [Solution] Epoll is the only way, using no additional threads, to aggregate descriptors to one epoll descriptor. [Verification] Run tests Change-Id: I3863129a8b947c467615b2e9d352fce3bd1cda9a --- common/ipc/client.cpp | 2 +- common/ipc/internals/acceptor.cpp | 2 +- common/ipc/internals/event-queue.hpp | 4 +- common/ipc/internals/processor.cpp | 10 +- common/ipc/internals/request-queue.hpp | 4 +- common/ipc/internals/socket.cpp | 18 +- common/ipc/service.cpp | 2 +- common/utils/event-poll.cpp | 151 +++++++++++++++ common/utils/event-poll.hpp | 68 +++++++ common/{ipc/internals => utils}/eventfd.cpp | 26 ++- common/{ipc/internals => utils}/eventfd.hpp | 11 +- .../internals/utils.cpp => utils/fd-utils.cpp} | 76 ++++---- .../internals/utils.hpp => utils/fd-utils.hpp} | 13 +- common/utils/glib-poll-dispatcher.cpp | 61 ++++++ common/utils/glib-poll-dispatcher.hpp | 53 ++++++ common/utils/thread-poll-dispatcher.cpp | 53 ++++++ common/utils/thread-poll-dispatcher.hpp | 52 ++++++ tests/unit_tests/ipc/ut-ipc.cpp | 2 - tests/unit_tests/utils/ut-event-poll.cpp | 205 +++++++++++++++++++++ 19 files changed, 726 insertions(+), 87 deletions(-) create mode 100644 common/utils/event-poll.cpp create mode 100644 common/utils/event-poll.hpp rename common/{ipc/internals => utils}/eventfd.cpp (67%) rename common/{ipc/internals => utils}/eventfd.hpp (88%) rename common/{ipc/internals/utils.cpp => utils/fd-utils.cpp} (68%) rename common/{ipc/internals/utils.hpp => utils/fd-utils.hpp} (90%) create mode 100644 common/utils/glib-poll-dispatcher.cpp create mode 100644 common/utils/glib-poll-dispatcher.hpp create mode 100644 common/utils/thread-poll-dispatcher.cpp create mode 100644 common/utils/thread-poll-dispatcher.hpp create mode 100644 tests/unit_tests/utils/ut-event-poll.cpp diff --git a/common/ipc/client.cpp b/common/ipc/client.cpp index 51e59f8..6669d8a 100644 --- a/common/ipc/client.cpp +++ b/common/ipc/client.cpp @@ -45,7 +45,7 @@ Client::~Client() LOGS("Client Destructor"); try { stop(); - } catch (IPCException& e) { + } catch (std::exception& e) { LOGE("Error in Client's destructor: " << e.what()); } } diff --git a/common/ipc/internals/acceptor.cpp b/common/ipc/internals/acceptor.cpp index 627e1fe..ecb2210 100644 --- a/common/ipc/internals/acceptor.cpp +++ b/common/ipc/internals/acceptor.cpp @@ -49,7 +49,7 @@ Acceptor::~Acceptor() LOGT("Destroying Acceptor"); try { stop(); - } catch (IPCException& e) { + } catch (std::exception& e) { LOGE("Error in destructor: " << e.what()); } LOGT("Destroyed Acceptor"); diff --git a/common/ipc/internals/event-queue.hpp b/common/ipc/internals/event-queue.hpp index 2c591f7..b4532fd 100644 --- a/common/ipc/internals/event-queue.hpp +++ b/common/ipc/internals/event-queue.hpp @@ -26,7 +26,7 @@ #define COMMON_IPC_INTERNALS_EVENT_QUEUE_HPP #include "ipc/exception.hpp" -#include "ipc/internals/eventfd.hpp" +#include "utils/eventfd.hpp" #include "logger/logger.hpp" #include @@ -82,7 +82,7 @@ private: std::mutex mCommunicationMutex; std::queue mMessages; - EventFD mEventFD; + utils::EventFD mEventFD; }; template diff --git a/common/ipc/internals/processor.cpp b/common/ipc/internals/processor.cpp index 79c1a22..93f721f 100644 --- a/common/ipc/internals/processor.cpp +++ b/common/ipc/internals/processor.cpp @@ -26,8 +26,8 @@ #include "ipc/exception.hpp" #include "ipc/internals/processor.hpp" -#include "ipc/internals/utils.hpp" #include "utils/signal.hpp" +#include "utils/exception.hpp" #include #include @@ -79,21 +79,21 @@ Processor::~Processor() LOGS(mLogPrefix + "Processor Destructor"); try { stop(); - } catch (IPCException& e) { + } catch (std::exception& e) { LOGE(mLogPrefix + "Error in Processor's destructor: " << e.what()); } } Processor::Peers::iterator Processor::getPeerInfoIterator(const FileDescriptor fd) { - return std::find_if(mPeerInfo.begin(), mPeerInfo.end(), [&fd](const PeerInfo & peerInfo) { + return std::find_if(mPeerInfo.begin(), mPeerInfo.end(), [fd](const PeerInfo & peerInfo) { return fd == peerInfo.socketPtr->getFD(); }); } Processor::Peers::iterator Processor::getPeerInfoIterator(const PeerID peerID) { - return std::find_if(mPeerInfo.begin(), mPeerInfo.end(), [&peerID](const PeerInfo & peerInfo) { + return std::find_if(mPeerInfo.begin(), mPeerInfo.end(), [peerID](const PeerInfo & peerInfo) { return peerID == peerInfo.peerID; }); } @@ -411,7 +411,7 @@ bool Processor::handleInput(const FileDescriptor fd) Socket::Guard guard = socket.getGuard(); socket.read(&methodID, sizeof(methodID)); socket.read(&messageID, sizeof(messageID)); - } catch (const IPCException& e) { + } catch (const UtilsException& e) { LOGE(mLogPrefix + "Error during reading the socket"); removePeerInternal(peerIt, std::make_exception_ptr(IPCNaughtyPeerException())); diff --git a/common/ipc/internals/request-queue.hpp b/common/ipc/internals/request-queue.hpp index e1ad46b..44306ee 100644 --- a/common/ipc/internals/request-queue.hpp +++ b/common/ipc/internals/request-queue.hpp @@ -26,7 +26,7 @@ #define COMMON_IPC_INTERNALS_MESSAGE_QUEUE_HPP #include "ipc/exception.hpp" -#include "ipc/internals/eventfd.hpp" +#include "utils/eventfd.hpp" #include "logger/logger.hpp" #include @@ -115,7 +115,7 @@ private: std::list mRequests; std::mutex mStateMutex; - EventFD mEventFD; + utils::EventFD mEventFD; }; template diff --git a/common/ipc/internals/socket.cpp b/common/ipc/internals/socket.cpp index 2469af6..a66456e 100644 --- a/common/ipc/internals/socket.cpp +++ b/common/ipc/internals/socket.cpp @@ -26,7 +26,7 @@ #include "ipc/exception.hpp" #include "ipc/internals/socket.hpp" -#include "ipc/internals/utils.hpp" +#include "utils/fd-utils.hpp" #include "logger/logger.hpp" #include @@ -60,8 +60,8 @@ Socket::Socket(Socket&& socket) noexcept Socket::~Socket() noexcept { try { - ipc::close(mFD); - } catch (IPCException& e) { + utils::close(mFD); + } catch (std::exception& e) { LOGE("Error in Socket's destructor: " << e.what()); } } @@ -89,13 +89,13 @@ std::shared_ptr Socket::accept() void Socket::write(const void* bufferPtr, const size_t size) const { Guard guard(mCommunicationMutex); - ipc::write(mFD, bufferPtr, size); + utils::write(mFD, bufferPtr, size); } void Socket::read(void* bufferPtr, const size_t size) const { Guard guard(mCommunicationMutex); - ipc::read(mFD, bufferPtr, size); + utils::read(mFD, bufferPtr, size); } int Socket::getSystemdSocket(const std::string& path) @@ -142,7 +142,7 @@ int Socket::createZoneSocket(const std::string& path) reinterpret_cast(&serverAddress), sizeof(struct sockaddr_un))) { std::string message = strerror(errno); - ::close(sockfd); + utils::close(sockfd); LOGE("Error in bind: " << message); IPCException("Error in bind: " + message); } @@ -150,7 +150,7 @@ int Socket::createZoneSocket(const std::string& path) if (-1 == ::listen(sockfd, MAX_QUEUE_LENGTH)) { std::string message = strerror(errno); - ::close(sockfd); + utils::close(sockfd); LOGE("Error in listen: " << message); IPCException("Error in listen: " + message); } @@ -188,7 +188,7 @@ Socket Socket::connectSocket(const std::string& path) if (-1 == connect(fd, reinterpret_cast(&serverAddress), sizeof(struct sockaddr_un))) { - ::close(fd); + utils::close(fd); LOGE("Error in connect: " + std::string(strerror(errno))); throw IPCException("Error in connect: " + std::string(strerror(errno))); } @@ -196,7 +196,7 @@ Socket Socket::connectSocket(const std::string& path) // Nonblock socket int flags = fcntl(fd, F_GETFL, 0); if (-1 == fcntl(fd, F_SETFL, flags | O_NONBLOCK)) { - ::close(fd); + utils::close(fd); LOGE("Error in fcntl: " + std::string(strerror(errno))); throw IPCException("Error in fcntl: " + std::string(strerror(errno))); } diff --git a/common/ipc/service.cpp b/common/ipc/service.cpp index d945f73..442d804 100644 --- a/common/ipc/service.cpp +++ b/common/ipc/service.cpp @@ -50,7 +50,7 @@ Service::~Service() LOGS("Service Destructor"); try { stop(); - } catch (IPCException& e) { + } catch (std::exception& e) { LOGE("Error in Service's destructor: " << e.what()); } } diff --git a/common/utils/event-poll.cpp b/common/utils/event-poll.cpp new file mode 100644 index 0000000..b37d727 --- /dev/null +++ b/common/utils/event-poll.cpp @@ -0,0 +1,151 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * Contact: Piotr Bartosiewicz + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +/** + * @file + * @author Piotr Bartosiewicz (p.bartosiewi@partner.samsung.com) + * @brief C++ epoll wrapper + */ + +#include "config.hpp" +#include "utils/event-poll.hpp" +#include "utils/fd-utils.hpp" +#include "utils/exception.hpp" +#include "logger/logger.hpp" + +#include +#include +#include +#include + +namespace vasum { +namespace utils { + +EventPoll::EventPoll() + : mPollFD(::epoll_create1(EPOLL_CLOEXEC)) +{ + if (mPollFD == -1) { + LOGE("Failed to create epoll: " << getSystemErrorMessage()); + throw UtilsException("Could not create epoll"); + } +} + +EventPoll::~EventPoll() +{ + if (!mCallbacks.empty()) { + LOGW("Not removed callbacks: " << mCallbacks.size()); + assert(0 && "Not removed callbacks left"); + } + utils::close(mPollFD); +} + +int EventPoll::getPollFD() const +{ + return mPollFD; +} + +void EventPoll::addFD(const int fd, const Events events, Callback&& callback) +{ + std::lock_guard lock(mMutex); + + if (mCallbacks.find(fd) != mCallbacks.end()) { + LOGW("Already added fd: " << fd); + throw UtilsException("FD already added"); + } + + if (!addFDInternal(fd, events)) { + throw UtilsException("Could not add fd"); + } + + mCallbacks.insert({fd, std::make_shared(std::move(callback))}); + LOGT("Callback added for " << fd); +} + +void EventPoll::removeFD(const int fd) +{ + std::lock_guard lock(mMutex); + + auto iter = mCallbacks.find(fd); + if (iter == mCallbacks.end()) { + LOGW("Failed to remove nonexistent fd: " << fd); + throw UtilsException("FD does not exist"); + } + mCallbacks.erase(iter); + removeFDInternal(fd); + LOGT("Callback removed for " << fd); +} + +bool EventPoll::dispatchIteration(const int timeoutMs) +{ + for (;;) { + epoll_event event; + int num = epoll_wait(mPollFD, &event, 1, timeoutMs); + if (num == 0) { + return false; // timeout + } + if (num < 0) { + if (errno == EINTR) { + continue; + } + LOGE("Failed to wait on epoll: " << getSystemErrorMessage()); + throw UtilsException("Could not wait for event"); + } + + // callback could be removed in the meantime, so be careful, find it inside lock + std::lock_guard lock(mMutex); + auto iter = mCallbacks.find(event.data.fd); + if (iter == mCallbacks.end()) { + continue; + } + + // add ref because removeFD(self) can be called inside callback + std::shared_ptr callback(iter->second); + return (*callback)(event.data.fd, event.events); + } +} + +void EventPoll::dispatchLoop() +{ + while (dispatchIteration(-1)) {} +} + +bool EventPoll::addFDInternal(const int fd, const Events events) +{ + epoll_event event; + memset(&event, 0, sizeof(event)); + event.events = events; + event.data.fd = fd; + + if (epoll_ctl(mPollFD, EPOLL_CTL_ADD, fd, &event) == -1) { + LOGE("Failed to add fd to poll: " << getSystemErrorMessage()); + return false; + } + return true; +} + +void EventPoll::removeFDInternal(const int fd) +{ + if (epoll_ctl(mPollFD, EPOLL_CTL_DEL, fd, NULL) == -1) { + assert(errno != EBADF); // always removeFD before closing fd locally! + // this is important because linux will reuse this fd number + LOGE("Failed to remove fd from poll: " << getSystemErrorMessage()); + } +} + +} // namespace utils +} // namespace vasum diff --git a/common/utils/event-poll.hpp b/common/utils/event-poll.hpp new file mode 100644 index 0000000..1a7ae2c --- /dev/null +++ b/common/utils/event-poll.hpp @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * Contact: Piotr Bartosiewicz + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +/** + * @file + * @author Piotr Bartosiewicz (p.bartosiewi@partner.samsung.com) + * @brief C++ epoll wrapper + */ + +#ifndef COMMON_UTILS_EVENT_POLL_HPP +#define COMMON_UTILS_EVENT_POLL_HPP + +#include +#include +#include +#include + +namespace vasum { +namespace utils { + +class EventPoll { +public: + + typedef unsigned int Events; + typedef std::function Callback; + + EventPoll(); + ~EventPoll(); + + int getPollFD() const; + + void addFD(const int fd, const Events events, Callback&& callback); + void removeFD(const int fd); + + bool dispatchIteration(const int timeoutMs); + void dispatchLoop(); + +private: + typedef std::recursive_mutex Mutex; + + const int mPollFD; + Mutex mMutex; + std::unordered_map> mCallbacks; + + bool addFDInternal(const int fd, const Events events); + void removeFDInternal(const int fd); +}; + + +} // namespace utils +} // namespace vasum + +#endif // COMMON_UTILS_EVENT_POLL_HPP diff --git a/common/ipc/internals/eventfd.cpp b/common/utils/eventfd.cpp similarity index 67% rename from common/ipc/internals/eventfd.cpp rename to common/utils/eventfd.cpp index 729243d..2fd8d62 100644 --- a/common/ipc/internals/eventfd.cpp +++ b/common/utils/eventfd.cpp @@ -24,9 +24,9 @@ #include "config.hpp" -#include "ipc/internals/eventfd.hpp" -#include "ipc/internals/utils.hpp" -#include "ipc/exception.hpp" +#include "utils/eventfd.hpp" +#include "utils/exception.hpp" +#include "utils/fd-utils.hpp" #include "logger/logger.hpp" #include @@ -35,24 +35,20 @@ #include namespace vasum { -namespace ipc { +namespace utils { EventFD::EventFD() { - mFD = ::eventfd(0, EFD_SEMAPHORE | EFD_NONBLOCK); + mFD = ::eventfd(0, EFD_SEMAPHORE | EFD_CLOEXEC); if (mFD == -1) { - LOGE("Error in eventfd: " << std::string(strerror(errno))); - throw IPCException("Error in eventfd: " + std::string(strerror(errno))); + LOGE("Error in eventfd: " << getSystemErrorMessage()); + throw UtilsException("Error in eventfd: " + getSystemErrorMessage()); } } EventFD::~EventFD() { - try { - ipc::close(mFD); - } catch (IPCException& e) { - LOGE("Error in Event's destructor: " << e.what()); - } + utils::close(mFD); } int EventFD::getFD() const @@ -63,15 +59,15 @@ int EventFD::getFD() const void EventFD::send() { const std::uint64_t toSend = 1; - ipc::write(mFD, &toSend, sizeof(toSend)); + utils::write(mFD, &toSend, sizeof(toSend)); } void EventFD::receive() { std::uint64_t readBuffer; - ipc::read(mFD, &readBuffer, sizeof(readBuffer)); + utils::read(mFD, &readBuffer, sizeof(readBuffer)); } -} // namespace ipc +} // namespace utils } // namespace vasum diff --git a/common/ipc/internals/eventfd.hpp b/common/utils/eventfd.hpp similarity index 88% rename from common/ipc/internals/eventfd.hpp rename to common/utils/eventfd.hpp index cf3094c..b3d5027 100644 --- a/common/ipc/internals/eventfd.hpp +++ b/common/utils/eventfd.hpp @@ -22,17 +22,18 @@ * @brief Eventfd wrapper */ -#ifndef COMMON_IPC_INTERNALS_EVENTFD_HPP -#define COMMON_IPC_INTERNALS_EVENTFD_HPP +#ifndef COMMON_UTILS_EVENTFD_HPP +#define COMMON_UTILS_EVENTFD_HPP namespace vasum { -namespace ipc { +namespace utils { class EventFD { public: EventFD(); ~EventFD(); + EventFD(const EventFD& eventfd) = delete; EventFD& operator=(const EventFD&) = delete; @@ -56,7 +57,7 @@ private: int mFD; }; -} // namespace ipc +} // namespace utils } // namespace vasum -#endif // COMMON_IPC_INTERNALS_EVENTFD_HPP +#endif // COMMON_UTILS_EVENTFD_HPP diff --git a/common/ipc/internals/utils.cpp b/common/utils/fd-utils.cpp similarity index 68% rename from common/ipc/internals/utils.cpp rename to common/utils/fd-utils.cpp index cb9c93c..59bad36 100644 --- a/common/ipc/internals/utils.cpp +++ b/common/utils/fd-utils.cpp @@ -19,13 +19,13 @@ /** * @file * @author Jan Olszak (j.olszak@samsung.com) - * @brief Utility functions + * @brief File descriptor utility functions */ #include "config.hpp" -#include "ipc/exception.hpp" -#include "ipc/internals/utils.hpp" +#include "utils/fd-utils.hpp" +#include "utils/exception.hpp" #include "logger/logger.hpp" #include @@ -40,7 +40,7 @@ namespace fs = boost::filesystem; namespace chr = std::chrono; namespace vasum { -namespace ipc { +namespace utils { namespace { @@ -51,13 +51,14 @@ void waitForEvent(int fd, // Wait for the rest of the data struct pollfd fds[1]; fds[0].fd = fd; - fds[0].events = event | POLLHUP; + fds[0].events = event; for (;;) { chr::milliseconds timeoutMS = chr::duration_cast(deadline - chr::high_resolution_clock::now()); if (timeoutMS.count() < 0) { - LOGE("Timeout in read"); - throw IPCException("Timeout in read"); + LOGE("Timeout while waiting for event: " << std::hex << event << + " on fd: " << std::dec << fd); + throw UtilsException("Timeout"); } int ret = ::poll(fds, 1 /*fds size*/, timeoutMS.count()); @@ -66,13 +67,13 @@ void waitForEvent(int fd, if (errno == EINTR) { continue; } - LOGE("Error in poll: " + std::string(strerror(errno))); - throw IPCException("Error in poll: " + std::string(strerror(errno))); + LOGE("Error in poll: " + getSystemErrorMessage()); + throw UtilsException("Error in poll: " + getSystemErrorMessage()); } if (ret == 0) { LOGE("Timeout in read"); - throw IPCException("Timeout in read"); + throw UtilsException("Timeout in read"); } if (fds[0].revents & event) { @@ -82,7 +83,7 @@ void waitForEvent(int fd, if (fds[0].revents & POLLHUP) { LOGW("Peer disconnected"); - throw IPCException("Peer disconnected"); + throw UtilsException("Peer disconnected"); } } } @@ -98,11 +99,10 @@ void close(int fd) for (;;) { if (-1 == ::close(fd)) { if (errno == EINTR) { - LOGD("Close interrupted by a signal, retrying"); + LOGT("Close interrupted by a signal, retrying"); continue; } - LOGE("Error in close: " << std::string(strerror(errno))); - throw IPCException("Error in close: " + std::string(strerror(errno))); + LOGE("Error in close: " << getSystemErrorMessage()); } break; } @@ -118,22 +118,21 @@ void write(int fd, const void* bufferPtr, const size_t size, int timeoutMS) int n = ::write(fd, reinterpret_cast(bufferPtr) + nTotal, size - nTotal); - if (n > 0) { + if (n >= 0) { nTotal += n; + if (nTotal == size) { + // All data is written, break loop + break; + } } else if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) { // Neglected errors LOGD("Retrying write"); } else { - LOGE("Error during writing: " + std::string(strerror(errno))); - throw IPCException("Error during writing: " + std::string(strerror(errno))); + LOGE("Error during writing: " + getSystemErrorMessage()); + throw UtilsException("Error during writing: " + getSystemErrorMessage()); } - if (nTotal >= size) { - // All data is written, break loop - break; - } else { - waitForEvent(fd, POLLOUT, deadline); - } + waitForEvent(fd, POLLOUT, deadline); } } @@ -147,22 +146,25 @@ void read(int fd, void* bufferPtr, const size_t size, int timeoutMS) int n = ::read(fd, reinterpret_cast(bufferPtr) + nTotal, size - nTotal); - if (n > 0) { + if (n >= 0) { nTotal += n; + if (nTotal == size) { + // All data is read, break loop + break; + } + if (n == 0) { + LOGW("Peer disconnected"); + throw UtilsException("Peer disconnected"); + } } else if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) { // Neglected errors LOGD("Retrying read"); } else { - LOGE("Error during reading: " + std::string(strerror(errno))); - throw IPCException("Error during reading: " + std::string(strerror(errno))); + LOGE("Error during reading: " + getSystemErrorMessage()); + throw UtilsException("Error during reading: " + getSystemErrorMessage()); } - if (nTotal >= size) { - // All data is read, break loop - break; - } else { - waitForEvent(fd, POLLIN, deadline); - } + waitForEvent(fd, POLLIN, deadline); } } @@ -170,8 +172,8 @@ unsigned int getMaxFDNumber() { struct rlimit rlim; if (-1 == getrlimit(RLIMIT_NOFILE, &rlim)) { - LOGE("Error during getrlimit: " + std::string(strerror(errno))); - throw IPCException("Error during getrlimit: " + std::string(strerror(errno))); + LOGE("Error during getrlimit: " + getSystemErrorMessage()); + throw UtilsException("Error during getrlimit: " + getSystemErrorMessage()); } return rlim.rlim_cur; } @@ -182,8 +184,8 @@ void setMaxFDNumber(unsigned int limit) rlim.rlim_cur = limit; rlim.rlim_max = limit; if (-1 == setrlimit(RLIMIT_NOFILE, &rlim)) { - LOGE("Error during setrlimit: " + std::string(strerror(errno))); - throw IPCException("Error during setrlimit: " + std::string(strerror(errno))); + LOGE("Error during setrlimit: " + getSystemErrorMessage()); + throw UtilsException("Error during setrlimit: " + getSystemErrorMessage()); } } @@ -194,6 +196,6 @@ unsigned int getFDNumber() fs::directory_iterator()); } -} // namespace ipc +} // namespace utils } // namespace vasum diff --git a/common/ipc/internals/utils.hpp b/common/utils/fd-utils.hpp similarity index 90% rename from common/ipc/internals/utils.hpp rename to common/utils/fd-utils.hpp index c3bcaf1..ac32b0a 100644 --- a/common/ipc/internals/utils.hpp +++ b/common/utils/fd-utils.hpp @@ -19,20 +19,19 @@ /** * @file * @author Jan Olszak (j.olszak@samsung.com) - * @brief Utility functions + * @brief File descriptor utility functions */ -#ifndef COMMON_IPC_INTERNALS_UTILS_HPP -#define COMMON_IPC_INTERNALS_UTILS_HPP +#ifndef COMMON_UTILS_FD_HPP +#define COMMON_UTILS_FD_HPP #include namespace vasum { -namespace ipc { +namespace utils { /** * Close the file descriptor. - * Repeat until */ void close(int fd); @@ -73,7 +72,7 @@ void setMaxFDNumber(unsigned int limit); */ unsigned int getFDNumber(); -} // namespace ipc +} // namespace utils } // namespace vasum -#endif // COMMON_IPC_INTERNALS_UTILS_HPP +#endif // COMMON_UTILS_FD_HPP diff --git a/common/utils/glib-poll-dispatcher.cpp b/common/utils/glib-poll-dispatcher.cpp new file mode 100644 index 0000000..5c66d16 --- /dev/null +++ b/common/utils/glib-poll-dispatcher.cpp @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * Contact: Piotr Bartosiewicz + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +/** + * @file + * @author Piotr Bartosiewicz (p.bartosiewi@partner.samsung.com) + * @brief glib epoll dispatcher + */ + +#include "config.hpp" +#include "utils/glib-poll-dispatcher.hpp" +#include "utils/callback-wrapper.hpp" + +namespace vasum { +namespace utils { + +GlibPollDispatcher::GlibPollDispatcher(EventPoll& poll) +{ + mChannel = g_io_channel_unix_new(poll.getPollFD()); + + auto dispatchCallback = [&]() { + poll.dispatchIteration(0); + }; + + auto cCallback = [](GIOChannel*, GIOCondition, gpointer data) -> gboolean { + getCallbackFromPointer(data)(); + return TRUE; + }; + + mWatchId = g_io_add_watch_full(mChannel, + G_PRIORITY_DEFAULT, + G_IO_IN, + cCallback, + createCallbackWrapper(dispatchCallback, mGuard.spawn()), + &deleteCallbackWrapper); +} + +GlibPollDispatcher::~GlibPollDispatcher() +{ + g_source_remove(mWatchId); + g_io_channel_unref(mChannel); + // mGuard destructor will wait for full unregister of dispatchCallback +} + +} // namespace utils +} // namespace vasum diff --git a/common/utils/glib-poll-dispatcher.hpp b/common/utils/glib-poll-dispatcher.hpp new file mode 100644 index 0000000..07da0c3 --- /dev/null +++ b/common/utils/glib-poll-dispatcher.hpp @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * Contact: Piotr Bartosiewicz + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +/** + * @file + * @author Piotr Bartosiewicz (p.bartosiewi@partner.samsung.com) + * @brief glib epoll dispatcher + */ + +#ifndef COMMON_UTILS_GLIB_POLL_DISPATCHER_HPP +#define COMMON_UTILS_GLIB_POLL_DISPATCHER_HPP + +#include "utils/event-poll.hpp" +#include "utils/callback-guard.hpp" + +#include + +namespace vasum { +namespace utils { + +/** + * Will dispatch poll events in glib thread + */ +class GlibPollDispatcher { +public: + GlibPollDispatcher(EventPoll& poll); + ~GlibPollDispatcher(); +private: + CallbackGuard mGuard; + GIOChannel* mChannel; + guint mWatchId; +}; + + +} // namespace utils +} // namespace vasum + +#endif // COMMON_UTILS_GLIB_POLL_DISPATCHER_HPP diff --git a/common/utils/thread-poll-dispatcher.cpp b/common/utils/thread-poll-dispatcher.cpp new file mode 100644 index 0000000..f350587 --- /dev/null +++ b/common/utils/thread-poll-dispatcher.cpp @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * Contact: Piotr Bartosiewicz + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +/** + * @file + * @author Piotr Bartosiewicz (p.bartosiewi@partner.samsung.com) + * @brief Thread epoll dispatcher + */ + +#include "config.hpp" +#include "utils/thread-poll-dispatcher.hpp" + +#include + +namespace vasum { +namespace utils { + +ThreadPollDispatcher::ThreadPollDispatcher(EventPoll& poll) + : mPoll(poll) + , mThread([&]{ poll.dispatchLoop(); }) +{ + auto controlCallback = [this](int, EventPoll::Events) -> bool { + mStopEvent.receive(); + return false; // break the loop + }; + + poll.addFD(mStopEvent.getFD(), EPOLLIN, std::move(controlCallback)); +} + +ThreadPollDispatcher::~ThreadPollDispatcher() +{ + mStopEvent.send(); + mThread.join(); + mPoll.removeFD(mStopEvent.getFD()); +} + +} // namespace utils +} // namespace vasum diff --git a/common/utils/thread-poll-dispatcher.hpp b/common/utils/thread-poll-dispatcher.hpp new file mode 100644 index 0000000..e54cb4e --- /dev/null +++ b/common/utils/thread-poll-dispatcher.hpp @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * Contact: Piotr Bartosiewicz + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +/** + * @file + * @author Piotr Bartosiewicz (p.bartosiewi@partner.samsung.com) + * @brief Thread epoll dispatcher + */ + +#ifndef COMMON_UTILS_THREAD_POLL_DISPATCHER_HPP +#define COMMON_UTILS_THREAD_POLL_DISPATCHER_HPP + +#include "utils/event-poll.hpp" +#include "utils/eventfd.hpp" + +#include + +namespace vasum { +namespace utils { + +/** + * Will dispatch poll events in a newly created thread + */ +class ThreadPollDispatcher { +public: + ThreadPollDispatcher(EventPoll& poll); + ~ThreadPollDispatcher(); +private: + EventPoll& mPoll; + EventFD mStopEvent; + std::thread mThread; +}; + +} // namespace utils +} // namespace vasum + +#endif // COMMON_UTILS_THREAD_POLL_DISPATCHER_HPP diff --git a/tests/unit_tests/ipc/ut-ipc.cpp b/tests/unit_tests/ipc/ut-ipc.cpp index 193eec9..fa0de22 100644 --- a/tests/unit_tests/ipc/ut-ipc.cpp +++ b/tests/unit_tests/ipc/ut-ipc.cpp @@ -592,7 +592,6 @@ BOOST_AUTO_TEST_CASE(ServiceGSource) l.set(); }; - IPCGSource::Pointer serviceGSource; Service s(SOCKET_PATH); s.setMethodHandler(1, echoCallback); @@ -622,7 +621,6 @@ BOOST_AUTO_TEST_CASE(ClientGSource) Service s(SOCKET_PATH); s.start(); - IPCGSource::Pointer clientGSource; Client c(SOCKET_PATH); c.setMethodHandler(1, echoCallback); c.setSignalHandler(2, signalHandler); diff --git a/tests/unit_tests/utils/ut-event-poll.cpp b/tests/unit_tests/utils/ut-event-poll.cpp new file mode 100644 index 0000000..e387393 --- /dev/null +++ b/tests/unit_tests/utils/ut-event-poll.cpp @@ -0,0 +1,205 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * Contact: Piotr Bartosiewicz + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + + +/** + * @file + * @author Piotr Bartosiewicz (p.bartosiewi@partner.samsung.com) + * @brief Unit tests of event poll + */ + +#include "config.hpp" +#include "ut.hpp" + +#include "utils/event-poll.hpp" +#include "logger/logger.hpp" +#include "ipc/internals/socket.hpp" +#include "utils/latch.hpp" +#include "utils/glib-loop.hpp" +#include "utils/glib-poll-dispatcher.hpp" +#include "utils/thread-poll-dispatcher.hpp" + +#include +#include + +using namespace vasum::utils; +using namespace vasum::ipc; + +namespace { + +const int unsigned TIMEOUT = 1000; +#define ADD_EVENT(e) {EPOLL##e, #e} +const std::map EVENT_NAMES = { + ADD_EVENT(IN), + ADD_EVENT(OUT), + ADD_EVENT(ERR), + ADD_EVENT(HUP), + ADD_EVENT(RDHUP), +}; +#undef ADD_EVENT + +std::string strEvents(EventPoll::Events events) +{ + if (events == 0) { + return ""; + } + std::ostringstream ss; + for (const auto& p : EVENT_NAMES) { + if (events & p.first) { + ss << p.second << ", "; + events &= ~p.first; + } + } + if (events != 0) { + ss << std::hex << events; + return ss.str(); + } else { + std::string ret = ss.str(); + ret.resize(ret.size() - 2); + return ret; + } +} + +} // namespace + +BOOST_AUTO_TEST_SUITE(EventPollSuite) + +BOOST_AUTO_TEST_CASE(EmptyPoll) +{ + EventPoll poll; + BOOST_CHECK(!poll.dispatchIteration(0)); +} + +BOOST_AUTO_TEST_CASE(ThreadedPoll) +{ + EventPoll poll; + ThreadPollDispatcher dispatcher(poll); +} + +BOOST_AUTO_TEST_CASE(GlibPoll) +{ + ScopedGlibLoop loop; + + EventPoll poll; + GlibPollDispatcher dispatcher(poll); +} + +void doSocketTest(EventPoll& poll, Latch& goodMessage, Latch& remoteClosed) +{ + const std::string PATH = "/tmp/ut-poll.sock"; + const std::string MESSAGE = "This is a test message"; + + Socket listen = Socket::createSocket(PATH); + std::shared_ptr server; + + auto serverCallback = [&](int, EventPoll::Events events) -> bool { + LOGD("Server events: " << strEvents(events)); + + if (events & EPOLLOUT) { + server->write(MESSAGE.data(), MESSAGE.size()); + poll.removeFD(server->getFD()); + server.reset(); + } + return true; + }; + + auto listenCallback = [&](int, EventPoll::Events events) -> bool { + LOGD("Listen events: " << strEvents(events)); + if (events & EPOLLIN) { + server = listen.accept(); + poll.addFD(server->getFD(), EPOLLHUP | EPOLLRDHUP | EPOLLOUT, serverCallback); + } + return true; + }; + + poll.addFD(listen.getFD(), EPOLLIN, listenCallback); + + Socket client = Socket::connectSocket(PATH); + + auto clientCallback = [&](int, EventPoll::Events events) -> bool { + LOGD("Client events: " << strEvents(events)); + + if (events & EPOLLIN) { + std::string ret(MESSAGE.size(), 'x'); + client.read(&ret.front(), ret.size()); + if (ret == MESSAGE) { + goodMessage.set(); + } + } + if (events & EPOLLRDHUP) { + poll.removeFD(client.getFD()); + remoteClosed.set(); + } + return true; + }; + + poll.addFD(client.getFD(), EPOLLHUP | EPOLLRDHUP | EPOLLIN, clientCallback); + + BOOST_CHECK(goodMessage.wait(TIMEOUT)); + BOOST_CHECK(remoteClosed.wait(TIMEOUT)); + + poll.removeFD(listen.getFD()); +} + +BOOST_AUTO_TEST_CASE(ThreadedPollSocket) +{ + Latch goodMessage; + Latch remoteClosed; + + EventPoll poll; + ThreadPollDispatcher dispatcher(poll); + + doSocketTest(poll, goodMessage, remoteClosed); +} + +BOOST_AUTO_TEST_CASE(GlibPollSocket) +{ + Latch goodMessage; + Latch remoteClosed; + + ScopedGlibLoop loop; + + EventPoll poll; + GlibPollDispatcher dispatcher(poll); + + doSocketTest(poll, goodMessage, remoteClosed); +} + +BOOST_AUTO_TEST_CASE(PollStacking) +{ + Latch goodMessage; + Latch remoteClosed; + + EventPoll outer; + EventPoll inner; + + auto dispatchInner = [&](int, EventPoll::Events) -> bool { + inner.dispatchIteration(0); + return true; + }; + + outer.addFD(inner.getPollFD(), EPOLLIN, dispatchInner); + + ThreadPollDispatcher dispatcher(outer); + doSocketTest(inner, goodMessage, remoteClosed); + + outer.removeFD(inner.getPollFD()); +} + +BOOST_AUTO_TEST_SUITE_END() + -- 2.7.4 From a2bfdea7f5bb1e2126701e0cf7d691f326afa9c4 Mon Sep 17 00:00:00 2001 From: Mateusz Malicki Date: Thu, 12 Feb 2015 16:39:58 +0100 Subject: [PATCH 15/16] Creating netdev [Feature] Filled stubs for creating netdev (create_netdev_phys, create_netdev_macvlan, create_netdev_veth) [Cause] N/A [Solution] Manage netdev through netlink interface [Verification] Build, install, run vasum-server, create zone (vasum-cli create_zone zone1), start zone (vasum-cli start_zone zone1), move interface f.e. p2p1 to zone (vasum-cli create_netdev_phys zone1 p2p1) enter to zone (lxc-console -n zone1 --lxcpath=/usr/local/share/.zones -t 0) check interfaces (ifconfig -a) do analogous for create_netdev_macvlan and create_netdev_veth Change-Id: I299d3ebeb8f101a386f5b156dbe79d7779600ef6 --- common/lxc/zone.cpp | 5 + common/lxc/zone.hpp | 7 ++ common/netlink/netlink-message.cpp | 164 +++++++++++++++++++++++++ common/netlink/netlink-message.hpp | 116 ++++++++++++++++++ common/netlink/netlink.cpp | 155 ++++++++++++++++++++++++ common/netlink/netlink.hpp | 79 ++++++++++++ server/netdev.cpp | 242 +++++++++++++++++++++++++++++++++++++ server/netdev.hpp | 45 +++++++ server/zone-admin.cpp | 19 +-- 9 files changed, 823 insertions(+), 9 deletions(-) create mode 100644 common/netlink/netlink-message.cpp create mode 100644 common/netlink/netlink-message.hpp create mode 100644 common/netlink/netlink.cpp create mode 100644 common/netlink/netlink.hpp create mode 100644 server/netdev.cpp create mode 100644 server/netdev.hpp diff --git a/common/lxc/zone.cpp b/common/lxc/zone.cpp index dc148e4..bbb1e02 100644 --- a/common/lxc/zone.cpp +++ b/common/lxc/zone.cpp @@ -313,6 +313,11 @@ bool LxcZone::waitForState(State state, int timeout) return true; } +pid_t LxcZone::getInitPid() const +{ + return mLxcContainer->init_pid(mLxcContainer); +} + bool LxcZone::setRunLevel(int runLevel) { auto callback = [](void* param) -> int { diff --git a/common/lxc/zone.hpp b/common/lxc/zone.hpp index 1573c7d..0ed19a3 100644 --- a/common/lxc/zone.hpp +++ b/common/lxc/zone.hpp @@ -26,6 +26,7 @@ #define COMMON_LXC_ZONE_HPP #include +#include // fwd declaration of lxc internals struct lxc_container; @@ -136,6 +137,12 @@ public: * Unfreeze zone */ bool unfreeze(); + + /** + * Get pid of init process + */ + pid_t getInitPid() const; + private: lxc_container* mLxcContainer; diff --git a/common/netlink/netlink-message.cpp b/common/netlink/netlink-message.cpp new file mode 100644 index 0000000..72d3597 --- /dev/null +++ b/common/netlink/netlink-message.cpp @@ -0,0 +1,164 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * Contact: Mateusz Malicki + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +/** + * @file + * @author Mateusz Malicki (m.malicki2@samsung.com) + * @brief Netlink message class definition + */ + +#include "config.hpp" +#include "netlink-message.hpp" +#include "netlink.hpp" +#include "base-exception.hpp" + +#include + +#include +#include +#include + +#include +#include +#include +#include + +#ifndef PAGE_SIZE +#define PAGE_SIZE 4096 +#endif + +const int NLMSG_GOOD_SIZE = 2*PAGE_SIZE; +constexpr rtattr* NLMSG_TAIL(nlmsghdr* nmsg) +{ + return reinterpret_cast(reinterpret_cast(nmsg) + NLMSG_ALIGN(nmsg->nlmsg_len)); +} + +namespace vasum { +namespace netlink { + +NetlinkMessage::NetlinkMessage(uint16_t type, uint16_t flags) +{ + static uint32_t seq = 0; + mNlmsg.resize(NLMSG_GOOD_SIZE, 0); + hdr().nlmsg_len = NLMSG_HDRLEN; + hdr().nlmsg_flags = flags | NLM_F_ACK; + hdr().nlmsg_type = type; + hdr().nlmsg_seq = ++seq; + hdr().nlmsg_pid = getpid(); +} + +NetlinkMessage& NetlinkMessage::beginNested(int ifla) +{ + struct rtattr *nest = NLMSG_TAIL(&hdr()); + put(ifla, NULL, 0); + mNested.push(nest); + return *this; +} + +NetlinkMessage& NetlinkMessage::endNested() +{ + assert(!mNested.empty()); + rtattr *nest = reinterpret_cast(mNested.top()); + nest->rta_len = std::distance(reinterpret_cast(nest), + reinterpret_cast(NLMSG_TAIL(&hdr()))); + mNested.pop(); + return *this; +} + +NetlinkMessage& NetlinkMessage::put(int ifla, const std::string& value) +{ + return put(ifla, value.c_str(), value.size() + 1); +} + +NetlinkMessage& NetlinkMessage::put(int ifla, const void* data, int len) +{ + struct rtattr *rta; + size_t rtalen = RTA_LENGTH(len); + int newLen = NLMSG_ALIGN(hdr().nlmsg_len) + RTA_ALIGN(rtalen); + + setMinCapacity(newLen); + rta = NLMSG_TAIL(&hdr()); + rta->rta_type = ifla; + rta->rta_len = rtalen; + memcpy(RTA_DATA(rta), data, len); + hdr().nlmsg_len = newLen; + return *this; +} + +NetlinkMessage& NetlinkMessage::put(const void* data, int len) +{ + setMinCapacity(hdr().nlmsg_len + len); + memcpy((reinterpret_cast(&hdr()) + hdr().nlmsg_len), data, len); + hdr().nlmsg_len += len; + return *this; +} + +nlmsghdr& NetlinkMessage::hdr() { + return *reinterpret_cast(mNlmsg.data()); +} + +const nlmsghdr& NetlinkMessage::hdr() const { + return *reinterpret_cast(mNlmsg.data()); +} + +void NetlinkMessage::setMinCapacity(unsigned int size) +{ + if (mNlmsg.size() < size) { + mNlmsg.resize(size, 0); + } +} + +void send(const NetlinkMessage& msg) +{ + //TODO: Handle messages with responses + assert(msg.hdr().nlmsg_flags & NLM_F_ACK); + + const int answerLen = NLMSG_ALIGN(msg.hdr().nlmsg_len + sizeof(nlmsgerr)); + std::unique_ptr answerBuff(new char[answerLen]); + nlmsghdr* answer = reinterpret_cast(answerBuff.get()); + answer->nlmsg_len = answerLen; + + Netlink nl; + nl.open(); + try { + nl.send(&msg.hdr()); + //Receive ACK Netlink Message + do { + nl.rcv(answer); + } while (answer->nlmsg_type == NLMSG_NOOP); + } catch (const std::exception& ex) { + LOGE("Sending failed (" << ex.what() << ")"); + nl.close(); + throw; + } + nl.close(); + if (answer->nlmsg_type != NLMSG_ERROR) { + // It is not NACK/ACK message + throw VasumException("Sending failed ( unrecognized message type )"); + } + nlmsgerr *err = reinterpret_cast(NLMSG_DATA(answer)); + if (answer->nlmsg_seq != msg.hdr().nlmsg_seq) { + throw VasumException("Sending failed ( answer message was mismatched )"); + } + if (err->error) { + throw VasumException("Sending failed (" + getSystemErrorMessage(-err->error) + ")"); + } +} + +} // namespace netlink +} // namespace vasum diff --git a/common/netlink/netlink-message.hpp b/common/netlink/netlink-message.hpp new file mode 100644 index 0000000..e828feb --- /dev/null +++ b/common/netlink/netlink-message.hpp @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * Contact: Mateusz Malicki + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +/** + * @file + * @author Mateusz Malicki (m.malicki2@samsung.com) + * @brief Netlink message class declaration + */ + +#ifndef COMMON_NETLINK_NETLINK_MESSAGE_HPP +#define COMMON_NETLINK_NETLINK_MESSAGE_HPP + +#include +#include +#include +#include +#include +#include + +namespace vasum { +namespace netlink { + +/** + * NetlinkMessage is used to creatie a netlink messages + */ +class NetlinkMessage { +public: + /** + * Create netlink message + * + * @param type rtnetlink message type (see man 7 rtnetlink) + * @param flags nlmsg flags (see man 7 netlink) + */ + NetlinkMessage(std::uint16_t type, std::uint16_t flags); + + /** + * Add nested atribute type + * + * All future attributes will be nested in this attribute (till call to endNested) + * + * @param ifla attribute name + */ + NetlinkMessage& beginNested(int ifla); + + /** + * End nested atribute + */ + NetlinkMessage& endNested(); + + ///@{ + /*Add sample attribute */ + NetlinkMessage& put(int ifla, const std::string& value); + template + NetlinkMessage& put(int ifla, const T& value); + ///@} + + /** + * Add raw data + * + * Add raw data to end of netlink message + */ + template + NetlinkMessage& put(const T& value); + + /** + * Send netlink message + * + * It is not thread safe + */ + friend void send(const NetlinkMessage& msg); +private: + std::vector mNlmsg; + std::stack mNested; + + NetlinkMessage& put(int ifla, const void* data, int len); + NetlinkMessage& put(const void* data, int len); + nlmsghdr& hdr(); + const nlmsghdr& hdr() const; + void setMinCapacity(unsigned int size); + + +}; + +template +NetlinkMessage& NetlinkMessage::put(int ifla, const T& value) +{ + static_assert(std::is_pod::value, "Require trivial and standard-layout"); + return put(ifla, &value, sizeof(value)); +} + +template +NetlinkMessage& NetlinkMessage::put(const T& value) +{ + static_assert(std::is_pod::value, "Require trivial and standard-layout structure"); + return put(&value, sizeof(value)); +} + +} // namespace netlink +} // namespace vasum + +#endif // COMMON_NETLINK_NETLINK_MESSAGE_HPP diff --git a/common/netlink/netlink.cpp b/common/netlink/netlink.cpp new file mode 100644 index 0000000..fa86b45 --- /dev/null +++ b/common/netlink/netlink.cpp @@ -0,0 +1,155 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * Contact: Mateusz Malicki + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +/** + * @file + * @author Mateusz Malicki (m.malicki2@samsung.com) + * @brief Netlink class definition + */ + +#include "config.hpp" +#include "netlink.hpp" +#include "utils.hpp" +#include "base-exception.hpp" + +#include +#include +#include +#include +#include +#include + +namespace vasum { + +namespace { + +template +T make_clean() +{ + static_assert(std::is_pod::value, "make_clean require trivial and standard-layout"); + T value; + std::fill_n(reinterpret_cast(&value), sizeof(value), 0); + return value; +} + +} // namespace + +Netlink::Netlink() : mFd(-1) +{ +} + +Netlink::~Netlink() +{ + close(); +} + +void Netlink::open() +{ + assert(mFd == -1); + mFd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); + if (mFd == -1) { + LOGE("Can't open socket (" << getSystemErrorMessage() << ")"); + throw VasumException("Can't open netlink connection"); + } + + sockaddr_nl local = make_clean(); + local.nl_family = AF_NETLINK; + + if (bind(mFd, (struct sockaddr *)&local, sizeof(local)) < 0) { + int err = errno; + close(); + LOGE("Can't bind to socket (" << getSystemErrorMessage(err) << ")"); + throw VasumException("Can't set up netlink connection"); + } +} + +void Netlink::close() +{ + if (mFd != -1) { + ::close(mFd); + mFd = -1; + } +} + +void Netlink::send(const nlmsghdr *nlmsg) +{ + msghdr msg = make_clean(); + sockaddr_nl nladdr = make_clean(); + iovec iov = make_clean(); + + iov.iov_base = (void *)nlmsg; + iov.iov_len = nlmsg->nlmsg_len; + msg.msg_name = &nladdr; + msg.msg_namelen = sizeof(nladdr); + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + nladdr.nl_family = AF_NETLINK; + + int ret = sendmsg(mFd, &msg, 0); + if (ret < 0) { + LOGE("Can't send message (" << getSystemErrorMessage() << ")"); + throw VasumException("Can't send netlink message"); + } +} + +int Netlink::rcv(nlmsghdr *answer) +{ + //TODO: Handle too small buffer situation (buffer resizing) + msghdr msg = make_clean(); + sockaddr_nl nladdr = make_clean(); + iovec iov = make_clean(); + + iov.iov_base = answer; + iov.iov_len = answer->nlmsg_len; + msg.msg_name = &nladdr; + msg.msg_namelen = sizeof(nladdr); + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + nladdr.nl_family = AF_NETLINK; + + int ret = recvmsg(mFd, &msg, 0); + if (ret < 0) { + LOGE("Can't receive message (" + getSystemErrorMessage() + ")"); + throw VasumException("Can't receive netlink message"); + } + if (ret == 0) { + LOGE("Peer has performed an orderly shutdown"); + throw VasumException("Can't receive netlink message"); + } + if (msg.msg_flags & MSG_TRUNC) { + LOGE("Can't receive message (" + getSystemErrorMessage(EMSGSIZE) + ")"); + throw VasumException("Can't receive netlink message"); + } + if (msg.msg_flags & MSG_ERRQUEUE) { + LOGE("No data was received but an extended error"); + throw VasumException("Can't receive netlink message"); + } + if (msg.msg_flags & MSG_OOB) { + LOGE("Internal error (expedited or out-of-band data were received)"); + throw VasumException("Can't receive netlink message"); + } + if (msg.msg_flags & (MSG_EOR | MSG_CTRUNC)) { + assert(!"This should not happen!"); + LOGE("Internal error (" << std::to_string(msg.msg_flags) << ")"); + throw VasumException("Internal error while recaiving netlink message"); + } + + return ret; +} + +} //namespace vasum diff --git a/common/netlink/netlink.hpp b/common/netlink/netlink.hpp new file mode 100644 index 0000000..2e73ce8 --- /dev/null +++ b/common/netlink/netlink.hpp @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * Contact: Mateusz Malicki + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +/** + * @file + * @author Mateusz Malicki (m.malicki2@samsung.com) + * @brief Netlink class declaration + */ + +#ifndef COMMON_NETLINK_NETLINK_HPP +#define COMMON_NETLINK_NETLINK_HPP + +#include + +namespace vasum { + +/** + * Netlink class is responsible for communicating + * with kernel through netlink interface + */ +class Netlink { +public: + Netlink(); + ~Netlink(); + + Netlink(const Netlink& other) = delete; + Netlink& operator=(const Netlink& other) = delete; + + /** + * Open connnection + */ + void open(); + + /** + * Close connection + */ + void close(); + + /** + * Send message + * + * It is not thread safe and even you shouldn't call this function on + * different instances at the same time + * + * @param nlmsg pointer to message + */ + void send(const nlmsghdr *nlmsg); + + /** + * Receive message + * + * It is not thread safe and even you shouldn't call this function on + * different instances at the same time + * + * @param answer pointer to answer buffer + */ + int rcv(nlmsghdr *answer); +private: + int mFd; +}; + +} // namespace vasum + +#endif /* COMMON_NETLINK_NETLINK_HPP */ diff --git a/server/netdev.cpp b/server/netdev.cpp new file mode 100644 index 0000000..b4a2d21 --- /dev/null +++ b/server/netdev.cpp @@ -0,0 +1,242 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * Contact: Mateusz Malicki + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +/** + * @file + * @author Mateusz Malicki (m.malicki2@samsung.com) + * @brief Network devices management functions definition + */ + +#include "config.hpp" +#include "netdev.hpp" +#include "netlink/netlink-message.hpp" +#include "utils.hpp" +#include "exception.hpp" + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; +using namespace vasum; +using namespace vasum::netlink; + +namespace vasum { +namespace netdev { + +namespace { + +template +T make_clean() +{ + static_assert(std::is_pod::value, "make_clean require trivial and standard-layout"); + T value; + std::fill_n(reinterpret_cast(&value), sizeof(value), 0); + return value; +} + +string getUniqueVethName() +{ + auto find = [](const ifaddrs* ifaddr, const string& name) -> bool { + for (const ifaddrs* ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) { + if (name == ifa->ifa_name) { + return true; + } + } + return false; + }; + + ifaddrs* ifaddr; + getifaddrs(&ifaddr); + string newName; + int i = 0; + do { + newName = "veth0" + to_string(++i); + } while (find(ifaddr, newName)); + + freeifaddrs(ifaddr); + return newName; +} + +uint32_t getInterfaceIndex(const string& name) { + uint32_t index = if_nametoindex(name.c_str()); + if (!index) { + LOGE("Can't get " << name << " interface index (" << getSystemErrorMessage() << ")"); + throw ZoneOperationException("Can't find interface"); + } + return index; +} + +void validateNetdevName(const string& name) +{ + if (name.size() <= 1 || name.size() >= IFNAMSIZ) { + throw ZoneOperationException("Invalid netdev name format"); + } +} + +void createPipedNetdev(const string& netdev1, const string& netdev2) +{ + validateNetdevName(netdev1); + validateNetdevName(netdev2); + + NetlinkMessage nlm(RTM_NEWLINK, NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL | NLM_F_ACK); + ifinfomsg infoPeer = make_clean(); + infoPeer.ifi_family = AF_UNSPEC; + infoPeer.ifi_change = 0xFFFFFFFF; + nlm.put(infoPeer) + .beginNested(IFLA_LINKINFO) + .put(IFLA_INFO_KIND, "veth") + .beginNested(IFLA_INFO_DATA) + .beginNested(VETH_INFO_PEER) + .put(infoPeer) + .put(IFLA_IFNAME, netdev2) + .endNested() + .endNested() + .endNested() + .put(IFLA_IFNAME, netdev1); + send(nlm); +} + +void attachToBridge(const string& bridge, const string& netdev) +{ + validateNetdevName(bridge); + validateNetdevName(netdev); + + uint32_t index = getInterfaceIndex(netdev); + int fd = socket(AF_LOCAL, SOCK_STREAM, 0); + if (fd < 0) { + LOGE("Can't open socket (" << getSystemErrorMessage() << ")"); + throw ZoneOperationException("Can't attach to bridge"); + } + + struct ifreq ifr = make_clean(); + strncpy(ifr.ifr_name, bridge.c_str(), IFNAMSIZ); + ifr.ifr_ifindex = index; + int err = ioctl(fd, SIOCBRADDIF, &ifr); + if (err < 0) { + int error = errno; + //TODO: Close can be interrupted. Move util functions from ipc + ::close(fd); + LOGE("Can't attach to bridge (" + getSystemErrorMessage(error) + ")"); + throw ZoneOperationException("Can't attach to bridge"); + } + close(fd); +} + +int setFlags(const string& name, uint32_t mask, uint32_t flags) +{ + uint32_t index = getInterfaceIndex(name); + NetlinkMessage nlm(RTM_NEWLINK, NLM_F_REQUEST | NLM_F_ACK); + ifinfomsg infoPeer = make_clean(); + infoPeer.ifi_family = AF_UNSPEC; + infoPeer.ifi_index = index; + infoPeer.ifi_flags = flags; + // since kernel v2.6.22 ifi_change is used to change only selected flags; + infoPeer.ifi_change = mask; + nlm.put(infoPeer); + send(nlm); + return 0; +} + +void up(const string& netdev) +{ + setFlags(netdev, IFF_UP, IFF_UP); +} + +void moveToNS(const string& netdev, pid_t pid) +{ + uint32_t index = getInterfaceIndex(netdev); + NetlinkMessage nlm(RTM_NEWLINK, NLM_F_REQUEST | NLM_F_ACK); + ifinfomsg infopeer = make_clean(); + infopeer.ifi_family = AF_UNSPEC; + infopeer.ifi_index = index; + nlm.put(infopeer) + .put(IFLA_NET_NS_PID, pid); + send(nlm); +} + +void createMacvlan(const string& master, const string& slave, const macvlan_mode& mode) +{ + validateNetdevName(master); + validateNetdevName(slave); + + uint32_t index = getInterfaceIndex(master); + NetlinkMessage nlm(RTM_NEWLINK, NLM_F_REQUEST|NLM_F_CREATE|NLM_F_EXCL|NLM_F_ACK); + ifinfomsg infopeer = make_clean(); + infopeer.ifi_family = AF_UNSPEC; + infopeer.ifi_change = 0xFFFFFFFF; + nlm.put(infopeer) + .beginNested(IFLA_LINKINFO) + .put(IFLA_INFO_KIND, "macvlan") + .beginNested(IFLA_INFO_DATA) + .put(IFLA_MACVLAN_MODE, static_cast(mode)) + .endNested() + .endNested() + .put(IFLA_LINK, index) + .put(IFLA_IFNAME, slave); + send(nlm); +} + +} // namespace + +void createVeth(const pid_t& nsPid, const string& nsDev, const string& hostDev) +{ + string hostVeth = getUniqueVethName(); + LOGT("Creating veth: bridge: " << hostDev << ", port: " << hostVeth << ", zone: " << nsDev); + createPipedNetdev(nsDev, hostVeth); + //TODO: clean up if following instructions fail + attachToBridge(hostDev, hostVeth); + up(hostVeth); + moveToNS(nsDev, nsPid); +} + +void createMacvlan(const pid_t& nsPid, + const string& nsDev, + const string& hostDev, + const macvlan_mode& mode) +{ + LOGT("Creating macvlan: host: " << hostDev << ", zone: " << nsDev << ", mode: " << mode); + createMacvlan(hostDev, nsDev, mode); + //TODO: clean up if following instructions fail + up(nsDev); + moveToNS(nsDev, nsPid); +} + +void movePhys(const pid_t& nsPid, const string& devId) +{ + LOGT("Creating phys: dev: " << devId); + moveToNS(devId, nsPid); +} + +} //namespace netdev +} //namespace vasum + diff --git a/server/netdev.hpp b/server/netdev.hpp new file mode 100644 index 0000000..de761ca --- /dev/null +++ b/server/netdev.hpp @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * Contact: Mateusz Malicki + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +/** + * @file + * @author Mateusz Malicki (m.malicki2@samsung.com) + * @brief Network devices management functions declaration + */ + +#ifndef SERVER_NETDEV_HPP +#define SERVER_NETDEV_HPP + +#include +#include +#include + +namespace vasum { +namespace netdev { + +void createVeth(const pid_t& nsPid, const std::string& nsDev, const std::string& hostDev); +void createMacvlan(const pid_t& nsPid, + const std::string& nsDev, + const std::string& hostDev, + const macvlan_mode& mode); +void movePhys(const pid_t& nsPid, const std::string& devId); + +} //namespace netdev +} //namespace vasum + +#endif // SERVER_NETDEV_HPP diff --git a/server/zone-admin.cpp b/server/zone-admin.cpp index c5e994d..5a4adfa 100644 --- a/server/zone-admin.cpp +++ b/server/zone-admin.cpp @@ -26,6 +26,7 @@ #include "zone-admin.hpp" #include "exception.hpp" +#include "netdev.hpp" #include "logger/logger.hpp" #include "utils/paths.hpp" @@ -270,22 +271,22 @@ std::int64_t ZoneAdmin::getSchedulerQuota() return std::stoll(ret); } -void ZoneAdmin::createNetdevVeth(const std::string& /* zoneDev */, - const std::string& /* hostDev */) +void ZoneAdmin::createNetdevVeth(const std::string& zoneDev, + const std::string& hostDev) { - throw ZoneOperationException("Not implemented"); + netdev::createVeth(mZone.getInitPid(), zoneDev, hostDev); } -void ZoneAdmin::createNetdevMacvlan(const std::string& /* zoneDev */, - const std::string& /* hostDev */, - const uint32_t& /* mode */) +void ZoneAdmin::createNetdevMacvlan(const std::string& zoneDev, + const std::string& hostDev, + const uint32_t& mode) { - throw ZoneOperationException("Not implemented"); + netdev::createMacvlan(mZone.getInitPid(), zoneDev, hostDev, static_cast(mode)); } -void ZoneAdmin::moveNetdev(const std::string& /* devId */) +void ZoneAdmin::moveNetdev(const std::string& devId) { - throw ZoneOperationException("Not implemented"); + netdev::movePhys(mZone.getInitPid(), devId); } } // namespace vasum -- 2.7.4 From d8256e79f51e16d2d35fbf3b4c12f714cc47e215 Mon Sep 17 00:00:00 2001 From: Mateusz Malicki Date: Thu, 19 Feb 2015 15:44:34 +0100 Subject: [PATCH 16/16] Stubs for get/set ipv4/ipv6, destroy netdev and list netdev [Feature] Stubs (cli, client, server) for get/set ipv4/ipv6, destroy netdev and list netdev netdev [Cause] N/A [Solution] N/A [Verification] Build, run cli commnads Change-Id: Ia1dc21e5fb252b2f83d617abec785bce7d6ffc9e --- cli/command-line-interface.cpp | 129 +++++++++++++++++++++++ cli/command-line-interface.hpp | 49 +++++++++ cli/main.cpp | 66 ++++++++++++ client/CMakeLists.txt | 4 +- client/vasum-client-impl.cpp | 205 ++++++++++++++++++++++++++++++++++--- client/vasum-client-impl.hpp | 10 ++ client/vasum-client.cpp | 14 +++ client/vasum-client.h | 25 +++++ common/netlink/netlink-message.cpp | 6 +- server/host-connection.cpp | 53 ++++++++++ server/host-connection.hpp | 36 ++++++- server/host-dbus-definitions.hpp | 17 +++ server/zone-admin.cpp | 15 +++ server/zone-admin.hpp | 16 +++ server/zone.cpp | 18 ++++ server/zone.hpp | 15 +++ server/zones-manager.cpp | 87 +++++++++++++++- server/zones-manager.hpp | 9 ++ 18 files changed, 754 insertions(+), 20 deletions(-) diff --git a/cli/command-line-interface.cpp b/cli/command-line-interface.cpp index a189a92..77e9dc5 100644 --- a/cli/command-line-interface.cpp +++ b/cli/command-line-interface.cpp @@ -38,6 +38,7 @@ #include #include #include +#include using namespace std; @@ -394,5 +395,133 @@ void create_netdev_phys(int pos, int argc, const char** argv) argv[pos + 2])); } +void zone_get_netdevs(int pos, int argc, const char** argv) +{ + using namespace std::placeholders; + + if (argc <= pos + 1) { + throw runtime_error("Not enough parameters"); + } + VsmArrayString ids; + one_shot(bind(vsm_zone_get_netdevs, + _1, + argv[pos + 1], + &ids)); + string delim; + for (VsmString* id = ids; *id; ++id) { + cout << delim << *id; + delim = ", "; + } + if (delim.empty()) { + cout << "There is no network device in zone"; + } + cout << endl; + vsm_array_string_free(ids); +} + +void netdev_get_ipv4_addr(int pos, int argc, const char** argv) +{ + using namespace std::placeholders; + + if (argc <= pos + 2) { + throw runtime_error("Not enough parameters"); + } + in_addr addr; + one_shot(bind(vsm_netdev_get_ipv4_addr, + _1, + argv[pos + 1], + argv[pos + 2], + &addr)); + char buf[INET_ADDRSTRLEN]; + if (inet_ntop(AF_INET, &addr, buf, INET_ADDRSTRLEN) == NULL) { + throw runtime_error("Server gave the wrong address format"); + } + cout << buf << endl; +} + +void netdev_get_ipv6_addr(int pos, int argc, const char** argv) +{ + using namespace std::placeholders; + + if (argc <= pos + 2) { + throw runtime_error("Not enough parameters"); + } + in6_addr addr; + one_shot(bind(vsm_netdev_get_ipv6_addr, + _1, + argv[pos + 1], + argv[pos + 2], + &addr)); + char buf[INET6_ADDRSTRLEN]; + if (inet_ntop(AF_INET6, &addr, buf, INET6_ADDRSTRLEN) == NULL) { + throw runtime_error("Server gave the wrong address format"); + } + cout << buf << endl; +} + +void netdev_set_ipv4_addr(int pos, int argc, const char** argv) +{ + using namespace std::placeholders; + + if (argc <= pos + 4) { + throw runtime_error("Not enough parameters"); + } + in_addr addr; + if (inet_pton(AF_INET, argv[pos + 3], &addr) != 1) { + throw runtime_error("Wrong address format"); + }; + one_shot(bind(vsm_netdev_set_ipv4_addr, + _1, + argv[pos + 1], + argv[pos + 2], + &addr, + stoi(argv[pos + 4]))); +} + +void netdev_set_ipv6_addr(int pos, int argc, const char** argv) +{ + using namespace std::placeholders; + + if (argc <= pos + 4) { + throw runtime_error("Not enough parameters"); + } + in6_addr addr; + if (inet_pton(AF_INET6, argv[pos + 3], &addr) != 1) { + throw runtime_error("Wrong address format"); + }; + one_shot(bind(vsm_netdev_set_ipv6_addr, + _1, + argv[pos + 1], + argv[pos + 2], + &addr, + stoi(argv[pos + 4]))); +} + +void netdev_up(int pos, int argc, const char** argv) +{ + using namespace std::placeholders; + + if (argc <= pos + 2) { + throw runtime_error("Not enough parameters"); + } + one_shot(bind(vsm_netdev_up, + _1, + argv[pos + 1], + argv[pos + 2])); +} + +void netdev_down(int pos, int argc, const char** argv) +{ + using namespace std::placeholders; + + if (argc <= pos + 2) { + throw runtime_error("Not enough parameters"); + } + one_shot(bind(vsm_netdev_down, + _1, + argv[pos + 1], + argv[pos + 2])); +} + } // namespace cli } // namespace vasum diff --git a/cli/command-line-interface.hpp b/cli/command-line-interface.hpp index 34ac013..eb33428 100644 --- a/cli/command-line-interface.hpp +++ b/cli/command-line-interface.hpp @@ -208,6 +208,55 @@ void create_netdev_macvlan(int pos, int argc, const char** argv); */ void create_netdev_phys(int pos, int argc, const char** argv); +/** + * Parses command line arguments and prints result of vsm_zone_get_netdevs + * + * @see vsm_zone_get_netdevs + */ +void zone_get_netdevs(int pos, int argc, const char** argv); + +/** + * Parses command line arguments and prints result of vsm_netdev_get_ipv4_addr + * + * @see vsm_netdev_get_ipv4_addr + */ +void netdev_get_ipv4_addr(int pos, int argc, const char** argv); + +/** + * Parses command line arguments and and prints result of vsm_netdev_get_ipv6_addr + * + * @see vsm_netdev_get_ipv6_addr + */ +void netdev_get_ipv6_addr(int pos, int argc, const char** argv); + +/** + * Parses command line arguments and call vsm_netdev_set_ipv4_addr + * + * @see vsm_netdev_set_ipv4_addr + */ +void netdev_set_ipv4_addr(int pos, int argc, const char** argv); + +/** + * Parses command line arguments and call vsm_netdev_set_ipv6_addr + * + * @see vsm_netdev_set_ipv6_addr + */ +void netdev_set_ipv6_addr(int pos, int argc, const char** argv); + +/** + * Parses command line arguments and call vsm_netdev_up + * + * @see vsm_netdev_up + */ +void netdev_up(int pos, int argc, const char** argv); + +/** + * Parses command line arguments and call vsm_netdev_down + * + * @see vsm_netdev_down + */ +void netdev_down(int pos, int argc, const char** argv); + } // namespace cli } // namespace vasum diff --git a/cli/main.cpp b/cli/main.cpp index 38a8ae5..5f073be 100644 --- a/cli/main.cpp +++ b/cli/main.cpp @@ -170,6 +170,72 @@ std::map commands = { {{"zone_id", "id zone name"}, {"devId", "network device id"}} } + }, + { + "zone_get_netdevs", { + zone_get_netdevs, + "zone_get_netdevs zone_id", + "List network devices in the zone", + {{"zone_id", "id zone name"}} + } + }, + { + "netdev_get_ipv4_addr", { + netdev_get_ipv4_addr, + "netdev_get_ipv4_addr zone_id netdev_id", + "Get ipv4 address", + {{"zone_id", "id zone name"}, + {"netdev_id", "network device name"}} + } + }, + { + "netdev_get_ipv6_addr", { + netdev_get_ipv6_addr, + "netdev_get_ipv6_addr zone_id netdev_id", + "Get ipv6 address", + {{"zone_id", "id zone name"}, + {"netdev_id", "network device name"}} + } + }, + { + "netdev_set_ipv4_addr", { + netdev_set_ipv4_addr, + "netdev_set_ipv4_addr zone_id netdev_id address prefix_len", + "Set ipv4 address", + {{"zone_id", "id zone name"}, + {"netdev_id", "network device name"}, + {"address", "ipv4 address"}, + {"prefix_len", "bit length of prefix"}} + } + }, + { + "netdev_set_ipv6_addr", { + netdev_set_ipv6_addr, + "netdev_set_ipv6_addr zone_id netdev_id address prefix_len", + "Set ipv6 address", + {{"zone_id", "id zone name"}, + {"netdev_id", "network device name"}, + {"address", "ipv6 address"}, + {"prefix_len", "bit length of prefix"}} + } + }, + { + "netdev_up", { + netdev_up, + "netdev_up zone_id netdev_id", + "Turn up a network device in the zone", + {{"zone_id", "id zone name"}, + {"netdev_id", "network device id"}} + } + }, + { + "zone_get_netdevs", { + zone_get_netdevs, + "zone_get_netdevs zone_id", + "Turn down a network device in the zone", + {{"zone_id", "id zone name"}, + {"netdev_id", "network device id"}} + } } }; diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt index 7060b7b..558f3a7 100644 --- a/client/CMakeLists.txt +++ b/client/CMakeLists.txt @@ -23,7 +23,9 @@ FILE(GLOB project_SRCS *.cpp *.hpp *.h) FILE(GLOB common_SRCS ${COMMON_FOLDER}/utils/callback-guard.hpp ${COMMON_FOLDER}/utils/callback-guard.cpp ${COMMON_FOLDER}/utils/glib-loop.cpp - ${COMMON_FOLDER}/utils/glib-loop.hpp) + ${COMMON_FOLDER}/utils/glib-loop.hpp + ${COMMON_FOLDER}/base-exception.hpp + ${COMMON_FOLDER}/base-exception.cpp) SET(_LIB_VERSION_ "0.0.1") SET(_LIB_SOVERSION_ "0") diff --git a/client/vasum-client-impl.cpp b/client/vasum-client-impl.cpp index d6f4217..d8ba562 100644 --- a/client/vasum-client-impl.cpp +++ b/client/vasum-client-impl.cpp @@ -31,10 +31,15 @@ #include #include #include +#include +#include +#include +#include #include #include #include +#include using namespace std; using namespace dbus; @@ -77,6 +82,21 @@ void toDict(GVariant* in, VsmArrayString* keys, VsmArrayString* values) *values = outv; } +vector> toDict(GVariant* in) +{ + assert(in); + + const gchar* key; + const gchar* value; + vector> dict; + GVariantIter iter; + g_variant_iter_init(&iter, in); + while (g_variant_iter_loop(&iter, "(&s&s)", &key, &value)) { + dict.push_back(make_tuple(key, value)); + } + return dict; +} + void toBasic(GVariant* in, char** str) { assert(in); @@ -152,6 +172,37 @@ void toArray(GVariant* in, T** scArray) *scArray = ids; } +string toString(const in_addr* addr) +{ + char buf[INET_ADDRSTRLEN]; + const char* ret = inet_ntop(AF_INET, addr, buf, INET_ADDRSTRLEN); + if (ret == NULL) { + throw runtime_error(getSystemErrorMessage()); + } + return ret; +} + +string toString(const in6_addr* addr) +{ + char buf[INET6_ADDRSTRLEN]; + const char* ret = inet_ntop(AF_INET6, addr, buf, INET6_ADDRSTRLEN); + if (ret == NULL) { + throw runtime_error(getSystemErrorMessage()); + } + return ret; +} + +GVariant* createTupleArray(const vector>& dict) +{ + GVariantBuilder builder; + g_variant_builder_init(&builder, G_VARIANT_TYPE_ARRAY); + for (const auto entry : dict) { + g_variant_builder_add(&builder, "(ss)", get<0>(entry).c_str(), get<1>(entry).c_str()); + } + return g_variant_builder_end(&builder); +} + + VsmStatus toStatus(const exception& ex) { if (typeid(DbusCustomException) == typeid(ex)) { @@ -530,34 +581,162 @@ VsmStatus Client::vsm_revoke_device(const char* id, const char* device) noexcept return callMethod(HOST_INTERFACE, api::host::METHOD_REVOKE_DEVICE, args_in); } -VsmStatus Client::vsm_zone_get_netdevs(const char*, VsmArrayString*) noexcept +VsmStatus Client::vsm_zone_get_netdevs(const char* zone, VsmArrayString* netdevIds) noexcept { - mStatus = Status(VSMCLIENT_OTHER_ERROR, "Not implemented"); - return vsm_get_status(); + assert(zone); + assert(netdevIds); + + GVariant* out = NULL; + GVariant* args_in = g_variant_new("(s)", zone); + VsmStatus ret = callMethod(HOST_INTERFACE, + api::host::METHOD_GET_NETDEV_LIST, + args_in, + "(as)", + &out); + if (ret != VSMCLIENT_SUCCESS) { + return ret; + } + GVariant* unpacked; + g_variant_get(out, "(*)", &unpacked); + toArray(unpacked, netdevIds); + g_variant_unref(unpacked); + g_variant_unref(out); + return ret; } -VsmStatus Client::vsm_netdev_get_ipv4_addr(const char*, const char*, struct in_addr*) noexcept +VsmStatus Client::vsm_netdev_get_ipv4_addr(const char* zone, + const char* netdevId, + struct in_addr* addr) noexcept { - mStatus = Status(VSMCLIENT_OTHER_ERROR, "Not implemented"); + assert(zone); + assert(netdevId); + assert(addr); + + GVariant* out = NULL; + GVariant* args_in = g_variant_new("(ss)", zone, netdevId); + VsmStatus ret = callMethod(HOST_INTERFACE, + api::host::METHOD_GET_NETDEV_ATTRS, + args_in, + "(a(ss))", + &out); + if (ret != VSMCLIENT_SUCCESS) { + return ret; + } + GVariant* unpacked; + g_variant_get(out, "(*)", &unpacked); + vector> attrs = toDict(unpacked); + g_variant_unref(unpacked); + g_variant_unref(out); + + auto it = find_if(attrs.begin(), attrs.end(), [](const tuple& entry) { + return get<0>(entry) == "ipv4"; + }); + if (it != attrs.end()) { + if (inet_pton(AF_INET, get<1>(*it).c_str(), addr) != 1) { + mStatus = Status(VSMCLIENT_CUSTOM_ERROR, "Invalid response data"); + return vsm_get_status(); + } + mStatus = Status(); + return vsm_get_status(); + } + mStatus = Status(VSMCLIENT_CUSTOM_ERROR, "Address not found"); return vsm_get_status(); } -VsmStatus Client::vsm_netdev_get_ipv6_addr(const char*, const char*, struct in6_addr*) noexcept +VsmStatus Client::vsm_netdev_get_ipv6_addr(const char* zone, + const char* netdevId, + struct in6_addr* addr) noexcept { - mStatus = Status(VSMCLIENT_OTHER_ERROR, "Not implemented"); + assert(zone); + assert(netdevId); + assert(addr); + + GVariant* out = NULL; + GVariant* args_in = g_variant_new("(ss)", zone, netdevId); + VsmStatus ret = callMethod(HOST_INTERFACE, + api::host::METHOD_GET_NETDEV_ATTRS, + args_in, + "(a(ss))", + &out); + if (ret != VSMCLIENT_SUCCESS) { + return ret; + } + GVariant* unpacked; + g_variant_get(out, "(*)", &unpacked); + vector> attrs = toDict(unpacked); + g_variant_unref(unpacked); + g_variant_unref(out); + + //XXX: return only one address + auto it = find_if(attrs.begin(), attrs.end(), [](const tuple& entry) { + return get<0>(entry) == "ipv6"; + }); + if (it != attrs.end()) { + if (inet_pton(AF_INET6, get<1>(*it).c_str(), addr) != 1) { + mStatus = Status(VSMCLIENT_CUSTOM_ERROR, "Invalid response data"); + return vsm_get_status(); + } + mStatus = Status(); + return vsm_get_status(); + } + mStatus = Status(VSMCLIENT_CUSTOM_ERROR, "Address not found"); return vsm_get_status(); } -VsmStatus Client::vsm_netdev_set_ipv4_addr(const char*, const char*, struct in_addr*, int) noexcept +VsmStatus Client::vsm_netdev_set_ipv4_addr(const char* zone, + const char* netdevId, + struct in_addr* addr, + int mask) noexcept { - mStatus = Status(VSMCLIENT_OTHER_ERROR, "Not implemented"); - return vsm_get_status(); + try { + GVariant* dict = createTupleArray({make_tuple("ipv4", toString(addr)), + make_tuple("mask", to_string(mask))}); + GVariant* args_in = g_variant_new("(ss@a(ss))", zone, netdevId, dict); + return callMethod(HOST_INTERFACE, api::host::METHOD_SET_NETDEV_ATTRS, args_in); + } catch (exception& ex) { + mStatus = Status(VSMCLIENT_INVALID_ARGUMENT, ex.what()); + return vsm_get_status(); + } } -VsmStatus Client::vsm_netdev_set_ipv6_addr(const char*, const char*, struct in6_addr*, int) noexcept +VsmStatus Client::vsm_netdev_set_ipv6_addr(const char* zone, + const char* netdevId, + struct in6_addr* addr, + int mask) noexcept { - mStatus = Status(VSMCLIENT_OTHER_ERROR, "Not implemented"); - return vsm_get_status(); + try { + GVariant* dict = createTupleArray({make_tuple("ipv6", toString(addr)), + make_tuple("mask", to_string(mask))}); + GVariant* args_in = g_variant_new("(ss@a(ss))", zone, netdevId, dict); + return callMethod(HOST_INTERFACE, api::host::METHOD_SET_NETDEV_ATTRS, args_in); + } catch (exception& ex) { + mStatus = Status(VSMCLIENT_INVALID_ARGUMENT, ex.what()); + return vsm_get_status(); + } +} + +VsmStatus Client::vsm_netdev_up(const char* zone, const char* netdevId) noexcept +{ + try { + GVariant* dict = createTupleArray({make_tuple("up", "true")}); + GVariant* args_in = g_variant_new("(ss@a(ss))", zone, netdevId, dict); + return callMethod(HOST_INTERFACE, api::host::METHOD_SET_NETDEV_ATTRS, args_in); + } catch (exception& ex) { + mStatus = Status(VSMCLIENT_INVALID_ARGUMENT, ex.what()); + return vsm_get_status(); + } +} + +VsmStatus Client::vsm_netdev_down(const char* zone, const char* netdevId) noexcept +{ + try { + GVariant* dict = createTupleArray({make_tuple("up", "false")}); + GVariant* args_in = g_variant_new("(ss@a(ss))", zone, netdevId, dict); + return callMethod(HOST_INTERFACE, api::host::METHOD_SET_NETDEV_ATTRS, args_in); + } catch (exception& ex) { + mStatus = Status(VSMCLIENT_INVALID_ARGUMENT, ex.what()); + return vsm_get_status(); + } } VsmStatus Client::vsm_create_netdev_veth(const char* zone, diff --git a/client/vasum-client-impl.hpp b/client/vasum-client-impl.hpp index 193f140..9399839 100644 --- a/client/vasum-client-impl.hpp +++ b/client/vasum-client-impl.hpp @@ -229,6 +229,16 @@ public: int prefix) noexcept; /** + * @see ::vsm_netdev_up + */ + VsmStatus vsm_netdev_up(const char* zone, const char* netdevId) noexcept; + + /** + * @see ::vsm_netdev_down + */ + VsmStatus vsm_netdev_down(const char* zone, const char* netdevId) noexcept; + + /** * @see ::vsm_create_netdev_veth */ VsmStatus vsm_create_netdev_veth(const char* zone, diff --git a/client/vasum-client.cpp b/client/vasum-client.cpp index 1f011c1..9c0ca60 100644 --- a/client/vasum-client.cpp +++ b/client/vasum-client.cpp @@ -250,6 +250,20 @@ API VsmStatus vsm_netdev_set_ipv6_addr(VsmClient client, return getClient(client).vsm_netdev_set_ipv6_addr(zone, netdevId, addr, prefix); } +API VsmStatus vsm_netdev_up(VsmClient client, + const char* zone, + const char* netdevId) +{ + return getClient(client).vsm_netdev_up(zone, netdevId); +} + +API VsmStatus vsm_netdev_down(VsmClient client, + const char* zone, + const char* netdevId) +{ + return getClient(client).vsm_netdev_down(zone, netdevId); +} + API VsmStatus vsm_create_netdev_veth(VsmClient client, const char* zone, const char* zoneDev, diff --git a/client/vasum-client.h b/client/vasum-client.h index 1fb48b1..0bd40ad 100644 --- a/client/vasum-client.h +++ b/client/vasum-client.h @@ -552,6 +552,31 @@ VsmStatus vsm_netdev_set_ipv6_addr(VsmClient client, int prefix); /** + * Turn up a network device in the zone + * + * @param[in] client vasum-server's client + * @param[in] zone zone name + * @param[in] netdevId netdev id + * @return status of this function call + */ +VsmStatus vsm_netdev_up(VsmClient client, + const char* zone, + const char* netdevId); + +/** + * Turn down a network device in the zone + * + * @param[in] client vasum-server's client + * @param[in] zone zone name + * @param[in] netdevId netdev id + * @return status of this function call + */ +VsmStatus vsm_netdev_down(VsmClient client, + const char* zone, + const char* netdevId); + + +/** * Create veth netdev in zone * * @param[in] client vasum-server's client diff --git a/common/netlink/netlink-message.cpp b/common/netlink/netlink-message.cpp index 72d3597..9f33450 100644 --- a/common/netlink/netlink-message.cpp +++ b/common/netlink/netlink-message.cpp @@ -42,12 +42,16 @@ #define PAGE_SIZE 4096 #endif +namespace { + const int NLMSG_GOOD_SIZE = 2*PAGE_SIZE; -constexpr rtattr* NLMSG_TAIL(nlmsghdr* nmsg) +inline rtattr* NLMSG_TAIL(nlmsghdr* nmsg) { return reinterpret_cast(reinterpret_cast(nmsg) + NLMSG_ALIGN(nmsg->nlmsg_len)); } +} // namespace + namespace vasum { namespace netlink { diff --git a/server/host-connection.cpp b/server/host-connection.cpp index 75c4433..6790480 100644 --- a/server/host-connection.cpp +++ b/server/host-connection.cpp @@ -130,6 +130,21 @@ void HostConnection::setGetZoneInfoCallback(const GetZoneInfoCallback& callback) mGetZoneInfoCallback = callback; } +void HostConnection::setSetNetdevAttrsCallback(const SetNetdevAttrsCallback& callback) +{ + mSetNetdevAttrsCallback = callback; +} + +void HostConnection::setGetNetdevAttrsCallback(const GetNetdevAttrsCallback& callback) +{ + mGetNetdevAttrsCallback = callback; +} + +void HostConnection::setGetNetdevListCallback(const GetNetdevListCallback& callback) +{ + mGetNetdevListCallback = callback; +} + void HostConnection::setCreateNetdevVethCallback(const CreateNetdevVethCallback& callback) { mCreateNetdevVethCallback = callback; @@ -296,6 +311,44 @@ void HostConnection::onMessageCall(const std::string& objectPath, return; } + if (methodName == api::host::METHOD_SET_NETDEV_ATTRS){ + const gchar* zone = NULL; + const gchar* netdev = NULL; + GVariantIter* iter; + g_variant_get(parameters, "(&s&sa(ss))", &zone, &netdev, &iter); + gchar* key = NULL; + gchar* value = NULL; + std::vector> attrs; + while (g_variant_iter_loop(iter, "(&s&s)", &key, &value)) { + attrs.push_back(std::make_tuple(key, value)); + } + g_variant_iter_free(iter); + if (mSetNetdevAttrsCallback) { + mSetNetdevAttrsCallback(zone, netdev, attrs, result); + } + return; + } + + if (methodName == api::host::METHOD_GET_NETDEV_ATTRS){ + const gchar* zone = NULL; + const gchar* netdev = NULL; + g_variant_get(parameters, "(&s&s)", &zone, &netdev); + if (mGetNetdevAttrsCallback) { + mGetNetdevAttrsCallback(zone, netdev, result); + } + return; + } + + if (methodName == api::host::METHOD_GET_NETDEV_LIST){ + const gchar* zone = NULL; + g_variant_get(parameters, "(&s)", &zone); + if (mGetNetdevListCallback) { + mGetNetdevListCallback(zone, result); + } + return; + } + + if (methodName == api::host::METHOD_CREATE_NETDEV_VETH) { const gchar* id = NULL; const gchar* zoneDev = NULL; diff --git a/server/host-connection.hpp b/server/host-connection.hpp index 649ed15..569c68f 100644 --- a/server/host-connection.hpp +++ b/server/host-connection.hpp @@ -30,6 +30,8 @@ #include #include +#include +#include namespace vasum { @@ -60,8 +62,20 @@ public: typedef std::function GetZoneInfoCallback; - typedef std::function>& attrs, + dbus::MethodResultBuilder::Pointer result + )> SetNetdevAttrsCallback; + typedef std::function GetNetdevAttrsCallback; + typedef std::function GetNetdevListCallback; + typedef std::function CreateNetdevVethCallback; @@ -165,6 +179,21 @@ public: void setGetZoneInfoCallback(const GetZoneInfoCallback& callback); /** + * Register a callback called to set network device attributes + */ + void setSetNetdevAttrsCallback(const SetNetdevAttrsCallback& callback); + + /** + * Register a callback called to get network device attributes + */ + void setGetNetdevAttrsCallback(const GetNetdevAttrsCallback& callback); + + /** + * Register a callback called to get network device list + */ + void setGetNetdevListCallback(const GetNetdevListCallback& callback); + + /** * Register a callback called to create veth */ void setCreateNetdevVethCallback(const CreateNetdevVethCallback& callback); @@ -270,6 +299,9 @@ private: GetZoneIdsCallback mGetZoneIdsCallback; GetActiveZoneIdCallback mGetActiveZoneIdCallback; GetZoneInfoCallback mGetZoneInfoCallback; + SetNetdevAttrsCallback mSetNetdevAttrsCallback; + GetNetdevAttrsCallback mGetNetdevAttrsCallback; + GetNetdevListCallback mGetNetdevListCallback; CreateNetdevVethCallback mCreateNetdevVethCallback; CreateNetdevMacvlanCallback mCreateNetdevMacvlanCallback; CreateNetdevPhysCallback mCreateNetdevPhysCallback; diff --git a/server/host-dbus-definitions.hpp b/server/host-dbus-definitions.hpp index 6d25bb1..2c2a201 100644 --- a/server/host-dbus-definitions.hpp +++ b/server/host-dbus-definitions.hpp @@ -42,6 +42,9 @@ const std::string METHOD_GET_ZONE_DBUSES = "GetZoneDbuses"; const std::string METHOD_GET_ZONE_ID_LIST = "GetZoneIds"; const std::string METHOD_GET_ACTIVE_ZONE_ID = "GetActiveZoneId"; const std::string METHOD_GET_ZONE_INFO = "GetZoneInfo"; +const std::string METHOD_SET_NETDEV_ATTRS = "SetNetdevAttrs"; +const std::string METHOD_GET_NETDEV_ATTRS = "GetNetdevAttrs"; +const std::string METHOD_GET_NETDEV_LIST = "GetNetdevList"; const std::string METHOD_CREATE_NETDEV_VETH = "CreateNetdevVeth"; const std::string METHOD_CREATE_NETDEV_MACVLAN = "CreateNetdevMacvlan"; const std::string METHOD_CREATE_NETDEV_PHYS = "CreateNetdevPhys"; @@ -88,6 +91,20 @@ const std::string DEFINITION = " " " " " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " " " " " " " diff --git a/server/zone-admin.cpp b/server/zone-admin.cpp index 5a4adfa..519b172 100644 --- a/server/zone-admin.cpp +++ b/server/zone-admin.cpp @@ -289,4 +289,19 @@ void ZoneAdmin::moveNetdev(const std::string& devId) netdev::movePhys(mZone.getInitPid(), devId); } +void ZoneAdmin::setNetdevAttrs(const std::string& /* netdev */, const NetdevAttrs& /* attrs */) +{ + throw ZoneOperationException("Not implemented"); +} + +ZoneAdmin::NetdevAttrs ZoneAdmin::getNetdevAttrs(const std::string& /* netdev */) +{ + throw ZoneOperationException("Not implemented"); +} + +std::vector ZoneAdmin::getNetdevList() +{ + throw ZoneOperationException("Not implemented"); +} + } // namespace vasum diff --git a/server/zone-admin.hpp b/server/zone-admin.hpp index 9125a6d..44d2613 100644 --- a/server/zone-admin.hpp +++ b/server/zone-admin.hpp @@ -41,6 +41,7 @@ enum class SchedulerLevel { class ZoneAdmin { public: + typedef std::vector> NetdevAttrs; /** * ZoneAdmin constructor @@ -148,6 +149,21 @@ public: */ void moveNetdev(const std::string& devId); + /** + * Set network device attributes + */ + void setNetdevAttrs(const std::string& netdev, const NetdevAttrs& attrs); + + /** + * Get network device attributes + */ + NetdevAttrs getNetdevAttrs(const std::string& netdev); + + /** + * Get network device list + */ + std::vector getNetdevList(); + private: const ZoneConfig& mConfig; lxc::LxcZone mZone; diff --git a/server/zone.cpp b/server/zone.cpp index 0607fda..fed66fa 100644 --- a/server/zone.cpp +++ b/server/zone.cpp @@ -441,4 +441,22 @@ void Zone::removeDeclaration(const std::string& declarationId) mProvision->remove(declarationId); } +void Zone::setNetdevAttrs(const std::string& netdev, const ZoneAdmin::NetdevAttrs& attrs) +{ + Lock lock(mReconnectMutex); + mAdmin->setNetdevAttrs(netdev, attrs); +} + +ZoneAdmin::NetdevAttrs Zone::getNetdevAttrs(const std::string& netdev) +{ + Lock lock(mReconnectMutex); + return mAdmin->getNetdevAttrs(netdev); +} + +std::vector Zone::getNetdevList() +{ + Lock lock(mReconnectMutex); + return mAdmin->getNetdevList(); +} + } // namespace vasum diff --git a/server/zone.hpp b/server/zone.hpp index 759faa3..832fcec 100644 --- a/server/zone.hpp +++ b/server/zone.hpp @@ -285,6 +285,21 @@ public: */ void moveNetdev(const std::string& devId); + /** + * Set network device attributes + */ + void setNetdevAttrs(const std::string& netdev, const ZoneAdmin::NetdevAttrs& attrs); + + /** + * Get network device attributes + */ + ZoneAdmin::NetdevAttrs getNetdevAttrs(const std::string& netdev); + + /** + * Get network device list + */ + std::vector getNetdevList(); + private: utils::Worker::Pointer mWorker; ZoneConfig mConfig; diff --git a/server/zones-manager.cpp b/server/zones-manager.cpp index 5f0dca4..283f57f 100644 --- a/server/zones-manager.cpp +++ b/server/zones-manager.cpp @@ -141,6 +141,15 @@ ZonesManager::ZonesManager(const std::string& configPath) mHostConnection.setGetZoneInfoCallback(bind(&ZonesManager::handleGetZoneInfoCall, this, _1, _2)); + mHostConnection.setSetNetdevAttrsCallback(bind(&ZonesManager::handleSetNetdevAttrsCall, + this, _1, _2, _3, _4)); + + mHostConnection.setGetNetdevAttrsCallback(bind(&ZonesManager::handleGetNetdevAttrsCall, + this, _1, _2, _3)); + + mHostConnection.setGetNetdevListCallback(bind(&ZonesManager::handleGetNetdevListCall, + this, _1, _2)); + mHostConnection.setCreateNetdevVethCallback(bind(&ZonesManager::handleCreateNetdevVethCall, this, _1, _2, _3, _4)); @@ -803,6 +812,78 @@ void ZonesManager::handleGetZoneInfoCall(const std::string& id, zone.getRootPath().c_str())); } +void ZonesManager::handleSetNetdevAttrsCall(const std::string& zone, + const std::string& netdev, + const std::vector< + std::tuple>& attrs, + dbus::MethodResultBuilder::Pointer result) +{ + LOGI("SetNetdevAttrs call"); + try { + Lock lock(mMutex); + + getZone(zone).setNetdevAttrs(netdev, attrs); + result->setVoid(); + } catch (const InvalidZoneIdException&) { + LOGE("No zone with id=" << zone); + result->setError(api::ERROR_INVALID_ID, "No such zone id"); + } catch (const VasumException& ex) { + LOGE("Can't set attributes: " << ex.what()); + result->setError(api::ERROR_INTERNAL, ex.what()); + } +} + +void ZonesManager::handleGetNetdevAttrsCall(const std::string& zone, + const std::string& netdev, + dbus::MethodResultBuilder::Pointer result) +{ + LOGI("GetNetdevAttrs call"); + try { + Lock lock(mMutex); + + const auto attrs = getZone(zone).getNetdevAttrs(netdev); + + GVariantBuilder builder; + g_variant_builder_init(&builder, G_VARIANT_TYPE_ARRAY); + for (const auto entry : attrs) { + g_variant_builder_add(&builder, + "(ss)", + std::get<0>(entry).c_str(), + std::get<1>(entry).c_str()); + } + result->set(g_variant_builder_end(&builder)); + } catch (const InvalidZoneIdException&) { + LOGE("No zone with id=" << zone); + result->setError(api::ERROR_INVALID_ID, "No such zone id"); + } catch (const VasumException& ex) { + LOGE("Can't set attributes: " << ex.what()); + result->setError(api::ERROR_INTERNAL, ex.what()); + } +} + +void ZonesManager::handleGetNetdevListCall(const std::string& zone, + dbus::MethodResultBuilder::Pointer result) +{ + LOGI("GetNetdevList call"); + try { + Lock lock(mMutex); + std::vector netdevs; + for(auto& netdev: getZone(zone).getNetdevList()){ + netdevs.push_back(g_variant_new_string(netdev.c_str())); + } + GVariant* array = g_variant_new_array(G_VARIANT_TYPE("s"), + netdevs.data(), + netdevs.size()); + result->set(g_variant_new("(@as)", array)); + } catch (const InvalidZoneIdException&) { + LOGE("No zone with id=" << zone); + result->setError(api::ERROR_INVALID_ID, "No such zone id"); + } catch (const VasumException& ex) { + LOGE("Can't set attributes: " << ex.what()); + result->setError(api::ERROR_INTERNAL, ex.what()); + } +} + void ZonesManager::handleCreateNetdevVethCall(const std::string& zone, const std::string& zoneDev, const std::string& hostDev, @@ -814,7 +895,7 @@ void ZonesManager::handleCreateNetdevVethCall(const std::string& zone, getZone(zone).createNetdevVeth(zoneDev, hostDev); result->setVoid(); - } catch (const std::out_of_range&) { + } catch (const InvalidZoneIdException&) { LOGE("No zone with id=" << zone); result->setError(api::ERROR_INVALID_ID, "No such zone id"); } catch (const VasumException& ex) { @@ -835,7 +916,7 @@ void ZonesManager::handleCreateNetdevMacvlanCall(const std::string& zone, getZone(zone).createNetdevMacvlan(zoneDev, hostDev, mode); result->setVoid(); - } catch (const std::out_of_range&) { + } catch (const InvalidZoneIdException&) { LOGE("No zone with id=" << zone); result->setError(api::ERROR_INVALID_ID, "No such zone id"); } catch (const VasumException& ex) { @@ -854,7 +935,7 @@ void ZonesManager::handleCreateNetdevPhysCall(const std::string& zone, getZone(zone).moveNetdev(devId); result->setVoid(); - } catch (const std::out_of_range&) { + } catch (const InvalidZoneIdException&) { LOGE("No zone with id=" << zone); result->setError(api::ERROR_INVALID_ID, "No such zone id"); } catch (const VasumException& ex) { diff --git a/server/zones-manager.hpp b/server/zones-manager.hpp index df5e12b..ee1606d 100644 --- a/server/zones-manager.hpp +++ b/server/zones-manager.hpp @@ -161,6 +161,15 @@ private: void handleGetZoneIdsCall(dbus::MethodResultBuilder::Pointer result); void handleGetActiveZoneIdCall(dbus::MethodResultBuilder::Pointer result); void handleGetZoneInfoCall(const std::string& id, dbus::MethodResultBuilder::Pointer result); + void handleSetNetdevAttrsCall(const std::string& zone, + const std::string& netdev, + const std::vector>& attrs, + dbus::MethodResultBuilder::Pointer result); + void handleGetNetdevAttrsCall(const std::string& zone, + const std::string& netdev, + dbus::MethodResultBuilder::Pointer result); + void handleGetNetdevListCall(const std::string& zone, + dbus::MethodResultBuilder::Pointer result); void handleCreateNetdevVethCall(const std::string& zone, const std::string& zoneDev, const std::string& hostDev, -- 2.7.4