1 #include "../../uwsgi.h"
2 #include <libpq-fe.h>
3 
4 extern struct uwsgi_server uwsgi;
5 extern struct uwsgi_instance *ui;
6 
7 void uwsgi_imperial_monitor_pg_init(struct uwsgi_emperor_scanner *);
8 void uwsgi_imperial_monitor_pg(struct uwsgi_emperor_scanner *);
9 void emperor_pg_init(void);
10 
emperor_pg_init(void)11 void emperor_pg_init(void) {
12 	uwsgi_register_imperial_monitor("pg", uwsgi_imperial_monitor_pg_init, uwsgi_imperial_monitor_pg);
13 }
14 
uwsgi_imperial_monitor_pg_init(struct uwsgi_emperor_scanner * ues)15 void uwsgi_imperial_monitor_pg_init(struct uwsgi_emperor_scanner *ues) {
16 	uwsgi_log("[emperor] enabled emperor PostgreSQL monitor\n");
17 }
18 
uwsgi_imperial_monitor_pg(struct uwsgi_emperor_scanner * ues)19 void uwsgi_imperial_monitor_pg(struct uwsgi_emperor_scanner *ues) {
20 
21 	PGconn *conn = NULL;
22 	PGresult *res = NULL;
23 	const char *query = "SELECT name,config,EXTRACT(epoch FROM ts) FROM vassals";
24 
25 	char *conn_string = uwsgi_str(ues->arg + 5);
26 
27 	char *semicolon = strchr(conn_string, ';');
28 	if (semicolon) {
29 		query = semicolon + 1;
30 		*semicolon = '\0';
31 	}
32 #ifdef UWSGI_DEBUG
33 	uwsgi_log("connecting to PgSQL %s\n", conn_string);
34 #endif
35 	conn = PQconnectdb(conn_string);
36 	if (!conn || PQstatus(conn) != CONNECTION_OK) {
37 		uwsgi_log("libpq-error: %s", PQerrorMessage(conn));
38 		goto end;
39 	}
40 
41 	res = PQexec(conn, query);
42 	if (!res || PQresultStatus(res) != PGRES_TUPLES_OK) {
43 		uwsgi_log("libpq-error: %s\n", PQerrorMessage(conn));
44 		goto end;
45 	}
46 
47 	int i;
48 
49 	for (i = 0; i < PQntuples(res); i++) {
50 		if (PQnfields(res) >= 3) {
51 			char *name = PQgetvalue(res, i, 0);
52 			char *config = PQgetvalue(res, i, 1);
53 			char *ts = PQgetvalue(res, i, 2);
54 			int len = strlen(ts);
55 			char *dot = strchr(ts, '.');
56 			if (dot) {
57 				len = dot - ts;
58 			}
59 			uid_t vassal_uid = 0;
60 			gid_t vassal_gid = 0;
61 			if (uwsgi.emperor_tyrant) {
62 				if (PQnfields(res) < 5) {
63 					uwsgi_log("[emperor-pg] missing uid and gid for vassal %s\n", name);
64 					continue;
65 				}
66 				char *q_uid = PQgetvalue(res, i, 3);
67 				char *q_gid = PQgetvalue(res, i, 4);
68 				vassal_uid = uwsgi_str_num(q_uid, strlen(q_uid));
69 				vassal_gid = uwsgi_str_num(q_gid, strlen(q_gid));
70 			}
71 			char *socket_name = NULL;
72 			if (PQnfields(res) > 5) {
73 				socket_name = PQgetvalue(res, i, 5);
74 			}
75 			uwsgi_emperor_simple_do(ues, name, config, uwsgi_str_num(ts, len), vassal_uid, vassal_gid, socket_name);
76 		}
77 	}
78 
79 	// now check for removed instances
80         struct uwsgi_instance *c_ui = ui->ui_next;
81 
82         while (c_ui) {
83                 if (c_ui->scanner == ues) {
84 			int found = 0;
85 			for (i = 0; i < PQntuples(res); i++) {
86 				if (PQnfields(res) >= 3) {
87 					if (!strcmp(PQgetvalue(res, i, 0), c_ui->name)) {
88 						found = 1;
89 						break;
90 					}
91 				}
92 			}
93 			if (!found) {
94                                 emperor_stop(c_ui);
95                         }
96                 }
97                 c_ui = c_ui->ui_next;
98         }
99 
100 
101 end:
102 	free(conn_string);
103 
104 	if (res)
105 		PQclear(res);
106 	if (conn)
107 		PQfinish(conn);
108 }
109 
110 
111 struct uwsgi_plugin emperor_pg_plugin = {
112 
113 	.name = "emperor_pg",
114 	.on_load = emperor_pg_init,
115 };
116