diff --git a/control_plane/src/compute.rs b/control_plane/src/compute.rs index 059f07fb9a..3ba3c26eff 100644 --- a/control_plane/src/compute.rs +++ b/control_plane/src/compute.rs @@ -151,7 +151,7 @@ pub struct PostgresNode { pub env: LocalEnv, pageserver: Arc, is_test: bool, - timelineid: ZTimelineId, + pub timelineid: ZTimelineId, } impl PostgresNode { @@ -169,6 +169,7 @@ impl PostgresNode { lazy_static! { static ref CONF_PORT_RE: Regex = Regex::new(r"(?m)^\s*port\s*=\s*(\d+)\s*$").unwrap(); + static ref CONF_TIMELINE_RE: Regex = Regex::new(r"(?m)^\s*zenith_timeline\s*=\s*'(\w+)'\s*$").unwrap(); } // parse data directory name @@ -184,6 +185,7 @@ impl PostgresNode { ) })?; + // parse port let err_msg = format!( "failed to find port definition in config file {}", cfg_path.to_str().unwrap() @@ -199,11 +201,21 @@ impl PostgresNode { .parse() .with_context(|| err_msg)?; - // FIXME: What timeline is this server on? Would have to parse the postgresql.conf - // file for that, too. It's currently not needed for anything, but it would be - // nice to list the timeline in "zenith pg list" - let timelineid_buf = [0u8; 16]; - let timelineid = ZTimelineId::from(timelineid_buf); + // parse timeline + let err_msg = format!( + "failed to find timeline definition in config file {}", + cfg_path.to_str().unwrap() + ); + let timelineid: ZTimelineId = CONF_TIMELINE_RE + .captures(config.as_str()) + .ok_or_else(|| anyhow::Error::msg(err_msg.clone() + " 1"))? + .iter() + .last() + .ok_or_else(|| anyhow::Error::msg(err_msg.clone() + " 2"))? + .ok_or_else(|| anyhow::Error::msg(err_msg.clone() + " 3"))? + .as_str() + .parse() + .with_context(|| err_msg)?; // ok now Ok(PostgresNode { diff --git a/zenith/src/main.rs b/zenith/src/main.rs index 69a31efdae..d96b23b28f 100644 --- a/zenith/src/main.rs +++ b/zenith/src/main.rs @@ -1,4 +1,4 @@ -use std::fs; +use std::{collections::HashMap, fs}; use std::path::{Path, PathBuf}; use std::process::exit; use std::str::FromStr; @@ -158,13 +158,13 @@ pub fn get_branch_timeline(repopath: &Path, branchname: &str) -> ZTimelineId { fn handle_pg(pg_match: &ArgMatches, env: &local_env::LocalEnv) -> Result<()> { let mut cplane = ComputeControlPlane::load(env.clone())?; + // FIXME: cheat and resolve the timeline by peeking into the + // repository. In reality, when you're launching a compute node + // against a possibly-remote page server, we wouldn't know what + // branches exist in the remote repository. Or would we require + // that you "zenith fetch" them into a local repoitory first? match pg_match.subcommand() { ("create", Some(sub_m)) => { - // FIXME: cheat and resolve the timeline by peeking into the - // repository. In reality, when you're launching a compute node - // against a possibly-remote page server, we wouldn't know what - // branches exist in the remote repository. Or would we require - // that you "zenith fetch" them into a local repoitory first? let timeline_arg = sub_m.value_of("timeline").unwrap_or("main"); let timeline = get_branch_timeline(&env.repo_path, timeline_arg); @@ -173,9 +173,18 @@ fn handle_pg(pg_match: &ArgMatches, env: &local_env::LocalEnv) -> Result<()> { cplane.new_node(timeline)?; } ("list", Some(_sub_m)) => { - println!("NODE\tADDRESS\tSTATUS"); + let mut tl2branch = HashMap::::new(); + let branches_dir = zenith_repo_dir().join("refs").join("branches"); + for path in fs::read_dir(branches_dir.clone())? { + let branch_name = path?.file_name().to_str().unwrap().to_string(); + let branch_file = branches_dir.join(branch_name.clone()); + let timelineid = fs::read_to_string(branch_file)?.parse::()?; + tl2branch.insert(timelineid, branch_name); + } + + println!("NODE\tADDRESS\t\tSTATUS\tBRANCH"); for (node_name, node) in cplane.nodes.iter() { - println!("{}\t{}\t{}", node_name, node.address, node.status()); + println!("{}\t{}\t{}\t{}", node_name, node.address, node.status(), tl2branch[&node.timelineid]); } } ("start", Some(sub_m)) => {