about summary refs log tree commit diff
path: root/ops/yandex-cloud-rs/src/lib.rs
diff options
context:
space:
mode:
authorVincent Ambo <mail@tazj.in>2023-04-25T00·08+0300
committertazjin <tazjin@tvl.su>2023-04-28T12·50+0000
commitea1383682df4d308c21e11baed9b4172865a68e0 (patch)
tree6b0a1d5b657d02e3f02335a0be6c84c9a3194713 /ops/yandex-cloud-rs/src/lib.rs
parentf1ca5a3096a3805a9bb9b58ca9a243657d3dd5d4 (diff)
feat(ops/yandex-cloud-rs): generated gRPC clients for Yandex Cloud r/6116
This uses tonic to generate the full set of gRPC clients for Yandex
Cloud. Includes some utility functions like an authentication
interceptor to make these actually work.

Since the upstream protos are exported regularly I've decided that the
versioning will simply be date-based.

The point of this is journaldriver integration, of course, hence also
the log-centric example code.

Change-Id: I00a615dcba80030e7f9bcfd476b2cfdb298f130d
Reviewed-on: https://cl.tvl.fyi/c/depot/+/8525
Tested-by: BuildkiteCI
Reviewed-by: tazjin <tazjin@tvl.su>
Diffstat (limited to 'ops/yandex-cloud-rs/src/lib.rs')
-rw-r--r--ops/yandex-cloud-rs/src/lib.rs95
1 files changed, 95 insertions, 0 deletions
diff --git a/ops/yandex-cloud-rs/src/lib.rs b/ops/yandex-cloud-rs/src/lib.rs
new file mode 100644
index 000000000000..6b1425bc9e98
--- /dev/null
+++ b/ops/yandex-cloud-rs/src/lib.rs
@@ -0,0 +1,95 @@
+//! This module provides low-level generated gRPC clients for the
+//! Yandex Cloud APIs.
+//!
+//! The clients are generated using the [tonic][] and [prost][]
+//! crates and have default configuration.
+//!
+//! Documentation present in the protos is retained into the generated
+//! Rust types, but for detailed API information you should visit the
+//! official Yandex Cloud Documentation pages:
+//!
+//! * [in English](https://cloud.yandex.com/en-ru/docs/overview/api)
+//! * [in Russian](https://cloud.yandex.ru/docs/overview/api)
+//!
+//! The proto sources are available on the [Yandex Cloud GitHub][protos].
+//!
+//! [tonic]: https://docs.rs/tonic/latest/tonic/
+//! [prost]: https://docs.rs/prost/latest/prost/
+//! [protos]: https://github.com/yandex-cloud/cloudapi
+//!
+//! The majority of user-facing structures can be found in the
+//! [`yandex::cloud`] module.
+//!
+//! ## Usage
+//!
+//! Typically to use these APIs, you need to provide an authentication
+//! credential and an endpoint to connect to. The full list of
+//! Yandex's endpoints is [available online][endpoints] and you should
+//! look up the service you plan to use and pick the correct endpoint
+//! from the list.
+//!
+//! Authentication is done via an HTTP header using an IAM token,
+//! which can be done in Tonic using [interceptors][]. The
+//! [`AuthInterceptor`] provided by this crate can be used for that
+//! purpose.
+//!
+//! [endpoints]: https://cloud.yandex.com/en/docs/api-design-guide/concepts/endpoints
+//! [interceptors]: https://docs.rs/tonic/latest/tonic/service/trait.Interceptor.html
+
+use tonic::metadata::{Ascii, MetadataValue};
+use tonic::service::Interceptor;
+
+/// Helper trait for types or closures that can provide authentication
+/// tokens for Yandex Cloud.
+pub trait TokenProvider {
+    /// Fetch a currently valid authentication token for Yandex Cloud.
+    fn get_token<'a>(&'a mut self) -> &'a str;
+}
+
+impl TokenProvider for String {
+    fn get_token<'a>(&'a mut self) -> &'a str {
+        self.as_str()
+    }
+}
+
+impl TokenProvider for &'static str {
+    fn get_token(&mut self) -> &'static str {
+        *self
+    }
+}
+
+/// Interceptor for adding authentication headers to gRPC requests.
+/// This is constructed with a callable that returns authentication
+/// tokens.
+///
+/// This callable is responsible for ensuring that the returned tokens
+/// are valid at the given time, i.e. it should take care of
+/// refreshing and so on.
+pub struct AuthInterceptor<T: TokenProvider> {
+    token_provider: T,
+}
+
+impl<T: TokenProvider> AuthInterceptor<T> {
+    pub fn new(token_provider: T) -> Self {
+        Self { token_provider }
+    }
+}
+
+impl<T: TokenProvider> Interceptor for AuthInterceptor<T> {
+    fn call(
+        &mut self,
+        mut request: tonic::Request<()>,
+    ) -> Result<tonic::Request<()>, tonic::Status> {
+        let token: MetadataValue<Ascii> =
+            self.token_provider.get_token().try_into().map_err(|_| {
+                tonic::Status::invalid_argument("authorization token contained invalid characters")
+            })?;
+
+        request.metadata_mut().insert("authorization", token);
+
+        Ok(request)
+    }
+}
+
+// The rest of this file is generated by the build script at ../build.rs.
+include!("includes.rs");