blob: 7b710f11e6a3f2f6cdc7ef945038074f55e2c499 [file] [log] [blame]
Christopher Wileya4915c42014-03-27 14:45:37 -07001// Copyright 2014 The Chromium OS Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "buffet/manager.h"
6
Alex Vakulenkob3aac252014-05-07 17:35:24 -07007#include <map>
Alex Vakulenko9ea5a322015-04-17 15:35:34 -07008#include <set>
Alex Vakulenkob3aac252014-05-07 17:35:24 -07009#include <string>
10
Christopher Wileya4915c42014-03-27 14:45:37 -070011#include <base/bind.h>
12#include <base/bind_helpers.h>
Alex Vakulenko665c8852014-09-11 16:57:24 -070013#include <base/json/json_reader.h>
Christopher Wileyb76eb292014-05-05 16:09:16 -070014#include <base/json/json_writer.h>
Christopher Wileycd419662015-02-06 17:51:43 -080015#include <base/time/time.h>
Alex Vakulenkoa8b95bc2014-08-27 11:00:57 -070016#include <chromeos/dbus/async_event_sequencer.h>
17#include <chromeos/dbus/exported_object_manager.h>
18#include <chromeos/errors/error.h>
Anton Muhin332df192014-11-22 05:59:14 +040019#include <chromeos/key_value_store.h>
Christopher Wileyb76eb292014-05-05 16:09:16 -070020#include <dbus/bus.h>
Christopher Wiley90016242014-04-01 17:33:29 -070021#include <dbus/object_path.h>
Alex Vakulenko3cb466c2014-04-15 11:36:32 -070022#include <dbus/values_util.h>
Christopher Wileya4915c42014-03-27 14:45:37 -070023
Alex Vakulenko665c8852014-09-11 16:57:24 -070024#include "buffet/commands/command_instance.h"
Alex Vakulenkoe03af6d2015-04-20 11:00:54 -070025#include "buffet/commands/schema_constants.h"
Alex Vakulenko57123b22014-10-28 13:50:16 -070026#include "buffet/states/state_change_queue.h"
Alex Vakulenko07216fe2014-09-19 15:31:09 -070027#include "buffet/states/state_manager.h"
Christopher Wileye0fdeee2015-02-07 18:29:32 -080028#include "buffet/storage_impls.h"
Christopher Wileya4915c42014-03-27 14:45:37 -070029
Christopher Wiley2d2d92b2014-07-29 14:07:10 -070030using chromeos::dbus_utils::AsyncEventSequencer;
Christopher Wileyb5dd5ea2014-08-11 10:51:20 -070031using chromeos::dbus_utils::ExportedObjectManager;
Christopher Wileya4915c42014-03-27 14:45:37 -070032
33namespace buffet {
34
Alex Vakulenko57123b22014-10-28 13:50:16 -070035namespace {
36// Max of 100 state update events should be enough in the queue.
37const size_t kMaxStateChangeQueueSize = 100;
38} // anonymous namespace
39
Alex Vakulenkof2784de2014-08-15 11:49:35 -070040Manager::Manager(const base::WeakPtr<ExportedObjectManager>& object_manager)
41 : dbus_object_(object_manager.get(),
42 object_manager->GetBus(),
Vitaly Buka7ad8ffb2015-03-20 09:46:57 -070043 org::chromium::Buffet::ManagerAdaptor::GetObjectPath()) {
44}
Christopher Wileya4915c42014-03-27 14:45:37 -070045
Vitaly Buka7ad8ffb2015-03-20 09:46:57 -070046Manager::~Manager() {
47}
Alex Vakulenko57123b22014-10-28 13:50:16 -070048
Vitaly Buka76e70592015-04-16 11:39:02 -070049void Manager::Start(const base::FilePath& config_path,
50 const base::FilePath& state_path,
51 const base::FilePath& test_definitions_path,
52 bool xmpp_enabled,
53 const AsyncEventSequencer::CompletionAction& cb) {
Alex Vakulenko95110752014-09-03 16:27:21 -070054 command_manager_ =
55 std::make_shared<CommandManager>(dbus_object_.GetObjectManager());
Alex Vakulenko9ea5a322015-04-17 15:35:34 -070056 command_changed_callback_token_ = command_manager_->AddOnCommandDefChanged(
Vitaly Bukaaabadee2015-03-18 23:33:44 -070057 base::Bind(&Manager::OnCommandDefsChanged, base::Unretained(this)));
Christopher Wileybb5b8482015-02-12 13:42:16 -080058 command_manager_->Startup(base::FilePath{"/etc/buffet"},
59 test_definitions_path);
Alex Vakulenko57123b22014-10-28 13:50:16 -070060 state_change_queue_ = std::unique_ptr<StateChangeQueue>(
61 new StateChangeQueue(kMaxStateChangeQueueSize));
62 state_manager_ = std::make_shared<StateManager>(state_change_queue_.get());
Alex Vakulenko07216fe2014-09-19 15:31:09 -070063 state_manager_->Startup();
Christopher Wiley583d64b2015-03-24 14:30:17 -070064 std::unique_ptr<BuffetConfig> config{new BuffetConfig};
65 config->Load(config_path);
Christopher Wileye0fdeee2015-02-07 18:29:32 -080066 std::unique_ptr<FileStorage> state_store{new FileStorage{state_path}};
Christopher Wileye0fdeee2015-02-07 18:29:32 -080067 // TODO(avakulenko): Figure out security implications of storing
68 // device info state data unencrypted.
Alex Vakulenko1f30a622014-07-23 11:13:15 -070069 device_info_ = std::unique_ptr<DeviceRegistrationInfo>(
Christopher Wileyc900e482015-02-15 15:42:04 -080070 new DeviceRegistrationInfo(
71 command_manager_,
72 state_manager_,
Christopher Wiley583d64b2015-03-24 14:30:17 -070073 std::move(config),
Christopher Wileyc900e482015-02-15 15:42:04 -080074 chromeos::http::Transport::CreateDefault(),
75 std::move(state_store),
Christopher Wileyd732bd02015-04-07 11:11:18 -070076 xmpp_enabled,
Vitaly Bukafa947062015-04-17 00:41:31 -070077 &dbus_adaptor_));
Vitaly Bukab055f152015-03-12 13:41:43 -070078 device_info_->Load();
Alex Vakulenko2348e422014-11-21 08:57:57 -080079 dbus_adaptor_.RegisterWithDBusObject(&dbus_object_);
80 dbus_object_.RegisterAsync(cb);
Christopher Wileya4915c42014-03-27 14:45:37 -070081}
82
Alex Vakulenko2348e422014-11-21 08:57:57 -080083void Manager::CheckDeviceRegistered(DBusMethodResponse<std::string> response) {
Alex Vakulenko3cb466c2014-04-15 11:36:32 -070084 LOG(INFO) << "Received call to Manager.CheckDeviceRegistered()";
Alex Vakulenko5c7bf012014-10-30 16:28:38 -070085 chromeos::ErrorPtr error;
Nathan Bullock5e022a32015-04-08 15:13:07 -040086 bool registered = device_info_->HaveRegistrationCredentials(&error);
Alex Vakulenkob3aac252014-05-07 17:35:24 -070087 // If it fails due to any reason other than 'device not registered',
88 // treat it as a real error and report it to the caller.
89 if (!registered &&
Alex Vakulenko5c7bf012014-10-30 16:28:38 -070090 !error->HasError(kErrorDomainGCD, "device_not_registered")) {
91 response->ReplyWithError(error.get());
92 return;
Alex Vakulenkob3aac252014-05-07 17:35:24 -070093 }
Christopher Wileya4915c42014-03-27 14:45:37 -070094
Vitaly Buka620bd7e2015-03-16 01:07:01 -070095 response->Return(registered ? device_info_->GetDeviceId() : std::string());
Alex Vakulenko3cb466c2014-04-15 11:36:32 -070096}
97
Alex Vakulenko2348e422014-11-21 08:57:57 -080098void Manager::GetDeviceInfo(DBusMethodResponse<std::string> response) {
Alex Vakulenko3cb466c2014-04-15 11:36:32 -070099 LOG(INFO) << "Received call to Manager.GetDeviceInfo()";
100
Alex Vakulenko5c7bf012014-10-30 16:28:38 -0700101 chromeos::ErrorPtr error;
102 auto device_info = device_info_->GetDeviceInfo(&error);
103 if (!device_info) {
104 response->ReplyWithError(error.get());
105 return;
106 }
Alex Vakulenkob3aac252014-05-07 17:35:24 -0700107
Alex Vakulenko5c7bf012014-10-30 16:28:38 -0700108 std::string device_info_str;
Nathan Bullock4b6c0fb2015-04-01 15:32:58 -0400109 base::JSONWriter::WriteWithOptions(device_info.get(),
110 base::JSONWriter::OPTIONS_PRETTY_PRINT, &device_info_str);
Alex Vakulenko5c7bf012014-10-30 16:28:38 -0700111 response->Return(device_info_str);
Alex Vakulenko3cb466c2014-04-15 11:36:32 -0700112}
113
Alex Vakulenko2348e422014-11-21 08:57:57 -0800114void Manager::RegisterDevice(DBusMethodResponse<std::string> response,
115 const chromeos::VariantDictionary& params) {
Anton Muhinbeb1c5b2014-10-16 18:59:57 +0400116 LOG(INFO) << "Received call to Manager.RegisterDevice()";
Alex Vakulenko3cb466c2014-04-15 11:36:32 -0700117
Alex Vakulenko5c7bf012014-10-30 16:28:38 -0700118 chromeos::ErrorPtr error;
Alex Vakulenko2348e422014-11-21 08:57:57 -0800119 std::map<std::string, std::string> str_params;
120 for (const auto& pair : params) {
121 if (!pair.second.IsTypeCompatible<std::string>()) {
122 response->ReplyWithError(FROM_HERE, chromeos::errors::dbus::kDomain,
123 DBUS_ERROR_INVALID_ARGS,
124 "String value expected");
125 return;
126 }
Vitaly Buka7ad8ffb2015-03-20 09:46:57 -0700127 str_params.emplace_hint(str_params.end(), pair.first,
128 pair.second.Get<std::string>());
Alex Vakulenko2348e422014-11-21 08:57:57 -0800129 }
130 std::string device_id = device_info_->RegisterDevice(str_params, &error);
David Zeuthen1dbad472015-02-12 15:24:21 -0500131 if (!device_id.empty()) {
Alex Vakulenko5c7bf012014-10-30 16:28:38 -0700132 response->Return(device_id);
David Zeuthen1dbad472015-02-12 15:24:21 -0500133 return;
134 }
135 if (!error) {
136 // TODO(zeuthen): This can be changed to CHECK(error) once
137 // RegisterDevice() has been fixed to set |error| when failing.
Vitaly Buka7ad8ffb2015-03-20 09:46:57 -0700138 chromeos::Error::AddTo(&error, FROM_HERE, kErrorDomainGCD, "internal_error",
David Zeuthen1dbad472015-02-12 15:24:21 -0500139 "device_id empty but error not set");
140 }
141 response->ReplyWithError(error.get());
Christopher Wileya4915c42014-03-27 14:45:37 -0700142}
143
Alex Vakulenko2348e422014-11-21 08:57:57 -0800144void Manager::UpdateState(DBusMethodResponse<> response,
145 const chromeos::VariantDictionary& property_set) {
Alex Vakulenko5c7bf012014-10-30 16:28:38 -0700146 chromeos::ErrorPtr error;
Alex Vakulenkoff73cf22014-10-29 09:53:52 -0700147 base::Time timestamp = base::Time::Now();
Alex Vakulenko5c7bf012014-10-30 16:28:38 -0700148 bool all_success = true;
Alex Vakulenkoff73cf22014-10-29 09:53:52 -0700149 for (const auto& pair : property_set) {
Vitaly Buka7ad8ffb2015-03-20 09:46:57 -0700150 if (!state_manager_->SetPropertyValue(pair.first, pair.second, timestamp,
151 &error)) {
Alex Vakulenko5c7bf012014-10-30 16:28:38 -0700152 // Remember that an error occurred but keep going and update the rest of
153 // the properties if possible.
154 all_success = false;
155 }
Alex Vakulenkoff73cf22014-10-29 09:53:52 -0700156 }
Alex Vakulenko5c7bf012014-10-30 16:28:38 -0700157 if (!all_success)
158 response->ReplyWithError(error.get());
159 else
160 response->Return();
Christopher Wileya4915c42014-03-27 14:45:37 -0700161}
162
Alex Vakulenko61ad4db2015-01-20 10:50:04 -0800163bool Manager::GetState(chromeos::ErrorPtr* error, std::string* state) {
164 auto json = state_manager_->GetStateValuesAsJson(error);
165 if (!json)
166 return false;
Nathan Bullock4b6c0fb2015-04-01 15:32:58 -0400167 base::JSONWriter::WriteWithOptions(
168 json.get(), base::JSONWriter::OPTIONS_PRETTY_PRINT, state);
Alex Vakulenko61ad4db2015-01-20 10:50:04 -0800169 return true;
170}
171
Vitaly Buka64fc5fc2015-03-24 12:42:24 -0700172void Manager::AddCommand(DBusMethodResponse<std::string> response,
Alex Vakulenko2348e422014-11-21 08:57:57 -0800173 const std::string& json_command) {
Anton Muhin5191e812014-10-30 17:49:48 +0400174 static int next_id = 0;
Alex Vakulenko665c8852014-09-11 16:57:24 -0700175 std::string error_message;
176 std::unique_ptr<base::Value> value(base::JSONReader::ReadAndReturnError(
177 json_command, base::JSON_PARSE_RFC, nullptr, &error_message));
178 if (!value) {
Alex Vakulenkoac8037d2014-11-11 11:42:05 -0800179 response->ReplyWithError(FROM_HERE, chromeos::errors::json::kDomain,
Alex Vakulenko5c7bf012014-10-30 16:28:38 -0700180 chromeos::errors::json::kParseError,
181 error_message);
Alex Vakulenko665c8852014-09-11 16:57:24 -0700182 return;
183 }
Alex Vakulenko5c7bf012014-10-30 16:28:38 -0700184 chromeos::ErrorPtr error;
Alex Vakulenko665c8852014-09-11 16:57:24 -0700185 auto command_instance = buffet::CommandInstance::FromJson(
Alex Vakulenkof784e212015-04-20 12:33:52 -0700186 value.get(), commands::attributes::kCommand_Visibility_Local,
187 command_manager_->GetCommandDictionary(), &error);
Alex Vakulenko5c7bf012014-10-30 16:28:38 -0700188 if (!command_instance) {
189 response->ReplyWithError(error.get());
190 return;
191 }
Vitaly Buka64fc5fc2015-03-24 12:42:24 -0700192 std::string id = std::to_string(++next_id);
193 command_instance->SetID(id);
Alex Vakulenko5c7bf012014-10-30 16:28:38 -0700194 command_manager_->AddCommand(std::move(command_instance));
Vitaly Buka64fc5fc2015-03-24 12:42:24 -0700195 response->Return(id);
Alex Vakulenko665c8852014-09-11 16:57:24 -0700196}
197
Vitaly Buka3886e8f2015-03-24 11:39:40 -0700198void Manager::GetCommand(DBusMethodResponse<std::string> response,
199 const std::string& id) {
200 const CommandInstance* command = command_manager_->FindCommand(id);
201 if (!command) {
202 response->ReplyWithError(FROM_HERE, kErrorDomainGCD, "unknown_command",
203 "Can't find command with id: " + id);
204 return;
205 }
206 std::string command_str;
Nathan Bullock4b6c0fb2015-04-01 15:32:58 -0400207 base::JSONWriter::WriteWithOptions(command->ToJson().get(),
208 base::JSONWriter::OPTIONS_PRETTY_PRINT, &command_str);
Vitaly Buka3886e8f2015-03-24 11:39:40 -0700209 response->Return(command_str);
210}
211
Alex Vakulenkoe03af6d2015-04-20 11:00:54 -0700212void Manager::SetCommandVisibility(
Alex Vakulenko41f73a92015-04-24 18:09:32 -0700213 std::unique_ptr<chromeos::dbus_utils::DBusMethodResponse<>> response,
Alex Vakulenkoe03af6d2015-04-20 11:00:54 -0700214 const std::vector<std::string>& in_names,
215 const std::string& in_visibility) {
216 CommandDefinition::Visibility visibility;
217 chromeos::ErrorPtr error;
218 if (!visibility.FromString(in_visibility, &error)) {
219 response->ReplyWithError(error.get());
220 return;
221 }
222 if (!command_manager_->SetCommandVisibility(in_names, visibility, &error)) {
223 response->ReplyWithError(error.get());
224 return;
225 }
226 response->Return();
227}
228
Alex Vakulenko2348e422014-11-21 08:57:57 -0800229std::string Manager::TestMethod(const std::string& message) {
Alex Vakulenko7a1dc0b2014-08-15 11:45:46 -0700230 LOG(INFO) << "Received call to test method: " << message;
231 return message;
Christopher Wileyb76eb292014-05-05 16:09:16 -0700232}
233
Vitaly Bukafa947062015-04-17 00:41:31 -0700234bool Manager::UpdateDeviceInfo(chromeos::ErrorPtr* error,
235 const std::string& in_name,
236 const std::string& in_description,
237 const std::string& in_location) {
238 return device_info_->UpdateDeviceInfo(in_name, in_description, in_location,
239 error);
Christopher Wileyc900e482015-02-15 15:42:04 -0800240}
241
Vitaly Bukaaabadee2015-03-18 23:33:44 -0700242void Manager::OnCommandDefsChanged() {
243 chromeos::ErrorPtr error;
Alex Vakulenko9ea5a322015-04-17 15:35:34 -0700244 // Limit only to commands that are visible to the local clients.
245 auto commands = command_manager_->GetCommandDictionary().GetCommandsAsJson(
246 [](const buffet::CommandDefinition* def) {
247 return def->GetVisibility().local;
248 }, true, &error);
Vitaly Bukaaabadee2015-03-18 23:33:44 -0700249 CHECK(commands);
250 std::string json;
Nathan Bullock4b6c0fb2015-04-01 15:32:58 -0400251 base::JSONWriter::WriteWithOptions(commands.get(),
252 base::JSONWriter::OPTIONS_PRETTY_PRINT, &json);
Vitaly Bukaaabadee2015-03-18 23:33:44 -0700253 dbus_adaptor_.SetCommandDefs(json);
254}
255
Christopher Wileya4915c42014-03-27 14:45:37 -0700256} // namespace buffet