PolicyManager: New main PolicyManager class.
The PolicyManager class is the singleton instance used by the Update
Engine to make policy requests. The PolicyManager uses a Policy pure
virtual class with the definition of all the public policy
implementation. Different platforms can implement a different
subclass of it or extend the existing one.
The Policy class comprises the set of policy related decision and
the logic implementing those.
This patch includes a new PolicyManager class and a sample Policy
for ChromeOS that will be extended when the actual policies are
migrated to this framework. A default policy is also included and
is used whenever the actual policy fails, as a safe default.
BUG=chromium:338591
TEST=Unit tests pass.
Change-Id: If60c87d8cb9031eb15b6d4d5e937f65f56c79a04
Reviewed-on: https://chromium-review.googlesource.com/186884
Tested-by: Alex Deymo <deymo@chromium.org>
Reviewed-by: Gilad Arnold <garnold@chromium.org>
Commit-Queue: Alex Deymo <deymo@chromium.org>
diff --git a/SConstruct b/SConstruct
index 9a9f007..4bd8f31 100644
--- a/SConstruct
+++ b/SConstruct
@@ -238,6 +238,8 @@
p2p_manager.cc
payload_signer.cc
payload_state.cc
+ policy_manager/chromeos_policy.cc
+ policy_manager/policy_manager.cc
policy_manager/real_random_provider.cc
policy_manager/evaluation_context.cc
policy_manager/real_shill_provider.cc
@@ -293,6 +295,7 @@
policy_manager/boxed_value_unittest.cc
policy_manager/evaluation_context_unittest.cc
policy_manager/generic_variables_unittest.cc
+ policy_manager/policy_manager_unittest.cc
policy_manager/real_random_provider_unittest.cc
policy_manager/real_shill_provider_unittest.cc
policy_manager/variable_unittest.cc
diff --git a/policy_manager/chromeos_policy.cc b/policy_manager/chromeos_policy.cc
new file mode 100644
index 0000000..4588053
--- /dev/null
+++ b/policy_manager/chromeos_policy.cc
@@ -0,0 +1,21 @@
+// Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <string>
+
+#include "update_engine/policy_manager/chromeos_policy.h"
+
+using std::string;
+
+namespace chromeos_policy_manager {
+
+EvalStatus ChromeOSPolicy::UpdateCheckAllowed(EvaluationContext* ec,
+ string* error,
+ bool* result) const {
+ // TODO(deymo): Write this policy implementation with the actual policy.
+ *result = true;
+ return EvalStatusSucceeded;
+}
+
+} // namespace chromeos_policy_manager
diff --git a/policy_manager/chromeos_policy.h b/policy_manager/chromeos_policy.h
new file mode 100644
index 0000000..1247d93
--- /dev/null
+++ b/policy_manager/chromeos_policy.h
@@ -0,0 +1,29 @@
+// Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROMEOS_PLATFORM_UPDATE_ENGINE_POLICY_MANAGER_CHROMEOS_POLICY_H
+#define CHROMEOS_PLATFORM_UPDATE_ENGINE_POLICY_MANAGER_CHROMEOS_POLICY_H
+
+#include "update_engine/policy_manager/policy.h"
+
+namespace chromeos_policy_manager {
+
+// ChromeOSPolicy implements the policy-related logic used in ChromeOS.
+class ChromeOSPolicy : public Policy {
+ public:
+ ChromeOSPolicy() {}
+ virtual ~ChromeOSPolicy() {}
+
+ // Policy overrides.
+ virtual EvalStatus UpdateCheckAllowed(EvaluationContext* ec,
+ std::string* error,
+ bool* result) const;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ChromeOSPolicy);
+};
+
+} // namespace chromeos_policy_manager
+
+#endif // CHROMEOS_PLATFORM_UPDATE_ENGINE_POLICY_MANAGER_CHROMEOS_POLICY_H
diff --git a/policy_manager/default_policy.h b/policy_manager/default_policy.h
new file mode 100644
index 0000000..1d10084
--- /dev/null
+++ b/policy_manager/default_policy.h
@@ -0,0 +1,34 @@
+// Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROMEOS_PLATFORM_UPDATE_ENGINE_POLICY_MANAGER_DEFAULT_POLICY_H
+#define CHROMEOS_PLATFORM_UPDATE_ENGINE_POLICY_MANAGER_DEFAULT_POLICY_H
+
+#include "update_engine/policy_manager/policy.h"
+
+namespace chromeos_policy_manager {
+
+// The DefaultPolicy is a safe Policy implementation that doesn't fail. The
+// values returned by this policy are safe default in case of failure of the
+// actual policy being used by the PolicyManager.
+class DefaultPolicy : public Policy {
+ public:
+ DefaultPolicy() {}
+ virtual ~DefaultPolicy() {}
+
+ // Policy overrides.
+ virtual EvalStatus UpdateCheckAllowed(EvaluationContext* ec,
+ std::string* error,
+ bool* result) const {
+ *result = true;
+ return EvalStatusSucceeded;
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(DefaultPolicy);
+};
+
+} // namespace chromeos_policy_manager
+
+#endif // CHROMEOS_PLATFORM_UPDATE_ENGINE_POLICY_MANAGER_DEFAULT_POLICY_H
diff --git a/policy_manager/mock_policy.h b/policy_manager/mock_policy.h
new file mode 100644
index 0000000..744dff1
--- /dev/null
+++ b/policy_manager/mock_policy.h
@@ -0,0 +1,30 @@
+// Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROMEOS_PLATFORM_UPDATE_ENGINE_POLICY_MANAGER_MOCK_POLICY_H
+#define CHROMEOS_PLATFORM_UPDATE_ENGINE_POLICY_MANAGER_MOCK_POLICY_H
+
+#include <gmock/gmock.h>
+
+#include "update_engine/policy_manager/policy.h"
+
+namespace chromeos_policy_manager {
+
+// A mocked implementation of Policy.
+class MockPolicy : public Policy {
+public:
+ MockPolicy() {}
+ virtual ~MockPolicy() {}
+
+ // Policy overrides.
+ MOCK_CONST_METHOD3(UpdateCheckAllowed,
+ EvalStatus(EvaluationContext*, std::string*, bool*));
+
+private:
+ DISALLOW_COPY_AND_ASSIGN(MockPolicy);
+};
+
+} // namespace chromeos_policy_manager
+
+#endif // CHROMEOS_PLATFORM_UPDATE_ENGINE_POLICY_MANAGER_MOCK_POLICY_H
diff --git a/policy_manager/policy.h b/policy_manager/policy.h
new file mode 100644
index 0000000..b4a5a1e
--- /dev/null
+++ b/policy_manager/policy.h
@@ -0,0 +1,51 @@
+// Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROMEOS_PLATFORM_UPDATE_ENGINE_POLICY_MANAGER_POLICY_H
+#define CHROMEOS_PLATFORM_UPDATE_ENGINE_POLICY_MANAGER_POLICY_H
+
+#include "update_engine/policy_manager/evaluation_context.h"
+
+namespace chromeos_policy_manager {
+
+// The three different results of a policy request.
+enum EvalStatus {
+ EvalStatusFailed,
+ EvalStatusSucceeded,
+ EvalStatusAskMeAgainLater,
+};
+
+// The Policy class is an interface to the ensemble of policy requests that the
+// client can make. A derived class includes the policy implementations of
+// these.
+//
+// When compile-time selection of the policy is required due to missing or extra
+// parts in a given platform, a different Policy subclass can be used.
+class Policy {
+ public:
+ virtual ~Policy() {}
+
+ // List of policy requests. A policy request takes an EvaluationContext as the
+ // first argument, a returned error message, a returned value and optionally
+ // followed by one or more arbitrary constant arguments.
+ //
+ // When the implementation fails, the method returns EvalStatusFailed and sets
+ // the |error| string.
+
+ // UpdateCheckAllowed returns whether it is allowed to request an update check
+ // to Omaha.
+ virtual EvalStatus UpdateCheckAllowed(EvaluationContext* ec,
+ std::string* error,
+ bool* result) const = 0;
+
+ protected:
+ Policy() {}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(Policy);
+};
+
+} // namespace chromeos_policy_manager
+
+#endif // CHROMEOS_PLATFORM_UPDATE_ENGINE_POLICY_MANAGER_POLICY_H
diff --git a/policy_manager/policy_manager-inl.h b/policy_manager/policy_manager-inl.h
new file mode 100644
index 0000000..6c99be2
--- /dev/null
+++ b/policy_manager/policy_manager-inl.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROMEOS_PLATFORM_UPDATE_ENGINE_POLICY_MANAGER_POLICY_MANAGER_INL_H
+#define CHROMEOS_PLATFORM_UPDATE_ENGINE_POLICY_MANAGER_POLICY_MANAGER_INL_H
+
+#include "update_engine/policy_manager/evaluation_context.h"
+
+namespace chromeos_policy_manager {
+
+// Provider of random values.
+template<typename T, typename R, typename... Args>
+EvalStatus PolicyManager::PolicyRequest(T policy_method, R* result,
+ Args... args) {
+ EvaluationContext ec;
+ std::string error;
+
+ // First try calling the actual policy.
+ EvalStatus status = (policy_.get()->*policy_method)(&ec, &error, result,
+ args...);
+
+ if (status == EvalStatusFailed) {
+ LOG(WARNING) << "PolicyRequest() failed with error: " << error;
+ error.clear();
+ status = (default_policy_.*policy_method)(&ec, &error, result, args...);
+
+ if (status == EvalStatusFailed) {
+ LOG(WARNING) << "Request to DefaultPolicy also failed, passing error.";
+ }
+ }
+ // TODO(deymo): Log the actual state used from the EvaluationContext.
+ return status;
+}
+
+} // namespace chromeos_policy_manager
+
+#endif // CHROMEOS_PLATFORM_UPDATE_ENGINE_POLICY_MANAGER_POLICY_MANAGER_INL_H
diff --git a/policy_manager/policy_manager.cc b/policy_manager/policy_manager.cc
new file mode 100644
index 0000000..6bfbd0e
--- /dev/null
+++ b/policy_manager/policy_manager.cc
@@ -0,0 +1,31 @@
+// Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "update_engine/policy_manager/chromeos_policy.h"
+#include "update_engine/policy_manager/policy_manager.h"
+#include "update_engine/policy_manager/real_random_provider.h"
+
+namespace chromeos_policy_manager {
+
+template <typename T>
+bool InitProvider(scoped_ptr<T>* handle_ptr, T* provider) {
+ handle_ptr->reset(provider);
+ return handle_ptr->get() && (*handle_ptr)->Init();
+}
+
+bool PolicyManager::Init() {
+ // TODO(deymo): Make it possible to replace this policy with a different
+ // implementation with a build-time flag.
+ policy_.reset(new ChromeOSPolicy());
+
+ bool result = true;
+
+ // Initialize all the providers.
+ result = result && InitProvider<RandomProvider>(&random_,
+ new RealRandomProvider());
+
+ return result;
+}
+
+} // namespace chromeos_policy_manager
diff --git a/policy_manager/policy_manager.h b/policy_manager/policy_manager.h
new file mode 100644
index 0000000..d952899
--- /dev/null
+++ b/policy_manager/policy_manager.h
@@ -0,0 +1,68 @@
+// Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROMEOS_PLATFORM_UPDATE_ENGINE_POLICY_MANAGER_POLICY_MANAGER_H
+#define CHROMEOS_PLATFORM_UPDATE_ENGINE_POLICY_MANAGER_POLICY_MANAGER_H
+
+#include <base/memory/scoped_ptr.h>
+
+#include "update_engine/policy_manager/default_policy.h"
+#include "update_engine/policy_manager/policy.h"
+#include "update_engine/policy_manager/random_provider.h"
+
+namespace chromeos_policy_manager {
+
+// The main Policy Manager singleton class.
+class PolicyManager {
+ public:
+ PolicyManager() {}
+
+ // Initializes the PolicyManager instance. Returns whether the initialization
+ // succeeded.
+ bool Init();
+
+ // PolicyRequest() evaluates the given policy with the provided arguments and
+ // returns the result. The |policy_method| is the pointer-to-method of the
+ // Policy class for the policy request to call. The PolicyManager will call
+ // this method on the right policy. The pointer |result| must not be NULL and
+ // the remaining |args| depend on the arguments required by the passed
+ // |policy_method|.
+ //
+ // When the policy request succeeds, the |result| is set and the method
+ // returns EvalStatusSucceeded, otherwise, the |result| may not be set. Also,
+ // if the policy implementation should block, this method returns immediately
+ // with EvalStatusAskMeAgainLater. In case of failure EvalStatusFailed is
+ // returned and the |error| message is set, which must not be NULL.
+ //
+ // An example call to this method is:
+ // pm.PolicyRequest(&Policy::SomePolicyMethod, &bool_result, arg1, arg2);
+ template<typename T, typename R, typename... Args>
+ EvalStatus PolicyRequest(T policy_method , R* result, Args... args);
+
+ private:
+ friend class PmPolicyManagerTest;
+ FRIEND_TEST(PmPolicyManagerTest, PolicyRequestCallsPolicy);
+ FRIEND_TEST(PmPolicyManagerTest, PolicyRequestCallsDefaultOnError);
+ FRIEND_TEST(PmPolicyManagerTest, PolicyRequestDoesntBlock);
+
+ // The policy used by the PolicyManager. Note that since it is a const Policy,
+ // policy implementations are not allowed to persist state on this class.
+ scoped_ptr<const Policy> policy_;
+
+ // A safe default value to the current policy. This policy is used whenever
+ // a policy implementation fails with EvalStatusFailed.
+ const DefaultPolicy default_policy_;
+
+ // Providers.
+ scoped_ptr<RandomProvider> random_;
+
+ DISALLOW_COPY_AND_ASSIGN(PolicyManager);
+};
+
+} // namespace chromeos_policy_manager
+
+// Include the implementation of the template methods.
+#include "update_engine/policy_manager/policy_manager-inl.h"
+
+#endif // CHROMEOS_PLATFORM_UPDATE_ENGINE_POLICY_MANAGER_POLICY_MANAGER_H
diff --git a/policy_manager/policy_manager_unittest.cc b/policy_manager/policy_manager_unittest.cc
new file mode 100644
index 0000000..dc906f1
--- /dev/null
+++ b/policy_manager/policy_manager_unittest.cc
@@ -0,0 +1,92 @@
+// Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <base/memory/scoped_ptr.h>
+#include <base/time.h>
+#include <gtest/gtest.h>
+#include <gmock/gmock.h>
+#include <string>
+
+#include "update_engine/policy_manager/default_policy.h"
+#include "update_engine/policy_manager/mock_policy.h"
+#include "update_engine/policy_manager/pmtest_utils.h"
+#include "update_engine/policy_manager/policy_manager.h"
+
+using base::TimeDelta;
+using std::string;
+
+using testing::_;
+using testing::Return;
+using testing::StrictMock;
+
+namespace chromeos_policy_manager {
+
+class PmPolicyManagerTest : public ::testing::Test {
+ protected:
+ virtual void SetUp() {
+ EXPECT_TRUE(pmut_.Init());
+ }
+
+ PolicyManager pmut_; // PolicyManager undert test.
+};
+
+// The FailingPolicy implements a single method and make it always fail. This
+// class extends the DefaultPolicy class to allow extensions of the Policy
+// class without extending nor changing this test.
+class FailingPolicy : public DefaultPolicy {
+ virtual EvalStatus UpdateCheckAllowed(EvaluationContext* ec,
+ string* error,
+ bool* result) const {
+ *error = "FailingPolicy failed.";
+ return EvalStatusFailed;
+ }
+};
+
+// The LazyPolicy always returns
+class LazyPolicy : public DefaultPolicy {
+ virtual EvalStatus UpdateCheckAllowed(EvaluationContext* ec,
+ string* error,
+ bool* result) const {
+ return EvalStatusAskMeAgainLater;
+ }
+};
+
+TEST_F(PmPolicyManagerTest, PolicyRequestCall) {
+ bool result;
+ EvalStatus status = pmut_.PolicyRequest(&Policy::UpdateCheckAllowed, &result);
+ EXPECT_EQ(status, EvalStatusSucceeded);
+}
+
+TEST_F(PmPolicyManagerTest, PolicyRequestCallsPolicy) {
+ StrictMock<MockPolicy>* policy = new StrictMock<MockPolicy>();
+ pmut_.policy_.reset(policy);
+ bool result;
+
+ // Tests that the method is called on the policy_ instance.
+ EXPECT_CALL(*policy, UpdateCheckAllowed(_, _, _))
+ .WillOnce(Return(EvalStatusSucceeded));
+ EvalStatus status = pmut_.PolicyRequest(&Policy::UpdateCheckAllowed, &result);
+ EXPECT_EQ(status, EvalStatusSucceeded);
+}
+
+TEST_F(PmPolicyManagerTest, PolicyRequestCallsDefaultOnError) {
+ pmut_.policy_.reset(new FailingPolicy());
+
+ // Tests that the DefaultPolicy instance is called when the method fails,
+ // which will set this as true.
+ bool result = false;
+ EvalStatus status = pmut_.PolicyRequest(&Policy::UpdateCheckAllowed, &result);
+ EXPECT_EQ(status, EvalStatusSucceeded);
+ EXPECT_TRUE(result);
+}
+
+TEST_F(PmPolicyManagerTest, PolicyRequestDoesntBlock) {
+ pmut_.policy_.reset(new LazyPolicy());
+ bool result;
+
+ EvalStatus status = pmut_.PolicyRequest(&Policy::UpdateCheckAllowed, &result);
+ EXPECT_EQ(status, EvalStatusAskMeAgainLater);
+}
+
+} // namespace chromeos_policy_manager