Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: expose config through admin api #2955

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions generated/.tailcallrc.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,10 @@ set of server configurations. It dictates how the server behaves and helps tune
for various use-cases.
"""
directive @server(
"""
Control private admin API settings
"""
admin: Admin
"""
`apolloTracing` exposes GraphQL query performance data, including execution time
of queries and individual resolvers.
Expand Down Expand Up @@ -576,6 +580,13 @@ input Schema {
Enum: [String!]
}

input Admin {
"""
TCP port on which the admin api will be available
"""
port: Int!
}

"""
Type to configure Cross-Origin Resource Sharing (CORS) for a server.
"""
Expand Down
25 changes: 25 additions & 0 deletions generated/.tailcallrc.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,20 @@
},
"additionalProperties": false
},
"Admin": {
"type": "object",
"required": [
"port"
],
"properties": {
"port": {
"description": "TCP port on which the admin api will be available",
"type": "integer",
"format": "uint16",
"minimum": 1.0
}
}
},
"Alias": {
"description": "The @alias directive indicates that aliases of one enum value.",
"type": "object",
Expand Down Expand Up @@ -1004,6 +1018,17 @@
"description": "The `@server` directive, when applied at the schema level, offers a comprehensive set of server configurations. It dictates how the server behaves and helps tune tailcall for various use-cases.",
"type": "object",
"properties": {
"admin": {
"description": "Control private admin API settings",
"anyOf": [
{
"$ref": "#/definitions/Admin"
},
{
"type": "null"
}
]
},
"apolloTracing": {
"description": "`apolloTracing` exposes GraphQL query performance data, including execution time of queries and individual resolvers.",
"type": [
Expand Down
11 changes: 11 additions & 0 deletions src/cli/server/admin_server/graphql.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
use async_graphql::SimpleObject;

#[derive(SimpleObject)]

Check warning on line 3 in src/cli/server/admin_server/graphql.rs

View check run for this annotation

Codecov / codecov/patch

src/cli/server/admin_server/graphql.rs#L3

Added line #L3 was not covered by tests
pub struct Config {
pub sdl: String,
}

#[derive(SimpleObject)]

Check warning on line 8 in src/cli/server/admin_server/graphql.rs

View check run for this annotation

Codecov / codecov/patch

src/cli/server/admin_server/graphql.rs#L8

Added line #L8 was not covered by tests
pub struct Query {
pub config: Config,
}
4 changes: 4 additions & 0 deletions src/cli/server/admin_server/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
mod graphql;
mod server;

pub use server::AdminServer;
75 changes: 75 additions & 0 deletions src/cli/server/admin_server/server.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
use std::net::SocketAddr;

use anyhow::Result;
use async_graphql::{EmptyMutation, EmptySubscription, Request, Schema};
use http::{Method, Response, StatusCode};
use hyper::service::{make_service_fn, service_fn};
use hyper::Server;

use super::graphql::{Config, Query};
use crate::core::async_graphql_hyper::GraphQLResponse;
use crate::core::blueprint::Blueprint;
use crate::core::config::ConfigModule;
use crate::core::Errata;

#[derive(Debug)]
pub struct AdminServer {
addr: SocketAddr,
sdl: String,
}

impl AdminServer {
pub fn new(config_module: &ConfigModule) -> Result<Option<Self>> {
if let Some(admin) = config_module.server.admin.as_ref() {
let blueprint = Blueprint::try_from(config_module).map_err(Errata::from)?;
let sdl = crate::core::document::print(config_module.config().into());
let addr = (blueprint.server.hostname, admin.port.get()).into();

Ok(Some(Self { addr, sdl }))

Check warning on line 28 in src/cli/server/admin_server/server.rs

View check run for this annotation

Codecov / codecov/patch

src/cli/server/admin_server/server.rs#L22-L28

Added lines #L22 - L28 were not covered by tests
} else {
Ok(None)

Check warning on line 30 in src/cli/server/admin_server/server.rs

View check run for this annotation

Codecov / codecov/patch

src/cli/server/admin_server/server.rs#L30

Added line #L30 was not covered by tests
}
}

Check warning on line 32 in src/cli/server/admin_server/server.rs

View check run for this annotation

Codecov / codecov/patch

src/cli/server/admin_server/server.rs#L32

Added line #L32 was not covered by tests

pub async fn start(self) -> Result<()> {
let server = Server::try_bind(&self.addr)?;
let config = Config { sdl: self.sdl };
let query = Query { config };
let schema = Schema::new(query, EmptyMutation, EmptySubscription);

server
.serve(make_service_fn(|_| {
let schema = schema.clone();
async move {
Result::<_>::Ok(service_fn(move |req| {
let (parts, body) = req.into_parts();
let schema = schema.clone();

Check warning on line 46 in src/cli/server/admin_server/server.rs

View check run for this annotation

Codecov / codecov/patch

src/cli/server/admin_server/server.rs#L34-L46

Added lines #L34 - L46 were not covered by tests

async move {
match parts.method {
Method::POST if parts.uri.path() == "/graphql" => {
let body = hyper::body::to_bytes(body).await?;
let request: Request = serde_json::from_slice(&body)?;

Check warning on line 52 in src/cli/server/admin_server/server.rs

View check run for this annotation

Codecov / codecov/patch

src/cli/server/admin_server/server.rs#L48-L52

Added lines #L48 - L52 were not covered by tests

let res = schema.execute(request).await;
let res = GraphQLResponse::from(res);

Result::<_>::Ok(res.into_response()?)

Check warning on line 57 in src/cli/server/admin_server/server.rs

View check run for this annotation

Codecov / codecov/patch

src/cli/server/admin_server/server.rs#L54-L57

Added lines #L54 - L57 were not covered by tests
}
_ => {
let mut response = Response::default();

*response.status_mut() = StatusCode::NOT_FOUND;

Result::<_>::Ok(response)

Check warning on line 64 in src/cli/server/admin_server/server.rs

View check run for this annotation

Codecov / codecov/patch

src/cli/server/admin_server/server.rs#L60-L64

Added lines #L60 - L64 were not covered by tests
}
}
}
}))
}
}))
.await?;

Check warning on line 71 in src/cli/server/admin_server/server.rs

View check run for this annotation

Codecov / codecov/patch

src/cli/server/admin_server/server.rs#L67-L71

Added lines #L67 - L71 were not covered by tests

Ok(())
}

Check warning on line 74 in src/cli/server/admin_server/server.rs

View check run for this annotation

Codecov / codecov/patch

src/cli/server/admin_server/server.rs#L73-L74

Added lines #L73 - L74 were not covered by tests
}
9 changes: 8 additions & 1 deletion src/cli/server/http_server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
use anyhow::Result;
use tokio::sync::oneshot::{self};

use super::admin_server::AdminServer;
use super::http_1::start_http_1;
use super::http_2::start_http_2;
use super::server_config::ServerConfig;
Expand Down Expand Up @@ -53,7 +54,13 @@
.enable_all()
.build()?;

let result = runtime.spawn(async { self.start().await }).await?;
let admin_api = AdminServer::new(&self.config_module)?;

Check warning on line 57 in src/cli/server/http_server.rs

View check run for this annotation

Codecov / codecov/patch

src/cli/server/http_server.rs#L57

Added line #L57 was not covered by tests

if let Some(admin_api) = admin_api {
runtime.spawn(admin_api.start());
}

Check warning on line 61 in src/cli/server/http_server.rs

View check run for this annotation

Codecov / codecov/patch

src/cli/server/http_server.rs#L59-L61

Added lines #L59 - L61 were not covered by tests

let result = runtime.spawn(self.start()).await?;

Check warning on line 63 in src/cli/server/http_server.rs

View check run for this annotation

Codecov / codecov/patch

src/cli/server/http_server.rs#L63

Added line #L63 was not covered by tests
runtime.shutdown_background();

result
Expand Down
1 change: 1 addition & 0 deletions src/cli/server/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
mod admin_server;
pub mod http_1;
pub mod http_2;
pub mod http_server;
Expand Down
12 changes: 12 additions & 0 deletions src/core/config/server.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use std::collections::{BTreeMap, BTreeSet};
use std::num::NonZeroU16;

use derive_getters::Getters;
use schemars::JsonSchema;
Expand Down Expand Up @@ -130,6 +131,10 @@ pub struct Server {
/// - graphQL: "/graphql" If not specified, these default values will be
/// used.
pub routes: Option<Routes>,

/// Control private admin API settings
#[serde(default, skip_serializing_if = "is_default")]
pub admin: Option<Admin>,
}

#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, MergeRight, JsonSchema, Getters)]
Expand Down Expand Up @@ -184,6 +189,13 @@ pub enum HttpVersion {
HTTP2,
}

#[derive(Deserialize, Serialize, Debug, PartialEq, Eq, Clone, schemars::JsonSchema, MergeRight)]
#[serde(rename_all = "camelCase")]
pub struct Admin {
/// TCP port on which the admin api will be available
pub port: NonZeroU16,
}

impl Server {
pub fn enable_apollo_tracing(&self) -> bool {
self.apollo_tracing.unwrap_or(false)
Expand Down
3 changes: 2 additions & 1 deletion src/core/primitive.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use std::marker::PhantomData;
use std::num::NonZeroU64;
use std::num::{NonZeroU16, NonZeroU64};

use crate::core::merge_right::MergeRight;

Expand All @@ -16,6 +16,7 @@ impl Primitive for i8 {}
impl Primitive for NonZeroU64 {}
impl Primitive for String {}
impl Primitive for u16 {}
impl Primitive for NonZeroU16 {}
impl Primitive for u32 {}
impl Primitive for u64 {}
impl Primitive for u8 {}
Expand Down
Loading