Skip to content

Commit 2499255

Browse files
committed
Fix PostgresDump when connecting via the system’s hostname
1 parent 5fe335a commit 2499255

File tree

3 files changed

+138
-7
lines changed

3 files changed

+138
-7
lines changed
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
--
2+
-- PostgreSQL database dump
3+
--
4+
5+
-- Dumped from database version 17.0 (Debian 17.0-1.pgdg120+1)
6+
-- Dumped by pg_dump version 17.0 (Debian 17.0-1.pgdg120+1)
7+
8+
SET statement_timeout = 0;
9+
SET lock_timeout = 0;
10+
SET idle_in_transaction_session_timeout = 0;
11+
SET transaction_timeout = 0;
12+
SET client_encoding = 'UTF8';
13+
SET standard_conforming_strings = on;
14+
SELECT pg_catalog.set_config('search_path', '', false);
15+
SET check_function_bodies = false;
16+
SET xmloption = content;
17+
SET client_min_messages = warning;
18+
SET row_security = off;
19+
20+
--
21+
-- Name: other_schema; Type: SCHEMA; Schema: -; Owner: test-user
22+
--
23+
24+
CREATE SCHEMA other_schema;
25+
26+
27+
ALTER SCHEMA other_schema OWNER TO "test-user";
28+
29+
SET default_tablespace = '';
30+
31+
SET default_table_access_method = heap;
32+
33+
--
34+
-- Name: persons; Type: TABLE; Schema: other_schema; Owner: test-user
35+
--
36+
37+
CREATE TABLE other_schema.persons (
38+
id integer NOT NULL,
39+
name text NOT NULL
40+
);
41+
42+
43+
ALTER TABLE other_schema.persons OWNER TO "test-user";
44+
45+
--
46+
-- Name: employees; Type: TABLE; Schema: public; Owner: test-user
47+
--
48+
49+
CREATE TABLE public.employees (
50+
id integer NOT NULL,
51+
first_name character varying(50),
52+
last_name character varying(50),
53+
email character varying(100),
54+
hire_date date,
55+
salary numeric(10,2)
56+
);
57+
58+
59+
ALTER TABLE public.employees OWNER TO "test-user";
60+
61+
--
62+
-- Data for Name: persons; Type: TABLE DATA; Schema: other_schema; Owner: test-user
63+
--
64+
65+
COPY other_schema.persons (id, name) FROM stdin;
66+
1 John
67+
2 Jane
68+
3 Emily
69+
\.
70+
71+
72+
--
73+
-- Data for Name: employees; Type: TABLE DATA; Schema: public; Owner: test-user
74+
--
75+
76+
COPY public.employees (id, first_name, last_name, email, hire_date, salary) FROM stdin;
77+
1 John Doe john.doe@example.com 2022-01-15 60000.00
78+
2 Jane Smith jane.smith@example.com 2023-03-22 75000.00
79+
3 Emily Johnson emily.johnson@example.com 2021-05-10 50000.00
80+
4 Michael Brown michael.brown@example.com 2020-08-30 80000.00
81+
5 Sarah Davis sarah.davis@example.com 2024-06-01 70000.00
82+
\.
83+
84+
85+
--
86+
-- Name: persons persons_pkey; Type: CONSTRAINT; Schema: other_schema; Owner: test-user
87+
--
88+
89+
ALTER TABLE ONLY other_schema.persons
90+
ADD CONSTRAINT persons_pkey PRIMARY KEY (id);
91+
92+
93+
--
94+
-- Name: employees employees_pkey; Type: CONSTRAINT; Schema: public; Owner: test-user
95+
--
96+
97+
ALTER TABLE ONLY public.employees
98+
ADD CONSTRAINT employees_pkey PRIMARY KEY (id);
99+
100+
101+
--
102+
-- PostgreSQL database dump complete
103+
--

