| #ifndef THIRD_PARTY_MILOTIC_INTERNAL_CC_PROXY_PROXY_BUILDER_H_ |
| #define THIRD_PARTY_MILOTIC_INTERNAL_CC_PROXY_PROXY_BUILDER_H_ |
| |
| #include <cstddef> |
| #include <functional> |
| #include <list> |
| #include <memory> |
| #include <string> |
| #include <utility> |
| #include <vector> |
| |
| #include "absl/functional/any_invocable.h" |
| #include "absl/status/status.h" |
| #include "absl/status/statusor.h" |
| #include "redfish_query_engine/file/uds.h" |
| #include "grpcpp/security/authorization_policy_provider.h" |
| #include "proxy.h" |
| #include "proxy_config.pb.h" |
| #include "redfish_plugin.h" |
| #include "resource_authz.h" |
| #include "ssh_client.h" |
| #include "voyager/deferrable_priority_queue.hpp" |
| #include "voyager/priority_queue.hpp" |
| |
| namespace milotic { |
| |
| namespace internal { |
| absl::StatusOr<milotic_grpc_proxy::Configuration> LoadConfig( |
| const std::string& config_file_path); |
| } // namespace internal |
| |
| // A PluginFactory is a wrapper to register factory functions for plugins so |
| // that they can be linked to configuration items. Each plugin should have a |
| // corresponding configuration field in the milotic_grpc_proxy.Plugin message. |
| // The plugin should also create a static PluginFactory with a function that |
| // creates an instance of the plugin using the `Plugin` configuration proto. |
| // Usually, this is done using REGISTER_REDFISH_PLUGIN with the appropriate |
| // template parameters indicating the proto field and plugin type. See |
| // test_plugin.cc for an example. |
| class PluginFactory { |
| public: |
| using FactoryFn = std::function<std::unique_ptr<RedfishPlugin>( |
| const milotic_grpc_proxy::Plugin&)>; |
| // The constructor is not thread-safe. PluginFactory objects should usually be |
| // global statics, so they are initialized in the same thread. |
| explicit PluginFactory(FactoryFn&& f) { |
| GetFunctionList().push_back(std::move(f)); |
| } |
| |
| PluginFactory(const PluginFactory&) = delete; |
| |
| static std::unique_ptr<RedfishPlugin> CreatePlugin( |
| const milotic_grpc_proxy::Plugin& plugin); |
| |
| // TODO(shounak): This is much cleaner with static proto reflection, but that |
| // is not yet available in OSS. |
| template <auto Get, auto Has, typename PluginType> |
| static std::unique_ptr<RedfishPlugin> Default( |
| const milotic_grpc_proxy::Plugin& plugin_conf) { |
| if (!(plugin_conf.*Has)()) return nullptr; |
| return std::make_unique<PluginType>((plugin_conf.*Get)()); |
| } |
| |
| private: |
| static std::vector<FactoryFn>& GetFunctionList() { |
| static std::vector<FactoryFn> list; |
| return list; |
| } |
| }; |
| |
| #define REGISTER_REDFISH_PLUGIN(_name, _type) \ |
| ::milotic::PluginFactory _name##_plugin_factory( \ |
| ::milotic::PluginFactory::Default< \ |
| &::milotic_grpc_proxy::Plugin::_name, \ |
| &::milotic_grpc_proxy::Plugin::has_##_name, _type>) |
| |
| class ProxyBuilder { |
| public: |
| struct Options { |
| using ExecutorFactory = |
| absl::AnyInvocable<std::unique_ptr<voyager::Executor>( |
| const milotic_grpc_proxy::QueueOptions& options) const>; |
| using PermissionCheckerFactory = |
| absl::AnyInvocable<std::unique_ptr<PermissionChecker>() const>; |
| Options() : is_safe_uds_root(ecclesia::IsSafeUnixDomainSocketRoot) {} |
| Options& SafeUdsRoot( |
| std::function<bool(const std::string&)> new_is_safe_uds_root) { |
| is_safe_uds_root = new_is_safe_uds_root; |
| return *this; |
| } |
| Options& AddCredentials(Proxy::GrpcCredentials creds) { |
| credentials.push_back(std::move(creds)); |
| return *this; |
| } |
| Options& AddAuthorizationPolicy( |
| std::shared_ptr< |
| grpc::experimental::AuthorizationPolicyProviderInterface> |
| provider) { |
| authorization_providers.push_back(std::move(provider)); |
| return *this; |
| } |
| template <typename SshClientType> |
| Options& SetSshClientType() { |
| ssh_client_factory = SshClientType::Create; |
| return *this; |
| } |
| Options& SetExecutorFactory(ExecutorFactory new_executor_factory) { |
| executor_factory = std::move(new_executor_factory); |
| return *this; |
| } |
| Options& SetPermissionCheckerFactory( |
| PermissionCheckerFactory new_permission_checker_factory) { |
| permission_checker_factory = std::move(new_permission_checker_factory); |
| return *this; |
| } |
| std::function<bool(const std::string&)> is_safe_uds_root; |
| std::vector<Proxy::GrpcCredentials> credentials; |
| std::vector<std::shared_ptr< |
| grpc::experimental::AuthorizationPolicyProviderInterface>> |
| authorization_providers; |
| absl::AnyInvocable<absl::StatusOr<std::unique_ptr<SshClient>>( |
| SshClient::CreationOptions options) const> |
| ssh_client_factory; |
| ExecutorFactory executor_factory = |
| [](const milotic_grpc_proxy::QueueOptions& options) { |
| return std::make_unique<voyager::DefaultExecutor>(); |
| }; |
| PermissionCheckerFactory permission_checker_factory; |
| }; |
| |
| ProxyBuilder(const ProxyBuilder&) = delete; |
| ProxyBuilder& operator=(const ProxyBuilder&) = delete; |
| // Movable to support factory functions |
| ProxyBuilder(ProxyBuilder&&) = default; |
| |
| static absl::StatusOr<ProxyBuilder> CreateAndStart( |
| const milotic_grpc_proxy::Configuration& config, |
| const Options& options = Options()); |
| |
| static absl::StatusOr<ProxyBuilder> CreateAndStart( |
| const std::string& config_file_path, const Options& options = Options()); |
| |
| ~ProxyBuilder(); |
| absl::Status Wait(); |
| void Shutdown(); |
| |
| const voyager::DeferrablePriorityQueue& queue() const { return *queue_; } |
| |
| private: |
| ProxyBuilder(size_t queue_size, int quantum, |
| std::unique_ptr<voyager::Executor> executor) |
| : queue_(std::make_unique<voyager::DeferrablePriorityQueue>( |
| queue_size, std::move(executor))), |
| quantum_(quantum) {} |
| |
| absl::Status AddProxy( |
| const milotic_grpc_proxy::ProxyConfiguration& proxy_config, |
| const Options& options); |
| |
| std::list<Proxy> proxies_; |
| std::unique_ptr<voyager::DeferrablePriorityQueue> queue_; |
| int quantum_; |
| }; |
| |
| } // namespace milotic |
| #endif // THIRD_PARTY_MILOTIC_INTERNAL_CC_PROXY_PROXY_BUILDER_H_ |