-
Notifications
You must be signed in to change notification settings - Fork 1k
Add SSL support for backend connections in PGSQL monitor #5237
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
Open
rahim-kanji
wants to merge
4
commits into
v3.0
Choose a base branch
from
v3.0_pgsql-monitor-sslsupport-5205
base: v3.0
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
7205f42
Add SSL support for backend connections in PGSQL monitor
rahim-kanji fae283c
Add SSL and non-SSL connection OK metrics for PostgreSQL monitor conn…
rahim-kanji 0e7b5e2
Added TAP test
rahim-kanji d1b003a
Added TAP test to groups.json
rahim-kanji File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
191 changes: 191 additions & 0 deletions
191
test/tap/tests/pgsql-monitor_ssl_connections_test-t.cpp
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,191 @@ | ||
| /** | ||
| * @file pgsql-monitor_ssl_connections_test-t.cpp | ||
| * @brief Intention: validate that ProxySQL's PostgreSQL monitor correctly establishes SSL and non-SSL | ||
| * connections depending on server configuration. The test runs in two phases: first with `use_ssl=1` | ||
| * to ensure only SSL connection counters increase, and then with `use_ssl=0` to ensure only non-SSL | ||
| * counters increase. | ||
| */ | ||
|
|
||
| #include <unistd.h> | ||
| #include <string> | ||
| #include <sstream> | ||
| #include <chrono> | ||
| #include <thread> | ||
| #include "libpq-fe.h" | ||
| #include "command_line.h" | ||
| #include "tap.h" | ||
| #include "utils.h" | ||
|
|
||
| CommandLine cl; | ||
|
|
||
| using PGConnPtr = std::unique_ptr<PGconn, decltype(&PQfinish)>; | ||
|
|
||
| enum ConnType { | ||
| ADMIN, | ||
| BACKEND | ||
| }; | ||
|
|
||
| PGConnPtr createNewConnection(ConnType conn_type, const std::string& options = "", bool with_ssl = false) { | ||
|
|
||
| const char* host = (conn_type == BACKEND) ? cl.pgsql_host : cl.pgsql_admin_host; | ||
| int port = (conn_type == BACKEND) ? cl.pgsql_port : cl.pgsql_admin_port; | ||
| const char* username = (conn_type == BACKEND) ? cl.pgsql_root_username : cl.admin_username; | ||
| const char* password = (conn_type == BACKEND) ? cl.pgsql_root_password : cl.admin_password; | ||
|
|
||
| std::stringstream ss; | ||
|
|
||
| ss << "host=" << host << " port=" << port; | ||
| ss << " user=" << username << " password=" << password; | ||
| ss << (with_ssl ? " sslmode=require" : " sslmode=disable"); | ||
|
|
||
| if (options.empty() == false) { | ||
| ss << " options='" << options << "'"; | ||
| } | ||
|
|
||
| PGconn* conn = PQconnectdb(ss.str().c_str()); | ||
| if (PQstatus(conn) != CONNECTION_OK) { | ||
| fprintf(stderr, "Connection failed to '%s': %s", (conn_type == BACKEND ? "Backend" : "Admin"), PQerrorMessage(conn)); | ||
| PQfinish(conn); | ||
| return PGConnPtr(nullptr, &PQfinish); | ||
| } | ||
| return PGConnPtr(conn, &PQfinish); | ||
| } | ||
|
|
||
| static long getMonitorValue(PGConnPtr& admin, const char* varname) { | ||
| std::stringstream q; | ||
| q << "SELECT Variable_Value FROM stats_pgsql_global " | ||
| "WHERE Variable_Name='" << varname << "';"; | ||
|
|
||
| PGresult* res = PQexec(admin.get(), q.str().c_str()); | ||
| if (PQresultStatus(res) != PGRES_TUPLES_OK || PQntuples(res) == 0) { | ||
| PQclear(res); | ||
| return -1; | ||
| } | ||
| long v = atol(PQgetvalue(res, 0, 0)); | ||
| PQclear(res); | ||
| return v; | ||
| } | ||
|
|
||
| static long getConnectInterval(PGConnPtr& admin) { | ||
| PGresult* res = PQexec(admin.get(), | ||
| "SELECT Variable_Value FROM global_variables WHERE Variable_Name='pgsql-monitor_connect_interval';" | ||
| ); | ||
| if (PQresultStatus(res) != PGRES_TUPLES_OK || PQntuples(res) == 0) { | ||
| PQclear(res); | ||
| return 1000; // default fallback | ||
| } | ||
| long v = atol(PQgetvalue(res, 0, 0)); | ||
| PQclear(res); | ||
| return v; | ||
| } | ||
|
|
||
| static bool setUseSSL(PGConnPtr& admin, int value) { | ||
| std::stringstream q; | ||
| q << "UPDATE pgsql_servers SET use_ssl=" << value << ";"; | ||
| PGresult* res = PQexec(admin.get(), q.str().c_str()); | ||
| bool ok = PQresultStatus(res) == PGRES_COMMAND_OK; | ||
| PQclear(res); | ||
|
|
||
| PGresult* load = PQexec(admin.get(), "LOAD PGSQL SERVERS TO RUNTIME;"); | ||
| bool ok2 = PQresultStatus(load) == PGRES_COMMAND_OK; | ||
| PQclear(load); | ||
| usleep(10000); | ||
| return ok && ok2; | ||
| } | ||
|
|
||
| static bool setConnectInterval(PGConnPtr& admin, int value) { | ||
| std::stringstream q; | ||
| q << "SET pgsql-monitor_connect_interval=" << value << ";"; | ||
| PGresult* res = PQexec(admin.get(), q.str().c_str()); | ||
| bool ok = PQresultStatus(res) == PGRES_COMMAND_OK; | ||
| PQclear(res); | ||
|
|
||
| PGresult* load = PQexec(admin.get(), "LOAD PGSQL VARIABLES TO RUNTIME;"); | ||
| bool ok2 = PQresultStatus(load) == PGRES_COMMAND_OK; | ||
| PQclear(load); | ||
| usleep(10000); | ||
| return ok && ok2; | ||
| } | ||
|
|
||
| int main(int argc, char** argv) { | ||
|
|
||
| plan(7); | ||
|
|
||
| if (cl.getEnv()) | ||
| return exit_status(); | ||
|
|
||
| // ----------------------------------------- | ||
| // Connect to ADMIN | ||
| // ----------------------------------------- | ||
| auto admin = createNewConnection(ADMIN); | ||
| ok(admin != nullptr, "ADMIN connection created"); | ||
|
|
||
| long original_connect_interval_ms = getConnectInterval(admin); | ||
| diag("Original pgsql-monitor_connect_interval = %ld ms", original_connect_interval_ms); | ||
|
|
||
| setConnectInterval(admin, 2000); // set to 2 second for faster test | ||
| usleep(original_connect_interval_ms * 1000); // microseconds | ||
|
|
||
| long connect_interval_ms = getConnectInterval(admin); | ||
| diag("Updated pgsql-monitor_connect_interval = %ld ms", connect_interval_ms); | ||
|
|
||
| // ############################################################### | ||
| // PHASE 1: TEST SSL (use_ssl = 1) | ||
| // ############################################################### | ||
| diag("---- PHASE 1: Checking SSL monitoring ----"); | ||
|
|
||
| ok(setUseSSL(admin, 1), "Set pgsql_server -> use_ssl = 1"); | ||
|
|
||
| long initial_ssl = getMonitorValue(admin, "PgSQL_Monitor_ssl_connections_OK"); | ||
| long initial_non = getMonitorValue(admin, "PgSQL_Monitor_non_ssl_connections_OK"); | ||
|
|
||
| diag("Initial SSL OK: %ld", initial_ssl); | ||
| diag("Initial NON-SSL OK: %ld", initial_non); | ||
|
|
||
| usleep((connect_interval_ms * 2) * 1000); // microseconds | ||
|
|
||
| long after_ssl = getMonitorValue(admin, "PgSQL_Monitor_ssl_connections_OK"); | ||
| long after_non = getMonitorValue(admin, "PgSQL_Monitor_non_ssl_connections_OK"); | ||
|
|
||
| diag("After SSL mode -> SSL OK: %ld", after_ssl); | ||
| diag("After SSL mode -> NON-SSL OK: %ld", after_non); | ||
|
|
||
| ok(after_ssl > initial_ssl, | ||
| "SSL monitoring increased when use_ssl=1"); | ||
|
|
||
| ok(after_non == initial_non, | ||
| "NON-SSL monitoring unchanged when use_ssl=1"); | ||
|
|
||
| // ############################################################### | ||
| // PHASE 2: TEST NON-SSL (use_ssl = 0) | ||
| // ############################################################### | ||
| diag("---- PHASE 2: Checking NON-SSL monitoring ----"); | ||
|
|
||
| ok(setUseSSL(admin, 0), "Set pgsql_server -> use_ssl = 0"); | ||
|
|
||
| long initial_ssl2 = getMonitorValue(admin, "PgSQL_Monitor_ssl_connections_OK"); | ||
| long initial_non2 = getMonitorValue(admin, "PgSQL_Monitor_non_ssl_connections_OK"); | ||
|
|
||
| diag("Initial SSL OK (phase2): %ld", initial_ssl2); | ||
| diag("Initial NON-SSL OK (phase2): %ld", initial_non2); | ||
|
|
||
| usleep((connect_interval_ms * 2) * 1000); // microseconds | ||
|
|
||
| long after_ssl2 = getMonitorValue(admin, "PgSQL_Monitor_ssl_connections_OK"); | ||
| long after_non2 = getMonitorValue(admin, "PgSQL_Monitor_non_ssl_connections_OK"); | ||
|
|
||
| diag("After NON-SSL mode -> SSL OK: %ld", after_ssl2); | ||
| diag("After NON-SSL mode -> NON-SSL OK: %ld", after_non2); | ||
|
|
||
| ok(after_non2 > initial_non2, | ||
| "NON-SSL monitoring increased when use_ssl=0"); | ||
|
|
||
| ok(after_ssl2 == initial_ssl2, | ||
| "SSL monitoring unchanged when use_ssl=0"); | ||
|
|
||
| diag("SSL + NON-SSL monitoring test completed successfully"); | ||
|
|
||
| setConnectInterval(admin, original_connect_interval_ms); // reset to original value | ||
|
|
||
| return exit_status(); | ||
| } |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.