blob: a1457c4822f19384c5187ded630bfb7cc2828212 [file] [log] [blame]
Christopher Wiley4b5f04c2014-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 Vakulenko7c3226e2014-05-07 17:35:24 -07007#include <map>
8#include <string>
9
Christopher Wiley4b5f04c2014-03-27 14:45:37 -070010#include <base/bind.h>
11#include <base/bind_helpers.h>
Alex Vakulenko4f7778e2014-09-11 16:57:24 -070012#include <base/json/json_reader.h>
Christopher Wiley2ffa0042014-05-05 16:09:16 -070013#include <base/json/json_writer.h>
Christopher Wiley8994e012015-02-06 17:51:43 -080014#include <base/time/time.h>
Alex Vakulenko24e5f5d2014-08-27 11:00:57 -070015#include <chromeos/dbus/async_event_sequencer.h>
16#include <chromeos/dbus/exported_object_manager.h>
17#include <chromeos/errors/error.h>
Anton Muhin53e882a2014-11-22 05:59:14 +040018#include <chromeos/key_value_store.h>
Christopher Wiley2ffa0042014-05-05 16:09:16 -070019#include <dbus/bus.h>
Christopher Wiley54028f92014-04-01 17:33:29 -070020#include <dbus/object_path.h>
Alex Vakulenkof3d77e52014-04-15 11:36:32 -070021#include <dbus/values_util.h>
Christopher Wiley4b5f04c2014-03-27 14:45:37 -070022
Alex Vakulenko4f7778e2014-09-11 16:57:24 -070023#include "buffet/commands/command_instance.h"
Alex Vakulenkocf9c1462014-07-23 10:57:58 -070024#include "buffet/commands/command_manager.h"
Alex Vakulenkoecf961a2014-10-28 13:50:16 -070025#include "buffet/states/state_change_queue.h"
Alex Vakulenko95877b52014-09-19 15:31:09 -070026#include "buffet/states/state_manager.h"
Christopher Wiley357deca2015-02-07 18:29:32 -080027#include "buffet/storage_impls.h"
Christopher Wiley4b5f04c2014-03-27 14:45:37 -070028
Christopher Wiley68c07cc2014-07-29 14:07:10 -070029using chromeos::dbus_utils::AsyncEventSequencer;
Christopher Wiley1aa980e2014-08-11 10:51:20 -070030using chromeos::dbus_utils::ExportedObjectManager;
Christopher Wiley4b5f04c2014-03-27 14:45:37 -070031
32namespace buffet {
33
Alex Vakulenkoecf961a2014-10-28 13:50:16 -070034namespace {
35// Max of 100 state update events should be enough in the queue.
36const size_t kMaxStateChangeQueueSize = 100;
37} // anonymous namespace
38
Alex Vakulenkob6351532014-08-15 11:49:35 -070039Manager::Manager(const base::WeakPtr<ExportedObjectManager>& object_manager)
40 : dbus_object_(object_manager.get(),
41 object_manager->GetBus(),
Alex Vakulenko130edb02014-11-25 14:04:27 -080042 org::chromium::Buffet::ManagerAdaptor::GetObjectPath()) {}
Christopher Wiley4b5f04c2014-03-27 14:45:37 -070043
Alex Vakulenkoecf961a2014-10-28 13:50:16 -070044Manager::~Manager() {}
45
Christopher Wiley357deca2015-02-07 18:29:32 -080046void Manager::RegisterAsync(
47 const base::FilePath& config_path,
48 const base::FilePath& state_path,
Christopher Wileyc39f4a32015-02-12 13:42:16 -080049 const base::FilePath& test_definitions_path,
Christopher Wiley357deca2015-02-07 18:29:32 -080050 const AsyncEventSequencer::CompletionAction& cb) {
Alex Vakulenko05fa6812014-09-03 16:27:21 -070051 command_manager_ =
52 std::make_shared<CommandManager>(dbus_object_.GetObjectManager());
Christopher Wileyc39f4a32015-02-12 13:42:16 -080053 command_manager_->Startup(base::FilePath{"/etc/buffet"},
54 test_definitions_path);
Alex Vakulenkoecf961a2014-10-28 13:50:16 -070055 state_change_queue_ = std::unique_ptr<StateChangeQueue>(
56 new StateChangeQueue(kMaxStateChangeQueueSize));
57 state_manager_ = std::make_shared<StateManager>(state_change_queue_.get());
Alex Vakulenko95877b52014-09-19 15:31:09 -070058 state_manager_->Startup();
Anton Muhin53e882a2014-11-22 05:59:14 +040059 std::unique_ptr<chromeos::KeyValueStore> config_store{
Christopher Wiley357deca2015-02-07 18:29:32 -080060 new chromeos::KeyValueStore};
61 std::unique_ptr<FileStorage> state_store{new FileStorage{state_path}};
62 config_store->Load(config_path);
63 // TODO(avakulenko): Figure out security implications of storing
64 // device info state data unencrypted.
Alex Vakulenko98025c22014-07-23 11:13:15 -070065 device_info_ = std::unique_ptr<DeviceRegistrationInfo>(
Anton Muhin53e882a2014-11-22 05:59:14 +040066 new DeviceRegistrationInfo(command_manager_,
67 state_manager_,
Christopher Wiley357deca2015-02-07 18:29:32 -080068 std::move(config_store),
69 chromeos::http::Transport::CreateDefault(),
70 std::move(state_store)));
Alex Vakulenko98025c22014-07-23 11:13:15 -070071 device_info_->Load();
Christopher Wiley8994e012015-02-06 17:51:43 -080072 // Wait a significant amount of time for local daemons to publish their
73 // state to Buffet before publishing it to the cloud.
74 // TODO(wiley) We could do a lot of things here to either expose this
75 // timeout as a configurable knob or allow local
76 // daemons to signal that their state is up to date so that
77 // we need not wait for them.
78 device_info_->ScheduleStartDevice(base::TimeDelta::FromSeconds(5));
Alex Vakulenko12e2c1a2014-11-21 08:57:57 -080079 dbus_adaptor_.RegisterWithDBusObject(&dbus_object_);
80 dbus_object_.RegisterAsync(cb);
Christopher Wiley4b5f04c2014-03-27 14:45:37 -070081}
82
Alex Vakulenko12e2c1a2014-11-21 08:57:57 -080083void Manager::StartDevice(DBusMethodResponse<> response) {
Anton Muhin914b1382014-10-01 18:06:54 +040084 LOG(INFO) << "Received call to Manager.StartDevice()";
Anton Muhindd6d8282014-10-02 20:37:00 +040085
Alex Vakulenkob91dcfe2014-10-30 16:28:38 -070086 chromeos::ErrorPtr error;
87 device_info_->StartDevice(&error);
88 if (error)
89 response->ReplyWithError(error.get());
90 else
91 response->Return();
Anton Muhin914b1382014-10-01 18:06:54 +040092}
93
Alex Vakulenko12e2c1a2014-11-21 08:57:57 -080094void Manager::CheckDeviceRegistered(DBusMethodResponse<std::string> response) {
Alex Vakulenkof3d77e52014-04-15 11:36:32 -070095 LOG(INFO) << "Received call to Manager.CheckDeviceRegistered()";
Alex Vakulenkob91dcfe2014-10-30 16:28:38 -070096 chromeos::ErrorPtr error;
97 bool registered = device_info_->CheckRegistration(&error);
Alex Vakulenko7c3226e2014-05-07 17:35:24 -070098 // If it fails due to any reason other than 'device not registered',
99 // treat it as a real error and report it to the caller.
100 if (!registered &&
Alex Vakulenkob91dcfe2014-10-30 16:28:38 -0700101 !error->HasError(kErrorDomainGCD, "device_not_registered")) {
102 response->ReplyWithError(error.get());
103 return;
Alex Vakulenko7c3226e2014-05-07 17:35:24 -0700104 }
Christopher Wiley4b5f04c2014-03-27 14:45:37 -0700105
Alex Vakulenkob91dcfe2014-10-30 16:28:38 -0700106 std::string device_id;
107 if (registered) {
108 error.reset();
109 device_id = device_info_->GetDeviceId(&error);
110 if (error) {
111 response->ReplyWithError(error.get());
112 return;
113 }
114 }
Alex Vakulenkob6351532014-08-15 11:49:35 -0700115
Alex Vakulenkob91dcfe2014-10-30 16:28:38 -0700116 response->Return(device_id);
Alex Vakulenkof3d77e52014-04-15 11:36:32 -0700117}
118
Alex Vakulenko12e2c1a2014-11-21 08:57:57 -0800119void Manager::GetDeviceInfo(DBusMethodResponse<std::string> response) {
Alex Vakulenkof3d77e52014-04-15 11:36:32 -0700120 LOG(INFO) << "Received call to Manager.GetDeviceInfo()";
121
Alex Vakulenkob91dcfe2014-10-30 16:28:38 -0700122 chromeos::ErrorPtr error;
123 auto device_info = device_info_->GetDeviceInfo(&error);
124 if (!device_info) {
125 response->ReplyWithError(error.get());
126 return;
127 }
Alex Vakulenko7c3226e2014-05-07 17:35:24 -0700128
Alex Vakulenkob91dcfe2014-10-30 16:28:38 -0700129 std::string device_info_str;
Alex Vakulenko7c3226e2014-05-07 17:35:24 -0700130 base::JSONWriter::Write(device_info.get(), &device_info_str);
Alex Vakulenkob91dcfe2014-10-30 16:28:38 -0700131 response->Return(device_info_str);
Alex Vakulenkof3d77e52014-04-15 11:36:32 -0700132}
133
Alex Vakulenko12e2c1a2014-11-21 08:57:57 -0800134void Manager::RegisterDevice(DBusMethodResponse<std::string> response,
135 const chromeos::VariantDictionary& params) {
Anton Muhin9cc03fd2014-10-16 18:59:57 +0400136 LOG(INFO) << "Received call to Manager.RegisterDevice()";
Alex Vakulenkof3d77e52014-04-15 11:36:32 -0700137
Alex Vakulenkob91dcfe2014-10-30 16:28:38 -0700138 chromeos::ErrorPtr error;
Alex Vakulenko12e2c1a2014-11-21 08:57:57 -0800139 std::map<std::string, std::string> str_params;
140 for (const auto& pair : params) {
141 if (!pair.second.IsTypeCompatible<std::string>()) {
142 response->ReplyWithError(FROM_HERE, chromeos::errors::dbus::kDomain,
143 DBUS_ERROR_INVALID_ARGS,
144 "String value expected");
145 return;
146 }
147 str_params.emplace_hint(str_params.end(),
148 pair.first, pair.second.Get<std::string>());
149 }
150 std::string device_id = device_info_->RegisterDevice(str_params, &error);
David Zeuthen2101c082015-02-12 15:24:21 -0500151 if (!device_id.empty()) {
Alex Vakulenkob91dcfe2014-10-30 16:28:38 -0700152 response->Return(device_id);
David Zeuthen2101c082015-02-12 15:24:21 -0500153 return;
154 }
155 if (!error) {
156 // TODO(zeuthen): This can be changed to CHECK(error) once
157 // RegisterDevice() has been fixed to set |error| when failing.
158 chromeos::Error::AddTo(&error, FROM_HERE, kErrorDomainGCD,
159 "internal_error",
160 "device_id empty but error not set");
161 }
162 response->ReplyWithError(error.get());
Christopher Wiley4b5f04c2014-03-27 14:45:37 -0700163}
164
Alex Vakulenko12e2c1a2014-11-21 08:57:57 -0800165void Manager::UpdateState(DBusMethodResponse<> response,
166 const chromeos::VariantDictionary& property_set) {
Alex Vakulenkob91dcfe2014-10-30 16:28:38 -0700167 chromeos::ErrorPtr error;
Alex Vakulenkobfc70ad2014-10-29 09:53:52 -0700168 base::Time timestamp = base::Time::Now();
Alex Vakulenkob91dcfe2014-10-30 16:28:38 -0700169 bool all_success = true;
Alex Vakulenkobfc70ad2014-10-29 09:53:52 -0700170 for (const auto& pair : property_set) {
Alex Vakulenkob91dcfe2014-10-30 16:28:38 -0700171 if (!state_manager_->SetPropertyValue(pair.first, pair.second,
172 timestamp, &error)) {
173 // Remember that an error occurred but keep going and update the rest of
174 // the properties if possible.
175 all_success = false;
176 }
Alex Vakulenkobfc70ad2014-10-29 09:53:52 -0700177 }
Alex Vakulenkob91dcfe2014-10-30 16:28:38 -0700178 if (!all_success)
179 response->ReplyWithError(error.get());
180 else
181 response->Return();
Christopher Wiley4b5f04c2014-03-27 14:45:37 -0700182}
183
Alex Vakulenkoceab1772015-01-20 10:50:04 -0800184bool Manager::GetState(chromeos::ErrorPtr* error, std::string* state) {
185 auto json = state_manager_->GetStateValuesAsJson(error);
186 if (!json)
187 return false;
188 base::JSONWriter::Write(json.get(), state);
189 return true;
190}
191
Alex Vakulenko12e2c1a2014-11-21 08:57:57 -0800192void Manager::AddCommand(DBusMethodResponse<> response,
193 const std::string& json_command) {
Anton Muhind014d8b2014-10-30 17:49:48 +0400194 static int next_id = 0;
Alex Vakulenko4f7778e2014-09-11 16:57:24 -0700195 std::string error_message;
196 std::unique_ptr<base::Value> value(base::JSONReader::ReadAndReturnError(
197 json_command, base::JSON_PARSE_RFC, nullptr, &error_message));
198 if (!value) {
Alex Vakulenko90b3da92014-11-11 11:42:05 -0800199 response->ReplyWithError(FROM_HERE, chromeos::errors::json::kDomain,
Alex Vakulenkob91dcfe2014-10-30 16:28:38 -0700200 chromeos::errors::json::kParseError,
201 error_message);
Alex Vakulenko4f7778e2014-09-11 16:57:24 -0700202 return;
203 }
Alex Vakulenkob91dcfe2014-10-30 16:28:38 -0700204 chromeos::ErrorPtr error;
Alex Vakulenko4f7778e2014-09-11 16:57:24 -0700205 auto command_instance = buffet::CommandInstance::FromJson(
Alex Vakulenkob91dcfe2014-10-30 16:28:38 -0700206 value.get(), command_manager_->GetCommandDictionary(), &error);
207 if (!command_instance) {
208 response->ReplyWithError(error.get());
209 return;
210 }
Anton Muhind014d8b2014-10-30 17:49:48 +0400211 command_instance->SetID(std::to_string(++next_id));
Alex Vakulenkob91dcfe2014-10-30 16:28:38 -0700212 command_manager_->AddCommand(std::move(command_instance));
213 response->Return();
Alex Vakulenko4f7778e2014-09-11 16:57:24 -0700214}
215
Alex Vakulenko12e2c1a2014-11-21 08:57:57 -0800216std::string Manager::TestMethod(const std::string& message) {
Alex Vakulenko35e3bab2014-08-15 11:45:46 -0700217 LOG(INFO) << "Received call to test method: " << message;
218 return message;
Christopher Wiley2ffa0042014-05-05 16:09:16 -0700219}
220
Christopher Wiley4b5f04c2014-03-27 14:45:37 -0700221} // namespace buffet