diff --git a/compute_tools/src/compute.rs b/compute_tools/src/compute.rs
index 285be56264..329cc78573 100644
--- a/compute_tools/src/compute.rs
+++ b/compute_tools/src/compute.rs
@@ -19,6 +19,7 @@ use futures::future::join_all;
use futures::stream::FuturesUnordered;
use futures::StreamExt;
use nix::unistd::Pid;
+use postgres::config::Config;
use postgres::error::SqlState;
use postgres::{Client, NoTls};
use tracing::{debug, error, info, instrument, warn};
@@ -1367,6 +1368,28 @@ LIMIT 100",
download_size
}
+ pub fn set_role_grants(
+ &self,
+ db_name: &str,
+ schema_name: &str,
+ privilege: &str,
+ role_name: &str,
+ ) -> Result<()> {
+ let mut conf = Config::from_str(self.connstr.as_str()).unwrap();
+ conf.dbname(db_name);
+
+ let mut db_client = conf
+ .connect(NoTls)
+ .context("Failed to connect to the database")?;
+
+ let query = "GRANT $1 ON SCHEMA $2 TO $3";
+ db_client
+ .execute(query, &[&schema_name, &privilege, &role_name])
+ .context(format!("Failed to execute query: {}", query))?;
+
+ Ok(())
+ }
+
#[tokio::main]
pub async fn prepare_preload_libraries(
&self,
diff --git a/compute_tools/src/http/api.rs b/compute_tools/src/http/api.rs
index 79e6158081..60d542af4c 100644
--- a/compute_tools/src/http/api.rs
+++ b/compute_tools/src/http/api.rs
@@ -9,8 +9,10 @@ use crate::catalog::SchemaDumpError;
use crate::catalog::{get_database_schema, get_dbs_and_roles};
use crate::compute::forward_termination_signal;
use crate::compute::{ComputeNode, ComputeState, ParsedSpec};
-use compute_api::requests::ConfigurationRequest;
-use compute_api::responses::{ComputeStatus, ComputeStatusResponse, GenericAPIError};
+use compute_api::requests::{ConfigurationRequest, SetRoleGrantsRequest};
+use compute_api::responses::{
+ ComputeStatus, ComputeStatusResponse, GenericAPIError, SetRoleGrantsResult,
+};
use anyhow::Result;
use hyper::header::CONTENT_TYPE;
@@ -165,6 +167,35 @@ async fn routes(req: Request
, compute: &Arc) -> Response {
+ info!("serving /grants POST request");
+ let status = compute.get_status();
+ if status != ComputeStatus::Running {
+ let msg = format!(
+ "invalid compute status for set_role_grants request: {:?}",
+ status
+ );
+ error!(msg);
+ return Response::new(Body::from(msg));
+ }
+
+ let request = hyper::body::to_bytes(req.into_body()).await.unwrap();
+ let request = serde_json::from_slice::(&request).unwrap();
+ let res = compute.set_role_grants(
+ &request.database,
+ &request.schema,
+ &request.privilege,
+ &request.role,
+ );
+ match res {
+ Ok(_) => Response::new(Body::from("true")),
+ Err(e) => {
+ error!("set_role_grants failed: {}", e);
+ Response::new(Body::from(e.to_string()))
+ }
+ }
+ }
+
// get the list of installed extensions
// currently only used in python tests
// TODO: call it from cplane
diff --git a/compute_tools/src/http/openapi_spec.yaml b/compute_tools/src/http/openapi_spec.yaml
index e9fa66b323..6b54a9e986 100644
--- a/compute_tools/src/http/openapi_spec.yaml
+++ b/compute_tools/src/http/openapi_spec.yaml
@@ -10,7 +10,7 @@ paths:
/status:
get:
tags:
- - Info
+ - Info
summary: Get compute node internal status.
description: ""
operationId: getComputeStatus
@@ -25,7 +25,7 @@ paths:
/metrics.json:
get:
tags:
- - Info
+ - Info
summary: Get compute node startup metrics in JSON format.
description: ""
operationId: getComputeMetricsJSON
@@ -40,7 +40,7 @@ paths:
/insights:
get:
tags:
- - Info
+ - Info
summary: Get current compute insights in JSON format.
description: |
Note, that this doesn't include any historical data.
@@ -56,7 +56,7 @@ paths:
/installed_extensions:
get:
tags:
- - Info
+ - Info
summary: Get installed extensions.
description: ""
operationId: getInstalledExtensions
@@ -70,7 +70,7 @@ paths:
/info:
get:
tags:
- - Info
+ - Info
summary: Get info about the compute pod / VM.
description: ""
operationId: getInfo
@@ -130,7 +130,7 @@ paths:
/check_writability:
post:
tags:
- - Check
+ - Check
summary: Check that we can write new data on this compute.
description: ""
operationId: checkComputeWritability
@@ -147,7 +147,7 @@ paths:
/configure:
post:
tags:
- - Configure
+ - Configure
summary: Perform compute node configuration.
description: |
This is a blocking API endpoint, i.e. it blocks waiting until
@@ -201,7 +201,7 @@ paths:
/extension_server:
post:
tags:
- - Extension
+ - Extension
summary: Download extension from S3 to local folder.
description: ""
operationId: downloadExtension
@@ -230,7 +230,7 @@ paths:
/terminate:
post:
tags:
- - Terminate
+ - Terminate
summary: Terminate Postgres and wait for it to exit
description: ""
operationId: terminate
@@ -369,7 +369,7 @@ components:
moment, when spec was received.
example: "2022-10-12T07:20:50.52Z"
status:
- $ref: '#/components/schemas/ComputeStatus'
+ $ref: "#/components/schemas/ComputeStatus"
last_active:
type: string
description: |
@@ -427,6 +427,28 @@ components:
n_databases:
type: integer
+ SetRoleGrantsRequest:
+ type: object
+ required:
+ - database
+ - role
+ - grants
+ properties:
+ database:
+ type: string
+ description: Database name.
+ example: "neondb"
+ role:
+ type: string
+ description: Role name.
+ example: "neon"
+ grants:
+ type: array
+ items:
+ type: string
+ description: List of grants to set.
+ example: ["SELECT", "INSERT"]
+
#
# Errors
#
diff --git a/libs/compute_api/src/requests.rs b/libs/compute_api/src/requests.rs
index 5896c7dc65..963c5992af 100644
--- a/libs/compute_api/src/requests.rs
+++ b/libs/compute_api/src/requests.rs
@@ -12,3 +12,11 @@ use serde::Deserialize;
pub struct ConfigurationRequest {
pub spec: ComputeSpec,
}
+
+#[derive(Deserialize, Debug)]
+pub struct SetRoleGrantsRequest {
+ pub database: String,
+ pub schema: String,
+ pub privilege: String,
+ pub role: String,
+}
diff --git a/libs/compute_api/src/responses.rs b/libs/compute_api/src/responses.rs
index 5023fce003..4b4b16ebc4 100644
--- a/libs/compute_api/src/responses.rs
+++ b/libs/compute_api/src/responses.rs
@@ -168,3 +168,8 @@ pub struct InstalledExtension {
pub struct InstalledExtensions {
pub extensions: Vec,
}
+
+#[derive(Clone, Debug, Default, Serialize)]
+pub struct SetRoleGrantsResult {
+ pub extension: String,
+}