2 * Copyright (c) 2019-present Samsung Electronics Co., Ltd All Rights Reserved
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License
17 #include "policy-storage.hpp"
19 #include <vist/database/column.hpp>
20 #include <vist/database/statement.hpp>
21 #include <vist/exception.hpp>
22 #include <vist/logger.hpp>
23 #include <vist/query-builder.hpp>
30 const std::string SCRIPT_BASE = SCRIPT_INSTALL_DIR;
31 const std::string SCRIPT_CREATE_SCHEMA = "create-schema";
33 } // anonymous namespace
38 PolicyStorage::PolicyStorage(const std::string& path) :
39 database(std::make_shared<database::Connection>(path))
41 database->exec("PRAGMA foreign_keys = ON;");
42 database->transactionBegin();
43 database->exec(getScript(SCRIPT_CREATE_SCHEMA));
44 database->transactionEnd();
49 void PolicyStorage::sync()
51 DEBUG(VIST) << "Sync policy storage to cache object.";
54 syncPolicyDefinition();
57 void PolicyStorage::syncPolicyDefinition()
59 this->definitions.clear();
60 std::string query = schema::policyDefinition.selectAll();
61 database::Statement stmt(*database, query);
64 PolicyDefinition pd = { std::string(stmt.getColumn(0)), std::string(stmt.getColumn(1)) };
65 DEBUG(VIST) << "Defined policy:" << pd.name;
66 this->definitions.emplace(pd.name, std::move(pd));
69 DEBUG(VIST) << definitions.size() << "-policies synced.";
72 void PolicyStorage::syncAdmin()
75 std::string query = schema::admin.selectAll();
76 database::Statement stmt(*database, query);
79 Admin admin = { std::string(stmt.getColumn(0)), stmt.getColumn(1).getInt() };
80 this->admins.emplace(admin.name, std::move(admin));
83 DEBUG(VIST) << admins.size() << "-admins synced.";
86 void PolicyStorage::syncPolicyManaged()
88 this->managedPolicies.clear();
89 std::string query = schema::policyManaged.selectAll();
90 database::Statement stmt(*database, query);
94 pa.admin = std::string(stmt.getColumn(0));
95 pa.policy = std::string(stmt.getColumn(1));
96 pa.value = std::string(stmt.getColumn(2));
97 this->managedPolicies.emplace(pa.policy, std::move(pa));
100 DEBUG(VIST) << managedPolicies.size() << "-managed-policies synced.";
103 std::string PolicyStorage::getScript(const std::string& name)
105 std::string path = SCRIPT_BASE + "/" + name + ".sql";
106 std::ifstream is(path);
108 THROW(ErrCode::LogicError) << "Failed to open script: " << path;
110 std::istreambuf_iterator<char> begin(is), end;
111 auto content = std::string(begin, end);
113 THROW(ErrCode::LogicError) << "Failed to read script: " << path;
118 void PolicyStorage::define(const std::string& policy, const PolicyValue& ivalue)
120 if (this->definitions.find(policy) != this->definitions.end()) {
121 DEBUG(VIST) << "Policy is already defined: " << policy;
125 PolicyDefinition pd = { policy, ivalue.dump() };
127 std::string query = schema::PolicyDefinitionTable.insert(PolicyDefinition::Name,
128 PolicyDefinition::Ivalue);
129 database::Statement stmt(*database, query);
130 stmt.bind(1, pd.name);
131 stmt.bind(2, pd.ivalue);
133 THROW(ErrCode::RuntimeError) << stmt.getErrorMessage();
135 INFO(VIST) << "Policy defined >> name: " << pd.name << ", ivalue: " << pd.ivalue;
136 this->definitions.emplace(pd.name, std::move(pd));
139 void PolicyStorage::enroll(const std::string& name)
141 INFO(VIST) << "Enroll admin: " << name;
142 if (this->admins.find(name) != this->admins.end()) {
143 WARN(VIST) << "Admin is already enrolled.: " << name;
147 /// Make admin deactivated as default.
148 Admin admin = {name , 0};
150 std::string query = schema::AdminTable.insert(Admin::Name, Admin::Activated);
151 database::Statement stmt(*database, query);
152 stmt.bind(1, admin.name);
153 stmt.bind(2, admin.activated);
155 THROW(ErrCode::RuntimeError) << stmt.getErrorMessage();
157 this->admins.emplace(admin.name, std::move(admin));
159 /// PolicyManaged is triggered by enrolling admin.
162 int count = this->managedPolicies.size() / this->admins.size();
163 INFO(VIST) << "Admin[" << name << "] manages "
164 << std::to_string(count) << "-policies.";
167 void PolicyStorage::disenroll(const std::string& name)
169 if (name == DEFAULT_ADMIN_PATH)
170 THROW(ErrCode::RuntimeError) << "Cannot disenroll default admin.";
172 INFO(VIST) << "Disenroll admin: " << name;
173 if (this->admins.find(name) == this->admins.end()) {
174 ERROR(VIST) << "Not exist admin: " << name;
177 this->admins.erase(name);
180 std::string query = schema::admin.remove().where(expr(&Admin::name) == name);
181 database::Statement stmt(*database, query);
184 THROW(ErrCode::RuntimeError) << stmt.getErrorMessage();
187 this->syncPolicyManaged();
190 void PolicyStorage::activate(const std::string& admin, bool state)
192 if (this->admins.find(admin) == this->admins.end())
193 THROW(ErrCode::LogicError) << "Not exist admin: " << admin;
195 DEBUG(VIST) << "Activate admin: " << admin;
197 std::string query = schema::AdminTable.update(Admin::Activated)
198 .where(expr(&Admin::name) == admin);
199 database::Statement stmt(*this->database, query);
200 stmt.bind(1, static_cast<int>(state));
203 THROW(ErrCode::RuntimeError) << stmt.getErrorMessage();
205 this->admins[admin].activated = state;
206 INFO(VIST) << "Admin[" << admin << "]'s activated value is set: " << state;
209 bool PolicyStorage::isActivated(const std::string& admin)
211 if (this->admins.find(admin) == this->admins.end())
212 THROW(ErrCode::LogicError) << "Not exist admin: " << admin;
214 return this->admins[admin].activated;
217 bool PolicyStorage::isActivated()
219 for (const auto& admin : this->admins)
220 if (admin.second.activated)
226 void PolicyStorage::update(const std::string& admin,
227 const std::string& policy,
228 const PolicyValue& value)
230 DEBUG(VIST) << "Policy-update is called by admin: " << admin
231 << ", about: " << policy << ", value: " << value.dump();
233 if (this->admins.find(admin) == this->admins.end())
234 THROW(ErrCode::LogicError) << "Not exist admin: " << admin;
236 if (this->definitions.find(policy) == this->definitions.end())
237 THROW(ErrCode::LogicError) << "Not exist policy: " << policy;
239 std::string query = schema::PolicyManagedTable.update(PolicyManaged::Value)
240 .where(expr(&PolicyManaged::admin) == admin &&
241 expr(&PolicyManaged::policy) == policy);
242 database::Statement stmt(*this->database, query);
243 stmt.bind(1, value.dump());
245 stmt.bind(3, policy);
247 THROW(ErrCode::RuntimeError) << stmt.getErrorMessage();
249 /// TODO: Fix to sync without db i/o
250 this->syncPolicyManaged();
253 PolicyValue PolicyStorage::strictest(const std::shared_ptr<PolicyModel>& policy)
255 if (this->definitions.find(policy->getName()) == this->definitions.end())
256 THROW(ErrCode::LogicError) << "Not exist policy: " << policy->getName();
258 if (this->managedPolicies.size() == 0) {
259 INFO(VIST) << "There is no enrolled admin. Return policy initial value.";
260 return policy->getInitial();
263 std::shared_ptr<PolicyValue> strictestPtr = nullptr;
264 auto range = managedPolicies.equal_range(policy->getName());
265 for (auto iter = range.first; iter != range.second; iter++) {
266 DEBUG(VIST) << "Admin: " << iter->second.admin << ", "
267 << "Policy: " << iter->second.policy << ", "
268 << "Value: " << iter->second.value;
270 if (strictestPtr == nullptr) {
271 strictestPtr = std::make_shared<PolicyValue>(iter->second.value, true);
273 if (policy->compare(*strictestPtr, PolicyValue(iter->second.value, true)) > 0)
274 strictestPtr.reset(new PolicyValue(iter->second.value, true));
278 if (strictestPtr == nullptr)
279 THROW(ErrCode::RuntimeError) << "Not exist managed policy: " << policy;
281 DEBUG(VIST) << "The strictest value of [" << policy->getName()
282 << "] is " << strictestPtr->dump();
284 return std::move(*strictestPtr);
287 std::unordered_map<std::string, int> PolicyStorage::getAdmins() const noexcept
289 std::unordered_map<std::string, int> ret;
290 for (const auto& admin : this->admins)
291 ret[admin.second.name] = admin.second.activated;
296 } // namespace policy