14
14
package io .zonky .test .db .postgres .embedded ;
15
15
16
16
17
- import java .io .ByteArrayInputStream ;
18
- import java .io .Closeable ;
19
- import java .io .File ;
20
- import java .io .FileOutputStream ;
21
- import java .io .IOException ;
22
- import java .io .InputStream ;
17
+ import java .io .*;
23
18
import java .net .InetAddress ;
24
19
import java .net .InetSocketAddress ;
25
20
import java .net .ServerSocket ;
@@ -104,6 +99,7 @@ public class EmbeddedPostgres implements Closeable
104
99
private volatile FileOutputStream lockStream ;
105
100
private volatile FileLock lock ;
106
101
private final boolean cleanDataDirectory ;
102
+ private boolean useUnshare = false ;
107
103
108
104
private final ProcessBuilder .Redirect errorRedirector ;
109
105
private final ProcessBuilder .Redirect outputRedirector ;
@@ -133,6 +129,28 @@ public class EmbeddedPostgres implements Closeable
133
129
this .pgStartupWait = pgStartupWait ;
134
130
Objects .requireNonNull (this .pgStartupWait , "Wait time cannot be null" );
135
131
132
+ if (SystemUtils .IS_OS_LINUX ) {
133
+ int uid = (int ) new com .sun .security .auth .module .UnixSystem ().getUid ();
134
+ if (uid == 0 ) {
135
+ final List <String > command = new ArrayList <>();
136
+ command .addAll (Arrays .asList (
137
+ "unshare" , "-U" ,
138
+ "id" , "-u"
139
+ ));
140
+ final ProcessBuilder builder = new ProcessBuilder (command );
141
+ final Process process = builder .start ();
142
+ BufferedReader br = new BufferedReader (new InputStreamReader (process .getInputStream ()));
143
+ try {
144
+ process .waitFor ();
145
+ } catch (InterruptedException e ) {
146
+ throw new RuntimeException (e );
147
+ }
148
+ if (process .exitValue () == 0 && br .readLine () != "0" ) {
149
+ useUnshare = true ;
150
+ }
151
+ }
152
+ }
153
+
136
154
if (parentDirectory != null ) {
137
155
mkdirs (parentDirectory );
138
156
cleanOldDataDirectories (parentDirectory );
@@ -186,8 +204,8 @@ public DataSource getDatabase(String userName, String dbName) {
186
204
public DataSource getDatabase (String userName , String dbName , Map <String , String > properties )
187
205
{
188
206
final PGSimpleDataSource ds = new PGSimpleDataSource ();
189
- ds .setServerName ( "localhost" );
190
- ds .setPortNumber ( port );
207
+ ds .setServerNames ( new String [] { "localhost" } );
208
+ ds .setPortNumbers ( new int [] { port } );
191
209
ds .setDatabaseName (dbName );
192
210
ds .setUser (userName );
193
211
@@ -243,10 +261,10 @@ private void initdb()
243
261
watch .start ();
244
262
List <String > command = new ArrayList <>();
245
263
command .addAll (Arrays .asList (
246
- pgBin ( "initdb" ), "-A" , "trust" , "-U" , PG_SUPERUSER ,
264
+ "-A" , "trust" , "-U" , PG_SUPERUSER ,
247
265
"-D" , dataDirectory .getPath (), "-E" , "UTF-8" ));
248
266
command .addAll (createLocaleOptions ());
249
- system (command . toArray ( new String [ command . size ()]) );
267
+ system (pgBin ( "initdb" ), command );
250
268
LOG .info ("{} initdb completed in {}" , instanceId , watch );
251
269
}
252
270
@@ -259,13 +277,11 @@ private void startPostmaster() throws IOException
259
277
}
260
278
261
279
final List <String > args = new ArrayList <>();
280
+ args .addAll (pgBin ("postgres" ));
262
281
args .addAll (Arrays .asList (
263
- pgBin ("pg_ctl" ),
264
- "-D" , dataDirectory .getPath (),
265
- "-o" , createInitOptions ().stream ().collect (Collectors .joining (" " )),
266
- "-w" ,
267
- "start"
282
+ "-D" , dataDirectory .getPath ()
268
283
));
284
+ args .addAll (createInitOptions ());
269
285
270
286
final ProcessBuilder builder = new ProcessBuilder (args );
271
287
@@ -275,7 +291,7 @@ private void startPostmaster() throws IOException
275
291
final Process postmaster = builder .start ();
276
292
277
293
if (outputRedirector .type () == ProcessBuilder .Redirect .Type .PIPE ) {
278
- ProcessOutputLogger .logOutput (LOG , postmaster , "pg_ctl " );
294
+ ProcessOutputLogger .logOutput (LOG , postmaster , "postgres " );
279
295
}
280
296
281
297
LOG .info ("{} postmaster started as {} on port {}. Waiting up to {} for server startup to finish." , instanceId , postmaster .toString (), port , pgStartupWait );
@@ -414,7 +430,13 @@ public void close() throws IOException
414
430
415
431
private void pgCtl (File dir , String action )
416
432
{
417
- system (pgBin ("pg_ctl" ), "-D" , dir .getPath (), action , "-m" , PG_STOP_MODE , "-t" , PG_STOP_WAIT_S , "-w" );
433
+ final List <String > args = new ArrayList <>();
434
+ args .addAll (Arrays .asList (
435
+ "-D" , dir .getPath (), action ,
436
+ "-m" , PG_STOP_MODE , "-t" ,
437
+ PG_STOP_WAIT_S , "-w"
438
+ ));
439
+ system (pgBin ("pg_ctl" ), args );
418
440
}
419
441
420
442
private void cleanOldDataDirectories (File parentDirectory )
@@ -461,10 +483,17 @@ private void cleanOldDataDirectories(File parentDirectory)
461
483
}
462
484
}
463
485
464
- private String pgBin (String binaryName )
486
+ private List < String > pgBin (String binaryName )
465
487
{
488
+ final List <String > args = new ArrayList <>();
489
+ if (useUnshare ) {
490
+ args .addAll (Arrays .asList (
491
+ "unshare" , "-U"
492
+ ));
493
+ }
466
494
final String extension = SystemUtils .IS_OS_WINDOWS ? ".exe" : "" ;
467
- return new File (pgDir , "bin/" + binaryName + extension ).getPath ();
495
+ args .add (new File (pgDir , "bin/" + binaryName + extension ).getPath ());
496
+ return args ;
468
497
}
469
498
470
499
private static File getWorkingDirectory ()
@@ -614,8 +643,11 @@ public int hashCode() {
614
643
}
615
644
}
616
645
617
- private void system (String ... command )
646
+ private void system (List < String > bin , List < String > args )
618
647
{
648
+ final List <String > command = new ArrayList <>();
649
+ command .addAll (bin );
650
+ command .addAll (args );
619
651
try {
620
652
final ProcessBuilder builder = new ProcessBuilder (command );
621
653
builder .redirectErrorStream (true );
@@ -624,7 +656,7 @@ private void system(String... command)
624
656
final Process process = builder .start ();
625
657
626
658
if (outputRedirector .type () == ProcessBuilder .Redirect .Type .PIPE ) {
627
- String processName = command [ 0 ] .replaceAll ("^.*[\\ \\ /](\\ w+)(\\ .exe)?$" , "$1" );
659
+ String processName = bin . get ( bin . size () - 1 ) .replaceAll ("^.*[\\ \\ /](\\ w+)(\\ .exe)?$" , "$1" );
628
660
ProcessOutputLogger .logOutput (LOG , process , processName );
629
661
}
630
662
if (0 != process .waitFor ()) {
0 commit comments