From 6223cbdc999f25568971b43a1c04cbae10b64627 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Wed, 2 Sep 2020 10:08:36 -0400 Subject: [PATCH] feat: Add an authorization token to all client requests Connects to influxdata/fusion#59. Delorean currently ignores this header. Also add an example of using this to connect to an InfluxDB 2 instance; I tested this out with a locally running Influx DB 2 and I was able to write points! --- influxdb2_client/examples/influx2.rs | 27 ++++++++++++++++++++++++++ influxdb2_client/src/lib.rs | 29 +++++++++++++++++++--------- tests/end-to-end.rs | 3 ++- 3 files changed, 49 insertions(+), 10 deletions(-) create mode 100644 influxdb2_client/examples/influx2.rs diff --git a/influxdb2_client/examples/influx2.rs b/influxdb2_client/examples/influx2.rs new file mode 100644 index 0000000000..213c6bce2a --- /dev/null +++ b/influxdb2_client/examples/influx2.rs @@ -0,0 +1,27 @@ +use futures::prelude::*; + +#[tokio::main] +async fn main() -> Result<(), Box> { + let org = "0000000000000000"; + let bucket = "1111111111111111"; + let influx_url = "http://localhost:9999"; + let token = "my-token"; + + let client = influxdb2_client::Client::new(influx_url, token); + + let points = vec![ + influxdb2_client::DataPoint::builder("cpu_load_short") + .tag("host", "server01") + .tag("region", "us-west") + .field("value", 0.64) + .build()?, + influxdb2_client::DataPoint::builder("cpu_load_short") + .tag("host", "server01") + .field("value", 27.99) + .build()?, + ]; + + client.write(org, bucket, stream::iter(points)).await?; + + Ok(()) +} diff --git a/influxdb2_client/src/lib.rs b/influxdb2_client/src/lib.rs index 8bfbb2ef73..03cd18bca3 100644 --- a/influxdb2_client/src/lib.rs +++ b/influxdb2_client/src/lib.rs @@ -16,7 +16,6 @@ //! ## Work Remaining //! //! - Query -//! - Authentication //! - optional sync client //! - Influx 1.x API? //! - Other parts of the API @@ -36,7 +35,7 @@ //! let org_id = "0000111100001111"; //! let bucket_id = "1111000011110000"; //! -//! let client = Client::new("http://localhost:8888"); +//! let client = Client::new("http://localhost:8888", "some-token"); //! //! client.create_bucket(org_id, bucket_id).await?; //! @@ -62,7 +61,10 @@ use futures::{Stream, StreamExt}; use reqwest::{Body, Method}; use serde::Serialize; use snafu::{ResultExt, Snafu}; -use std::io::{self, Write}; +use std::{ + fmt, + io::{self, Write}, +}; pub mod data_point; pub use data_point::{DataPoint, FieldValue, WriteDataPoint}; @@ -100,27 +102,32 @@ pub enum RequestError { #[derive(Debug, Clone)] pub struct Client { url: String, + auth_header: String, reqwest: reqwest::Client, } impl Client { - /// Create a new client pointing to the URL specified in `protocol://server:port` format. + /// Create a new client pointing to the URL specified in `protocol://server:port` format and + /// using the specified token for authorization. /// /// # Example /// /// ``` - /// let client = influxdb2_client::Client::new("http://localhost:8888"); + /// let client = influxdb2_client::Client::new("http://localhost:8888", "my-token"); /// ``` - pub fn new(url: impl Into) -> Self { + pub fn new(url: impl Into, auth_token: impl fmt::Display) -> Self { Self { url: url.into(), + auth_header: format!("Token {}", auth_token), reqwest: reqwest::Client::new(), } } /// Consolidate common request building code fn request(&self, method: Method, url: &str) -> reqwest::RequestBuilder { - self.reqwest.request(method, url) + self.reqwest + .request(method, url) + .header("Authorization", &self.auth_header) } /// Write line protocol data to the specified organization and bucket. @@ -224,11 +231,13 @@ mod tests { async fn writing_points() -> Result { let org_id = "0000111100001111"; let bucket_id = "1111000011110000"; + let token = "some-token"; let mock_server = mock( "POST", format!("/api/v2/write?bucket={}&org={}", bucket_id, org_id).as_str(), ) + .match_header("Authorization", format!("Token {}", token).as_str()) .match_body( "\ cpu,host=server01 usage=0.5 @@ -237,7 +246,7 @@ cpu,host=server01,region=us-west usage=0.87 ) .create(); - let client = Client::new(&mockito::server_url()); + let client = Client::new(&mockito::server_url(), token); let points = vec![ DataPoint::builder("cpu") @@ -265,8 +274,10 @@ cpu,host=server01,region=us-west usage=0.87 async fn create_bucket() -> Result { let org_id = "0000111100001111"; let bucket_id = "1111000011110000"; + let token = "some-token"; let mock_server = mock("POST", "/api/v2/buckets") + .match_header("Authorization", format!("Token {}", token).as_str()) .match_body( format!( r#"{{"orgID":"{}","name":"{}","retentionRules":[]}}"#, @@ -276,7 +287,7 @@ cpu,host=server01,region=us-west usage=0.87 ) .create(); - let client = Client::new(&mockito::server_url()); + let client = Client::new(&mockito::server_url(), token); let _result = client.create_bucket(org_id, bucket_id).await; diff --git a/tests/end-to-end.rs b/tests/end-to-end.rs index 74f7cabd02..bf9756d578 100644 --- a/tests/end-to-end.rs +++ b/tests/end-to-end.rs @@ -40,6 +40,7 @@ use tempfile::TempDir; const HTTP_BASE: &str = "http://localhost:8080"; const API_BASE: &str = "http://localhost:8080/api/v2"; const GRPC_URL_BASE: &str = "http://localhost:8082/"; +const TOKEN: &str = "delorean doesn't have authentication yet"; type Error = Box; type Result = std::result::Result; @@ -109,7 +110,7 @@ async fn read_and_write_data() -> Result<()> { let bucket_id = u64::from_str_radix(bucket_id_str, 16).unwrap(); let client = reqwest::Client::new(); - let client2 = influxdb2_client::Client::new(HTTP_BASE); + let client2 = influxdb2_client::Client::new(HTTP_BASE, TOKEN); let mut grpc_client = DeloreanClient::connect(GRPC_URL_BASE).await?; let get_buckets_request = tonic::Request::new(Organization {