src/main/java/de/cronn/postgres/snapshot/util/PostgresUtils.java

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,8 @@ static GenericContainer<?> createPostgresContainer(String postgresVersion) {
4444

4545
static ConnectionInformation parseConnectionInformation(String jdbcUrl, String username, String password) {
4646
URI databaseUri = toUri(jdbcUrl);
47-
ContainerAndNetwork containerAndNetwork = findDockerContainer(databaseUri.getHost());
47+
String host = prepareHostname(databaseUri.getHost());
48+
ContainerAndNetwork containerAndNetwork = findDockerContainer(host);
4849

4950
if (containerAndNetwork != null) {
5051
String postgresVersion = findPostgresVersionOfRunningContainer(containerAndNetwork.inspectResponse());
@@ -53,25 +54,36 @@ static ConnectionInformation parseConnectionInformation(String jdbcUrl, String u
5354
throw new IllegalArgumentException("Unexpected path: " + databaseUriPath);
5455
}
5556
String databaseName = databaseUriPath.substring(1);
56-
String host = databaseUri.getHost();
5757
int port = databaseUri.getPort();
5858
String dockerNetworkId = containerAndNetwork.network().getNetworkID();
5959
return new ConnectionInformation(postgresVersion, host, dockerNetworkId, port, databaseName, username, password);
60-
6160
} else {
6261
try (Connection connection = DriverManager.getConnection(jdbcUrl, username, password)) {
6362
DatabaseMetaData metaData = connection.getMetaData();
6463
String postgresVersion = "%d.%d".formatted(metaData.getDatabaseMajorVersion(), metaData.getDatabaseMinorVersion());
6564
String databaseName = connection.getCatalog();
66-
String host = prepareHostname(databaseUri.getHost());
6765
int port = databaseUri.getPort();
68-
return new ConnectionInformation(postgresVersion, host, null, port, databaseName, username, password);
66+
String resolvedHost = resolveHostIfNecessary(host);
67+
return new ConnectionInformation(postgresVersion, resolvedHost, null, port, databaseName, username, password);
6968
} catch (SQLException e) {
7069
throw new RuntimeException(e);
7170
}
7271
}
7372
}
7473

74+
private static String resolveHostIfNecessary(String host) {
75+
if (isDockerHostInternal(host)) {
76+
return host;
77+
} else {
78+
try {
79+
return InetAddress.getByName(host).getHostAddress();
80+
} catch (UnknownHostException e) {
81+
log.warn("Failed to resolve '{}'", host, e);
82+
return host;
83+
}
84+
}
85+
}
86+
7587
private static String findPostgresVersionOfRunningContainer(InspectContainerResponse containerInfo) {
7688
DockerClient client = DockerClientFactory.instance().client();
7789
try {
@@ -100,7 +112,7 @@ private record ContainerAndNetwork(InspectContainerResponse inspectResponse, Con
100112
}
101113

102114
static ContainerAndNetwork findDockerContainer(String host) {
103-
if (isLocalhost(host)) {
115+
if (isDockerHostInternal(host)) {
104116
return null;
105117
}
106118

@@ -161,12 +173,18 @@ static boolean isLocalhost(String host) {
161173
}
162174

163175
static String deriveNetworkMode(ConnectionInformation connectionInformation) {
164-
if (connectionInformation.host().equals(PostgresConstants.DOCKER_HOST_INTERNAL)) {
176+
if (isDockerHostInternal(connectionInformation.host())) {
165177
return null;
166178
} else if (connectionInformation.dockerNetworkId() != null) {
179+
log.debug("Using Docker network '{}'", connectionInformation.dockerNetworkId());
167180
return connectionInformation.dockerNetworkId();
168181
} else {
182+
log.debug("Using network mode 'host'");
169183
return "host";
170184
}
171185
}
186+
187+
private static boolean isDockerHostInternal(String host) {
188+
return host.equals(PostgresConstants.DOCKER_HOST_INTERNAL);
189+
}
172190
}

src/test/java/de/cronn/postgres/snapshot/util/PostgresDumpTest.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
import java.io.OutputStream;
66
import java.io.Writer;
7+
import java.net.InetAddress;
78
import java.nio.charset.StandardCharsets;
89
import java.nio.file.Files;
910
import java.nio.file.Path;
@@ -168,6 +169,15 @@ void testDumpWithIllegalParameters() {
168169
PostgresDumpOption.SCHEMA_ONLY, PostgresDumpOption.DATA_ONLY))
169170
.withMessageStartingWith("Container startup failed for image postgres:");
170171
}
172+
173+
@Test
174+
void testConnectViaHostName() throws Exception {
175+
String jdbcUrl = postgresContainer.getJdbcUrl();
176+
assertThat(jdbcUrl).contains("://localhost:");
177+
String replacedJdbcUrl = jdbcUrl.replaceFirst("localhost:", InetAddress.getLocalHost().getHostName() + ":");
178+
String schema = PostgresDump.dumpToString(replacedJdbcUrl, USERNAME, PASSWORD);
179+
compareActualWithValidationFile(schema);
180+
}
171181
}
172182

173183
@Test

0 commit comments

Comments
 (0)