Skip to content

Commit 1b648ca

Browse files
authored
Send proper server parameters to clients using admin db (#103)
* Send proper server parameters to clients using admin db * clean up * fix python test * build * Add python * missing & * debug ls * fix tests * fix tests * fix * Fix warning * Address comments
1 parent 35381ba commit 1b648ca

File tree

7 files changed

+86
-20
lines changed

7 files changed

+86
-20
lines changed

.circleci/config.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,9 @@ jobs:
3232
command: "cargo fmt --check"
3333
- run:
3434
name: "Install dependencies"
35-
command: "sudo apt-get update && sudo apt-get install -y psmisc postgresql-contrib-12 postgresql-client-12 ruby ruby-dev libpq-dev"
35+
command: "sudo apt-get update && sudo apt-get install -y psmisc postgresql-contrib-12 postgresql-client-12 ruby ruby-dev libpq-dev python"
3636
- run:
37-
name: "Build"
37+
name: "Build"
3838
command: "cargo build"
3939
- run:
4040
name: "Test"

.circleci/run_tests.sh

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,8 +69,17 @@ psql -U sharding_user -e -h 127.0.0.1 -p 6432 -f tests/sharding/query_routing_te
6969
cd tests/ruby && \
7070
sudo gem install bundler && \
7171
bundle install && \
72-
ruby tests.rb && \
73-
cd ../..
72+
ruby tests.rb
73+
cd /home/circleci/project
74+
75+
#
76+
# Python tests
77+
#
78+
cd tests/python && \
79+
pip install -r requirements.txt && \
80+
python tests.py
81+
cd /home/circleci/project
82+
7483

7584
# Admin tests
7685
export PGPASSWORD=admin_pass

src/admin.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,18 @@ use crate::pool::get_all_pools;
1010
use crate::stats::get_stats;
1111
use crate::ClientServerMap;
1212

13+
pub fn generate_server_info_for_admin() -> BytesMut {
14+
let mut server_info = BytesMut::new();
15+
16+
server_info.put(server_paramater_message("application_name", ""));
17+
server_info.put(server_paramater_message("client_encoding", "UTF8"));
18+
server_info.put(server_paramater_message("server_encoding", "UTF8"));
19+
server_info.put(server_paramater_message("server_version", VERSION));
20+
server_info.put(server_paramater_message("DateStyle", "ISO, MDY"));
21+
22+
return server_info;
23+
}
24+
1325
/// Handle admin client.
1426
pub async fn handle_admin<T>(
1527
stream: &mut T,

src/client.rs

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use std::collections::HashMap;
55
use tokio::io::{split, AsyncReadExt, BufReader, ReadHalf, WriteHalf};
66
use tokio::net::TcpStream;
77

8-
use crate::admin::handle_admin;
8+
use crate::admin::{generate_server_info_for_admin, handle_admin};
99
use crate::config::get_config;
1010
use crate::constants::*;
1111
use crate::errors::Error;
@@ -311,10 +311,7 @@ where
311311
Err(_) => return Err(Error::SocketError),
312312
};
313313

314-
let mut target_pool: ConnectionPool = ConnectionPool::default();
315-
let mut transaction_mode = false;
316-
317-
if admin {
314+
let (target_pool, transaction_mode, server_info) = if admin {
318315
let correct_user = config.general.admin_username.as_str();
319316
let correct_password = config.general.admin_password.as_str();
320317

@@ -325,8 +322,13 @@ where
325322
wrong_password(&mut write, user).await?;
326323
return Err(Error::ClientError);
327324
}
325+
(
326+
ConnectionPool::default(),
327+
false,
328+
generate_server_info_for_admin(),
329+
)
328330
} else {
329-
target_pool = match get_pool(database.clone(), user.clone()) {
331+
let target_pool = match get_pool(database.clone(), user.clone()) {
330332
Some(pool) => pool,
331333
None => {
332334
error_response(
@@ -340,8 +342,8 @@ where
340342
return Err(Error::ClientError);
341343
}
342344
};
343-
transaction_mode = target_pool.settings.pool_mode == "transaction";
344-
345+
let transaction_mode = target_pool.settings.pool_mode == "transaction";
346+
let server_info = target_pool.server_info();
345347
// Compare server and client hashes.
346348
let correct_password = target_pool.settings.user.password.as_str();
347349
let password_hash = md5_hash_password(user, correct_password, &salt);
@@ -351,12 +353,13 @@ where
351353
wrong_password(&mut write, user).await?;
352354
return Err(Error::ClientError);
353355
}
354-
}
356+
(target_pool, transaction_mode, server_info)
357+
};
355358

356359
debug!("Password authentication successful");
357360

358361
auth_ok(&mut write).await?;
359-
write_all(&mut write, target_pool.server_info()).await?;
362+
write_all(&mut write, server_info).await?;
360363
backend_key_data(&mut write, process_id, secret_key).await?;
361364
ready_for_query(&mut write).await?;
362365

src/messages.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use tokio::net::TcpStream;
77

88
use crate::errors::Error;
99
use std::collections::HashMap;
10+
use std::mem;
1011

1112
/// Postgres data type mappings
1213
/// used in RowDescription ('T') message.
@@ -498,3 +499,20 @@ where
498499

499500
Ok(bytes)
500501
}
502+
503+
pub fn server_paramater_message(key: &str, value: &str) -> BytesMut {
504+
let mut server_info = BytesMut::new();
505+
506+
let null_byte_size = 1;
507+
let len: usize =
508+
mem::size_of::<i32>() + key.len() + null_byte_size + value.len() + null_byte_size;
509+
510+
server_info.put_slice("S".as_bytes());
511+
server_info.put_i32(len.try_into().unwrap());
512+
server_info.put_slice(key.as_bytes());
513+
server_info.put_bytes(0, 1);
514+
server_info.put_slice(value.as_bytes());
515+
server_info.put_bytes(0, 1);
516+
517+
return server_info;
518+
}

