Skip to content

Commit

Permalink
fetches creds from data plane api instead of control plane api (#451)
Browse files Browse the repository at this point in the history
  • Loading branch information
shahadarsh authored Dec 22, 2023
1 parent fab88e9 commit 7915225
Show file tree
Hide file tree
Showing 26 changed files with 884 additions and 31 deletions.
13 changes: 13 additions & 0 deletions tembo-cli/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion tembo-cli/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
workspace = { members = ["temboclient"] }
workspace = { members = ["temboclient", "tembodataclient"] }
[package]
name = "tembo-cli"
version = "0.10.0"
Expand Down Expand Up @@ -45,6 +45,7 @@ log = "0.4.20"
tera = "1.0"
curl = "0.4.44"
temboclient = { version = "1.0.0", path = "temboclient" }
tembodataclient = { version = "0.0.1", path = "tembodataclient" }
tokio = { version = "1.26.0", features = [
"rt",
"rt-multi-thread",
Expand Down
16 changes: 16 additions & 0 deletions tembo-cli/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,22 @@ Validates Tembo.toml (same as `tembo validate`) and applies the changes to the c

Install OpenAPI Generator if not already by following steps [here](https://openapi-generator.tech/docs/installation)

### Data plane API client

Go to `tembodataclient` directory in your terminal.

Delete the contents of the directory first and then run following command to re-generate the rust client code for the API.

```bash
openapi-generator generate -i https://api.data-1.use1.tembo.io/api-docs/openapi.json -g rust -o . --additional-properties=packageName=tembodataclient
```

* Go to `tembodataclient/src/lib.rs` & add followng line at the top to disable clippy for the generated code

```
#![allow(clippy::all)]
```

### Control plane API client

Go to `temboclient` directory in your terminal.
Expand Down
2 changes: 1 addition & 1 deletion tembo-cli/rustfmt.toml
Original file line number Diff line number Diff line change
@@ -1 +1 @@
ignore = ["temboclient"]
ignore = ["temboclient", "tembodataclient"]
4 changes: 3 additions & 1 deletion tembo-cli/src/cli/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ pub const CREDENTIALS_DEFAULT_TEXT: &str = "version = \"1.0\"
[[profile]]
name = 'prod'
tembo_access_token = 'ACCESS_TOKEN'
tembo_host = 'https://api.coredb.io'
tembo_host = 'https://api.tembo.io'
tembo_data_host = 'https://api.data-1.use1.tembo.io'
";

#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
Expand Down Expand Up @@ -58,6 +59,7 @@ pub struct Profile {
pub name: String,
pub tembo_access_token: String,
pub tembo_host: String,
pub tembo_data_host: String,
}

pub enum Target {
Expand Down
24 changes: 5 additions & 19 deletions tembo-cli/src/cli/sqlx_utils.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
use crate::Result;
use base64::{engine::general_purpose, Engine as _};
use spinners::Spinner;
use spinners::Spinners;
use sqlx::migrate::Migrator;
Expand All @@ -12,23 +11,15 @@ pub struct SqlxUtils {}

impl SqlxUtils {
// run sqlx migrate
pub async fn run_migrations(connection_info: ConnectionInfo, decode: bool) -> Result {
pub async fn run_migrations(connection_info: ConnectionInfo) -> Result {
let mut sp = Spinner::new(Spinners::Line, "Running SQL migration".into());

let user: String;
let pwd: String;

if decode {
user = SqlxUtils::b64_decode(&connection_info.user);
pwd = SqlxUtils::b64_decode(&connection_info.password);
} else {
user = connection_info.user;
pwd = connection_info.password;
}

let connection_string = format!(
"postgresql://{}:{}@{}:{}",
user, pwd, connection_info.host, connection_info.port
connection_info.user,
connection_info.password,
connection_info.host,
connection_info.port
);

let pool = Pool::<Postgres>::connect(connection_string.as_str()).await?;
Expand All @@ -40,9 +31,4 @@ impl SqlxUtils {

Ok(())
}

fn b64_decode(b64_encoded: &str) -> String {
let bytes = general_purpose::STANDARD.decode(b64_encoded).unwrap();
String::from_utf8(bytes).unwrap()
}
}
60 changes: 52 additions & 8 deletions tembo-cli/src/cmd/apply.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::{
cli::{
context::{get_current_context, Environment, Target},
context::{get_current_context, Environment, Profile, Target},
sqlx_utils::SqlxUtils,
tembo_config,
},
Expand Down Expand Up @@ -28,6 +28,7 @@ use temboclient::{
StackType, State, Storage, TrunkInstall, UpdateInstance,
},
};
use tembodataclient::apis::secrets_api::get_secret_v1;
use tokio::runtime::Runtime;

use crate::cli::{docker::Docker, file_utils::FileUtils, tembo_config::InstanceSettings};
Expand All @@ -47,7 +48,7 @@ pub fn execute(_args: &ArgMatches) -> Result<()> {
if env.target == Target::Docker.to_string() {
return execute_docker();
} else if env.target == Target::TemboCloud.to_string() {
return execute_tembo_cloud(env);
return execute_tembo_cloud(env.clone());
}

Ok(())
Expand Down Expand Up @@ -97,7 +98,7 @@ fn execute_docker() -> Result<()> {
};
Runtime::new()
.unwrap()
.block_on(SqlxUtils::run_migrations(conn_info, false))?;
.block_on(SqlxUtils::run_migrations(conn_info))?;
}

// If all of the above was successful, we can print the url to user
Expand All @@ -111,13 +112,13 @@ pub fn execute_tembo_cloud(env: Environment) -> Result<()> {

let profile = env.clone().selected_profile.unwrap();
let config = Configuration {
base_path: profile.tembo_host,
bearer_access_token: Some(profile.tembo_access_token),
base_path: profile.clone().tembo_host,
bearer_access_token: Some(profile.clone().tembo_access_token),
..Default::default()
};

for (_key, value) in instance_settings.iter() {
let mut instance_id = get_instance_id(value.instance_name.clone(), &config, &env)?;
let mut instance_id = get_instance_id(value.instance_name.clone(), &config, env.clone())?;

if let Some(env_instance_id) = instance_id.clone() {
update_existing_instance(env_instance_id, value, &config, env.clone());
Expand All @@ -131,11 +132,21 @@ pub fn execute_tembo_cloud(env: Environment) -> Result<()> {

let connection_info: Option<Box<ConnectionInfo>> =
is_instance_up(instance_id.as_ref().unwrap().clone(), &config, &env)?;

if connection_info.is_some() {
let conn_info = get_conn_info_with_creds(
profile.clone(),
&instance_id,
connection_info,
env.clone(),
)?;

Runtime::new()
.unwrap()
.block_on(SqlxUtils::run_migrations(*connection_info.unwrap(), true))?;
.block_on(SqlxUtils::run_migrations(conn_info))?;

sp.stop_with_message("- Instance is now up!".to_string());

break;
}
}
Expand All @@ -144,10 +155,43 @@ pub fn execute_tembo_cloud(env: Environment) -> Result<()> {
Ok(())
}

fn get_conn_info_with_creds(
profile: Profile,
instance_id: &Option<String>,
connection_info: Option<Box<ConnectionInfo>>,
env: Environment,
) -> Result<ConnectionInfo> {
let dataplane_config = tembodataclient::apis::configuration::Configuration {
base_path: profile.tembo_data_host,
bearer_access_token: Some(profile.tembo_access_token),
..Default::default()
};

let result = Runtime::new().unwrap().block_on(get_secret_v1(
&dataplane_config,
env.org_id.clone().unwrap().as_str(),
instance_id.as_ref().unwrap(),
"superuser-role",
));

if result.is_err() {
return Err(Error::msg("Error fetching instance credentials!"));
}

let mut conn_info = *connection_info.unwrap();

let map = result.as_ref().unwrap();

conn_info.user = map.get("username").unwrap().to_string();
conn_info.password = map.get("password").unwrap().to_string();

Ok(conn_info)
}

pub fn get_instance_id(
instance_name: String,
config: &Configuration,
env: &Environment,
env: Environment,
) -> Result<Option<String>> {
let v = Runtime::new()
.unwrap()
Expand Down
2 changes: 1 addition & 1 deletion tembo-cli/src/cmd/delete.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ fn execute_tembo_cloud(env: Environment) -> Result<()> {
};

for (_key, value) in instance_settings.iter() {
let instance_id = get_instance_id(value.instance_name.clone(), &config, &env)?;
let instance_id = get_instance_id(value.instance_name.clone(), &config, env.clone())?;
if let Some(env_instance_id) = instance_id {
let v = Runtime::new().unwrap().block_on(delete_instance(
&config,
Expand Down
3 changes: 3 additions & 0 deletions tembo-cli/tembodataclient/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
/target/
**/*.rs.bk
Cargo.lock
23 changes: 23 additions & 0 deletions tembo-cli/tembodataclient/.openapi-generator-ignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# OpenAPI Generator Ignore
# Generated by openapi-generator https://github.com/openapitools/openapi-generator

# Use this file to prevent files from being overwritten by the generator.
# The patterns follow closely to .gitignore or .dockerignore.

# As an example, the C# client generator defines ApiClient.cs.
# You can make changes and tell OpenAPI Generator to ignore just this file by uncommenting the following line:
#ApiClient.cs

# You can match any string of characters against a directory, file or extension with a single asterisk (*):
#foo/*/qux
# The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux

# You can recursively match patterns against a directory, file or extension with a double asterisk (**):
#foo/**/qux
# This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux

# You can also negate patterns with an exclamation (!).
# For example, you can ignore all files in a docs folder with the file extension .md:
#docs/*.md
# Then explicitly reverse the ignore rule for a single file:
#!docs/README.md
16 changes: 16 additions & 0 deletions tembo-cli/tembodataclient/.openapi-generator/FILES
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
.gitignore
.openapi-generator-ignore
.travis.yml
Cargo.toml
README.md
docs/AvailableSecret.md
docs/MetricsApi.md
docs/SecretsApi.md
git_push.sh
src/apis/configuration.rs
src/apis/metrics_api.rs
src/apis/mod.rs
src/apis/secrets_api.rs
src/lib.rs
src/models/available_secret.rs
src/models/mod.rs
1 change: 1 addition & 0 deletions tembo-cli/tembodataclient/.openapi-generator/VERSION
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
7.1.0
1 change: 1 addition & 0 deletions tembo-cli/tembodataclient/.travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
language: rust
18 changes: 18 additions & 0 deletions tembo-cli/tembodataclient/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
[package]
name = "tembodataclient"
version = "0.0.1"
authors = ["OpenAPI Generator team and contributors"]
description = "In the case of large or sensitive data, we avoid collecting it into Tembo Cloud. Instead, there is a Tembo Data API for each region, cloud, or private data plane. </br> </br> To find the Tembo Cloud API, please find it [here](https://api.tembo.io/swagger-ui/). "
# Override this license by providing a License Object in the OpenAPI.
license = "Unlicense"
edition = "2018"

[dependencies]
serde = "^1.0"
serde_derive = "^1.0"
serde_json = "^1.0"
url = "^2.2"
uuid = { version = "^1.0", features = ["serde", "v4"] }
[dependencies.reqwest]
version = "^0.11"
features = ["json", "multipart"]
53 changes: 53 additions & 0 deletions tembo-cli/tembodataclient/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# Rust API client for tembodataclient

In the case of large or sensitive data, we avoid collecting it into Tembo Cloud. Instead, there is a Tembo Data API for each region, cloud, or private data plane.
</br>
</br>
To find the Tembo Cloud API, please find it [here](https://api.tembo.io/swagger-ui/).



## Overview

This API client was generated by the [OpenAPI Generator](https://openapi-generator.tech) project. By using the [openapi-spec](https://openapis.org) from a remote server, you can easily generate an API client.

- API version: v0.0.1
- Package version: v0.0.1
- Build package: `org.openapitools.codegen.languages.RustClientCodegen`

## Installation

Put the package under your project folder in a directory named `tembodataclient` and add the following to `Cargo.toml` under `[dependencies]`:

```
tembodataclient = { path = "./tembodataclient" }
```

## Documentation for API Endpoints

All URIs are relative to *http://localhost*

Class | Method | HTTP request | Description
------------ | ------------- | ------------- | -------------
*MetricsApi* | [**query_range**](docs/MetricsApi.md#query_range) | **GET** /{namespace}/metrics/query_range |
*SecretsApi* | [**get_secret**](docs/SecretsApi.md#get_secret) | **GET** /{namespace}/secrets/{secret_name} | Please use /api/v1/orgs/{org_id}/instances/{instance_id}/secrets/{secret_name}
*SecretsApi* | [**get_secret_names**](docs/SecretsApi.md#get_secret_names) | **GET** /{namespace}/secrets | Please use /api/v1/orgs/{org_id}/instances/{instance_id}/secrets
*SecretsApi* | [**get_secret_names_v1**](docs/SecretsApi.md#get_secret_names_v1) | **GET** /api/v1/orgs/{org_id}/instances/{instance_id}/secrets |
*SecretsApi* | [**get_secret_v1**](docs/SecretsApi.md#get_secret_v1) | **GET** /api/v1/orgs/{org_id}/instances/{instance_id}/secrets/{secret_name} |


## Documentation For Models

- [AvailableSecret](docs/AvailableSecret.md)


To get access to the crate's generated documentation, use:

```
cargo doc --open
```

## Author



12 changes: 12 additions & 0 deletions tembo-cli/tembodataclient/docs/AvailableSecret.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# AvailableSecret

## Properties

Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**name** | **String** | The name of an available secret |
**possible_keys** | **Vec<String>** | For this secret, available keys |

[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)


Loading

0 comments on commit 7915225

Please sign in to comment.