28
28
import pwd
29
29
import tempfile
30
30
import shutil
31
+ import time
31
32
32
33
# Try to use psycopg2 by default. If psycopg2 isn"t available then use
33
34
# pg8000 which is slower but much more portable because uses only
45
46
last_assigned_port = int (random .random () * 16384 ) + 49152 ;
46
47
47
48
48
- class ClusterException (Exception ):
49
- pass
49
+ class ClusterException (Exception ): pass
50
+ class QueryException ( Exception ): pass
50
51
51
52
52
53
class PostgresNode :
53
54
def __init__ (self , name , port ):
54
55
self .name = name
56
+ self .host = '127.0.0.1'
55
57
self .port = port
56
58
self .base_dir = tempfile .mkdtemp ()
57
59
os .makedirs (self .logs_dir )
@@ -75,6 +77,11 @@ def output_filename(self):
75
77
def error_filename (self ):
76
78
return "%s/stderr.log" % self .logs_dir
77
79
80
+ @property
81
+ def connstr (self ):
82
+ return "port=%s" % self .port
83
+ # return "port=%s host=%s" % (self.port, self.host)
84
+
78
85
def load_pg_config (self ):
79
86
""" Loads pg_config output into dict """
80
87
pg_config = os .environ .get ("PG_CONFIG" ) \
@@ -116,6 +123,10 @@ def init(self, allows_streaming=False):
116
123
"fsync = off\n "
117
124
"log_statement = all\n "
118
125
"port = %s\n " % self .port )
126
+ conf .write (
127
+ # "unix_socket_directories = '%s'\n"
128
+ # "listen_addresses = ''\n";)
129
+ "listen_addresses = '%s'\n " % self .host )
119
130
120
131
if allows_streaming :
121
132
conf .write (
@@ -129,7 +140,7 @@ def init(self, allows_streaming=False):
129
140
"max_connections = 10\n " )
130
141
self .set_replication_conf ()
131
142
132
- def init_from_backup (self , root_node , backup_name ):
143
+ def init_from_backup (self , root_node , backup_name , has_streaming = False , hba_permit_replication = True ):
133
144
"""Initializes cluster from backup, made by another node"""
134
145
135
146
# Copy data from backup
@@ -142,11 +153,25 @@ def init_from_backup(self, root_node, backup_name):
142
153
"postgresql.conf" ,
143
154
"port = %s" % self .port
144
155
)
156
+ # Enable streaming
157
+ if hba_permit_replication :
158
+ self .set_replication_conf ()
159
+ if has_streaming :
160
+ self .enable_streaming (root_node )
145
161
146
162
def set_replication_conf (self ):
147
163
hba_conf = "%s/pg_hba.conf" % self .data_dir
148
164
with open (hba_conf , "a" ) as conf :
149
165
conf .write ("local replication all trust\n " )
166
+ # conf.write("host replication all 127.0.0.1/32 trust\n")
167
+
168
+ def enable_streaming (self , root_node ):
169
+ config_name = "%s/recovery.conf" % self .data_dir
170
+ with open (config_name , "a" ) as conf :
171
+ conf .write (
172
+ "primary_conninfo='%s application_name=%s'\n "
173
+ "standby_mode=on\n "
174
+ % (root_node .connstr , self .name ))
150
175
151
176
def append_conf (self , filename , string ):
152
177
"""Appends line to a config file like "postgresql.conf"
@@ -254,6 +279,22 @@ def safe_psql(self, dbname, query):
254
279
raise ClusterException ("psql failed:\n " + err )
255
280
return out
256
281
282
+ def poll_query_until (self , dbname , query ):
283
+ """Runs a query once a second until it returs True"""
284
+ max_attemps = 60
285
+ attemps = 0
286
+
287
+ while attemps < max_attemps :
288
+ ret = self .safe_psql (dbname , query )
289
+
290
+ # TODO: fix psql so that it returns result without newline
291
+ if ret == "t\n " :
292
+ return
293
+
294
+ time .sleep (1 )
295
+ attemps += 1
296
+ raise QueryException ("Timeout while waiting for query to return True" )
297
+
257
298
def execute (self , dbname , query ):
258
299
"""Executes the query and returns all rows"""
259
300
connection = pglib .connect (
@@ -327,3 +368,8 @@ def clean_all():
327
368
for node in registered_nodes :
328
369
node .cleanup ()
329
370
registered_nodes = []
371
+
372
+ def stop_all ():
373
+ global registered_nodes
374
+ for node in registered_nodes :
375
+ node .stop ()
0 commit comments