tests/python/tests.py

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,22 @@
11
import psycopg2
22

3-
conn = psycopg2.connect("postgres://random:password@127.0.0.1:6432/db")
4-
cur = conn.cursor()
3+
def test_normal_db_access():
4+
conn = psycopg2.connect("postgres://sharding_user:sharding_user@127.0.0.1:6432/sharded_db?application_name=testing_pgcat")
5+
cur = conn.cursor()
56

6-
cur.execute("SELECT 1");
7-
res = cur.fetchall()
7+
cur.execute("SELECT 1")
8+
res = cur.fetchall()
9+
print(res)
810

9-
print(res)
1011

11-
# conn.commit()
12+
def test_admin_db_access():
13+
conn = psycopg2.connect("postgres://user:pass@127.0.0.1:6432/pgcat")
14+
conn.autocommit = True # BEGIN/COMMIT is not supported by admin db
15+
cur = conn.cursor()
16+
17+
cur.execute("SHOW POOLS")
18+
res = cur.fetchall()
19+
print(res)
20+
21+
test_normal_db_access()
22+
test_admin_db_access()

tests/ruby/tests.rb

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,3 +128,16 @@ def poorly_behaved_client
128128
25.times do
129129
poorly_behaved_client
130130
end
131+
132+
133+
def test_server_parameters
134+
server_conn = PG::connect("postgres://sharding_user:sharding_user@127.0.0.1:6432/sharded_db?application_name=testing_pgcat")
135+
raise StandardError, "Bad server version" if server_conn.server_version == 0
136+
server_conn.close
137+
138+
admin_conn = PG::connect("postgres://admin_user:admin_pass@127.0.0.1:6432/pgcat")
139+
raise StandardError, "Bad server version" if admin_conn.server_version == 0
140+
admin_conn.close
141+
142+
puts 'Server parameters ok'
143+
end

0 commit comments

Comments
 (0)