Skip to content

Commit 2350e06

Browse files
committed
feat: Add API to update license to meta-service in flight
Update EE license token with the following API: ``` curl -qs '127.0.0.1:28101/v1/ctrl/update_license?license=<license_token>' ``` On success, i.e., the token is valid and not expired, meta-service respond with the 200 OK with token info, such as: ``` {"Success":"JWTClaims{issuer: databend, issued_at: 2024-05-13T05:57:24.000000Z+0000, expires_at: 2025-05-13T05:57:24.000000Z+0000, custom: LicenseInfo{ type: enterprise, org: databend-interval-test, tenants: None, features: [Unlimited] }}"} ``` If the token is invalid, or expired, it responds with 400 Bad Request and a reason that cause the failure, such as: ``` Invalid license: JWT compact encoding error ```
1 parent 5546846 commit 2350e06

File tree

6 files changed

+70
-2
lines changed

6 files changed

+70
-2
lines changed

Cargo.lock

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/meta/ee/src/lib.rs

+10-1
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ pWjW3wxSdeARerxs/BeoWK7FspDtfLaAT8iJe4YEmR0JpkRQ8foWs0ve3w==
7070
}
7171

7272
/// Parse the JWT token and restore the claims.
73-
fn parse_jwt_token(&self, raw: &str) -> Result<JWTClaims<LicenseInfo>, anyhow::Error> {
73+
pub fn parse_jwt_token(&self, raw: &str) -> Result<JWTClaims<LicenseInfo>, anyhow::Error> {
7474
let public_key = ES256PublicKey::from_pem(&self.public_key)?;
7575

7676
let claim = public_key.verify_token::<LicenseInfo>(raw, None)?;
@@ -118,4 +118,13 @@ pWjW3wxSdeARerxs/BeoWK7FspDtfLaAT8iJe4YEmR0JpkRQ8foWs0ve3w==
118118

119119
Ok(())
120120
}
121+
122+
pub fn update_license(&self, license: String) -> Result<(), anyhow::Error> {
123+
self.check_license(&license)?;
124+
125+
let mut x = self.license_token.lock().unwrap();
126+
*x = Some(license);
127+
128+
Ok(())
129+
}
121130
}

src/meta/service/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ databend-common-arrow = { workspace = true }
3131
databend-common-base = { workspace = true }
3232
databend-common-grpc = { workspace = true }
3333
databend-common-http = { workspace = true }
34+
databend-common-license = { workspace = true }
3435
databend-common-meta-api = { workspace = true }
3536
databend-common-meta-client = { workspace = true }
3637
databend-common-meta-kvapi = { workspace = true }

src/meta/service/src/api/http/v1/ctrl.rs

+51
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,10 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15+
use std::collections::BTreeMap;
1516
use std::sync::Arc;
1617

18+
use databend_common_license::display_jwt_claims::DisplayJWTClaimsExt;
1719
use databend_common_meta_sled_store::openraft::async_runtime::watch::WatchReceiver;
1820
use databend_common_meta_types::NodeId;
1921
use http::StatusCode;
@@ -127,3 +129,52 @@ pub async fn trigger_transfer_leader(
127129
voter_ids,
128130
}))
129131
}
132+
133+
#[derive(serde::Serialize, serde::Deserialize, Debug)]
134+
pub struct UpdateLicenseQuery {
135+
pub(crate) license: String,
136+
}
137+
138+
#[derive(serde::Serialize, serde::Deserialize, Debug)]
139+
pub struct UpdateLicenseResponse {
140+
pub from: NodeId,
141+
pub to: NodeId,
142+
pub voter_ids: Vec<NodeId>,
143+
}
144+
145+
/// Update the `databend_enterprise_license` of this meta node.
146+
#[poem::handler]
147+
pub async fn update_license(
148+
meta_node: Data<&Arc<MetaNode>>,
149+
query: Option<Query<UpdateLicenseQuery>>,
150+
) -> poem::Result<impl IntoResponse> {
151+
let Some(query) = query else {
152+
return Err(poem::Error::from_string(
153+
"Invalid license",
154+
StatusCode::BAD_REQUEST,
155+
));
156+
};
157+
158+
let metrics = meta_node.raft.metrics().borrow_watched().clone();
159+
let id = metrics.id;
160+
161+
let saved = meta_node
162+
.ee_gate
163+
.parse_jwt_token(query.license.as_str())
164+
.map_err(|e| {
165+
poem::Error::from_string(format!("Invalid license: {}", e), StatusCode::BAD_REQUEST)
166+
})?;
167+
168+
meta_node
169+
.ee_gate
170+
.update_license(query.license.clone())
171+
.map_err(|e| poem::Error::from_string(e.to_string(), StatusCode::BAD_REQUEST))?;
172+
173+
let claim_str = saved.display_jwt_claims().to_string();
174+
info!("id={} Updated license: {}", id, claim_str);
175+
176+
let mut resp = BTreeMap::new();
177+
resp.insert("Success", claim_str);
178+
179+
Ok(Json(resp))
180+
}

src/meta/service/src/api/http_service.rs

+4
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,10 @@ impl HttpService {
6565
"/v1/ctrl/trigger_transfer_leader",
6666
get(super::http::v1::ctrl::trigger_transfer_leader),
6767
)
68+
.at(
69+
"/v1/ctrl/update_license",
70+
get(super::http::v1::ctrl::update_license),
71+
)
6872
.at(
6973
"/v1/cluster/nodes",
7074
get(super::http::v1::cluster_state::nodes_handler),

src/meta/service/src/meta_service/meta_node.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ pub struct MetaNode {
108108
pub sto: RaftStore,
109109
pub dispatcher_handle: EventDispatcherHandle,
110110
pub raft: MetaRaft,
111+
pub(crate) ee_gate: MetaServiceEnterpriseGate,
111112
pub running_tx: watch::Sender<()>,
112113
pub running_rx: watch::Receiver<()>,
113114
pub join_handles: Mutex<Vec<JoinHandle<Result<(), AnyError>>>>,
@@ -146,7 +147,7 @@ impl MetaNodeBuilder {
146147

147148
let ee_gate = self.ee_gate.clone();
148149

149-
let net = NetworkFactory::new(sto.clone(), ee_gate);
150+
let net = NetworkFactory::new(sto.clone(), ee_gate.clone());
150151

151152
let log_store = sto.clone();
152153
let sm_store = sto.clone();
@@ -167,6 +168,7 @@ impl MetaNodeBuilder {
167168
sto: sto.clone(),
168169
dispatcher_handle: EventDispatcherHandle::new(dispatcher_tx),
169170
raft: raft.clone(),
171+
ee_gate,
170172
running_tx: tx,
171173
running_rx: rx,
172174
join_handles: Mutex::new(Vec::new()),

0 commit comments

Comments
 (0)