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(meta): watch and reload license key from file #18768

Merged
merged 10 commits into from
Oct 9, 2024
Merged
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
113 changes: 112 additions & 1 deletion Cargo.lock

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

1 change: 1 addition & 0 deletions src/cmd_all/src/standalone.rs
Original file line number Diff line number Diff line change
Expand Up @@ -468,6 +468,7 @@ mod test {
dangerous_max_idle_secs: None,
connector_rpc_endpoint: None,
license_key: None,
license_key_file: None,
temp_secret_file_dir: "./meta/secrets/",
},
),
Expand Down
11 changes: 11 additions & 0 deletions src/license/src/key.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,17 @@ use std::str::FromStr;
use serde::{Deserialize, Serialize};

/// A license key with the paid tier that only works in tests.
///
/// The content is a JWT token with the following payload:
/// ```text
/// License {
/// sub: "rw-test",
/// iss: Test,
/// tier: Paid,
/// cpu_core_limit: None,
/// exp: 9999999999,
/// }
/// ```
pub(crate) const TEST_PAID_LICENSE_KEY_CONTENT: &str =
"eyJhbGciOiJSUzUxMiIsInR5cCI6IkpXVCJ9.\
eyJzdWIiOiJydy10ZXN0IiwidGllciI6InBhaWQiLCJpc3MiOiJ0ZXN0LnJpc2luZ3dhdmUuY29tIiwiZXhwIjo5OTk5OTk5OTk5fQ.\
Expand Down
14 changes: 10 additions & 4 deletions src/license/src/manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ pub enum Tier {
///
/// The issuer must be `prod.risingwave.com` in production, and can be `test.risingwave.com` in
/// development. This will be validated when refreshing the license key.
#[derive(Debug, Clone, Deserialize)]
#[derive(Debug, Clone, Deserialize, PartialEq, Eq)]
pub enum Issuer {
#[serde(rename = "prod.risingwave.com")]
Prod,
Expand All @@ -58,10 +58,13 @@ pub enum Issuer {
/// The content of a license.
///
/// We use JSON Web Token (JWT) to represent the license. This struct is the payload.
///
/// Prefer calling [`crate::Feature::check_available`] to check the availability of a feature,
/// other than directly checking the content of the license.
// TODO(license): Shall we add a version field?
#[derive(Debug, Clone, Deserialize)]
#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
#[serde(rename_all = "snake_case")]
pub(super) struct License {
pub struct License {
/// Subject of the license.
///
/// See <https://tools.ietf.org/html/rfc7519#section-4.1.2>.
Expand Down Expand Up @@ -171,7 +174,10 @@ impl LicenseManager {
/// Get the current license if it is valid.
///
/// Since the license can expire, the returned license should not be cached by the caller.
pub(super) fn license(&self) -> Result<License, LicenseKeyError> {
///
/// Prefer calling [`crate::Feature::check_available`] to check the availability of a feature,
/// other than directly calling this method and checking the content of the license.
pub fn license(&self) -> Result<License, LicenseKeyError> {
let license = self.inner.read().unwrap().license.clone()?;

// Check the expiration time additionally.
Expand Down
3 changes: 3 additions & 0 deletions src/meta/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ jsonbb = { workspace = true }
maplit = "1.0.2"
memcomparable = { version = "0.2" }
mime_guess = "2"
notify = { version = "6", default-features = false, features = ["macos_fsevent"] }
num-integer = "0.1"
num-traits = "0.2"
otlp-embedded = { workspace = true }
Expand Down Expand Up @@ -105,6 +106,8 @@ expect-test = "1.5"
rand = { workspace = true }
risingwave_hummock_sdk = { workspace = true, features = ["test"] }
risingwave_test_runner = { workspace = true }
tempfile = "3"
tracing-subscriber = "0.3"

[features]
test = []
Expand Down
6 changes: 6 additions & 0 deletions src/meta/node/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

mod server;

use std::path::PathBuf;
use std::time::Duration;

use clap::Parser;
Expand Down Expand Up @@ -192,6 +193,10 @@ pub struct MetaNodeOpts {
#[override_opts(path = system.license_key)]
pub license_key: Option<LicenseKey>,

/// The path of the license key file to be watched and hot-reloaded.
#[clap(long, env = "RW_LICENSE_KEY_PATH")]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo found 🤣

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Discussed with @BugenZhao elsewhere, here's the conclusion: RW_LICENSE_KEY_PATH will be kept instead of being changed to the RW_LICENSE_KEY_FILE in the PR description.

pub license_key_file: Option<PathBuf>,

/// 128-bit AES key for secret store in HEX format.
#[educe(Debug(ignore))] // TODO: use newtype to redact debug impl
#[clap(long, hide = true, env = "RW_SECRET_STORE_PRIVATE_KEY_HEX")]
Expand Down Expand Up @@ -468,6 +473,7 @@ pub fn start(
.meta
.developer
.actor_cnt_per_worker_parallelism_soft_limit,
license_key_path: opts.license_key_file,
},
config.system.into_init_system_params(),
Default::default(),
Expand Down
1 change: 1 addition & 0 deletions src/meta/node/src/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -398,6 +398,7 @@ pub async fn start_service_as_election_leader(
meta_store_impl,
)
.await?;
let _ = env.may_start_watch_license_key_file()?;
let system_params_reader = env.system_params_reader().await;

let data_directory = system_params_reader.data_directory();
Expand Down
5 changes: 5 additions & 0 deletions src/meta/src/manager/env.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
// limitations under the License.

use std::ops::Deref;
use std::path::PathBuf;
use std::sync::Arc;

use risingwave_common::config::{
Expand Down Expand Up @@ -298,6 +299,8 @@ pub struct MetaOpts {
// Cluster limits
pub actor_cnt_per_worker_parallelism_hard_limit: usize,
pub actor_cnt_per_worker_parallelism_soft_limit: usize,

pub license_key_path: Option<PathBuf>,
}

impl MetaOpts {
Expand Down Expand Up @@ -365,6 +368,7 @@ impl MetaOpts {
table_info_statistic_history_times: 240,
actor_cnt_per_worker_parallelism_hard_limit: usize::MAX,
actor_cnt_per_worker_parallelism_soft_limit: usize::MAX,
license_key_path: None,
}
}
}
Expand Down Expand Up @@ -526,6 +530,7 @@ impl MetaSrvEnv {
}
}
};

Ok(env)
}

Expand Down
Loading
Loading