Skip to content

Commit

Permalink
Add a primary key to all tables that lack one
Browse files Browse the repository at this point in the history
For logical replication, Postgres requires that all tables have a
primary key.  This commit adds primary keys to tables like the
databasechangelog and join tables.  It also adds the
"pg_stat_statements" library to our database container so that we can
monitor queries in development.

"A published table must have a 'replica identity' configured in order to
be able to replicate UPDATE and DELETE operations, so that appropriate
rows to update or delete can be identified on the subscriber side. By
default, this is the primary key, if there is one."

From https://www.postgresql.org/docs/12/logical-replication-publication.html

Also alter testcontainers to make the rhsm-subscriptions user a
superuser so we can create extensions in those containers as well.
  • Loading branch information
awood committed Dec 13, 2024
1 parent d70a14f commit 2b99b56
Show file tree
Hide file tree
Showing 7 changed files with 161 additions and 1 deletion.
5 changes: 4 additions & 1 deletion init_dbs.sh
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
#!/bin/bash
#!/bin/bash -x
# https://github.com/olivergondza/bash-strict-mode
set -eEuo pipefail
trap 's=$?; echo >&2 "$0: Error on line "$LINENO": $BASH_COMMAND"; exit $s' ERR

if [[ -v POSTGRESQL_USER || -v POSTGRESQL_PASSWORD || -v POSTGRESQL_DATABASE ]]; then
cat >&2 <<EOF
Expand Down
1 change: 1 addition & 0 deletions postgresql.conf
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
hba_file = '/pg_hba.conf'
listen_addresses = '*'
shared_preload_libraries = 'pg_stat_statements'
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
<?xml version="1.0" encoding="UTF-8"?>
<databaseChangeLog
xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog
http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.20.xsd">
<!--
These changeSets are only for PostgreSQL because the primary keys we're adding are just to satisfy
PostgreSQL's requirements for logical replication. See
https://www.postgresql.org/docs/12/logical-replication-publication.html
Consequently, these keys aren't mapped in JPA so we don't need to worry about them during
in-memory DB tests.
-->
<changeSet id="202412041537-01" author="awood" dbms="postgresql">
<!--
Creating an extension requires superuser permissions. But in production and stage, we don't
have those permissions. We have to create the extension in an out-of-band migration.
The creation command checks permissions before it checks the extensions existence, so even an
invocation that would have no effect will cause the changeset to fail. Accordingly, we have to
have a pre-condition to check if we should even attempt to create the extension. That way we
can use the same changeset in both development and production.
-->
<preConditions onFail="MARK_RAN">
<sqlCheck expectedResult="0">
SELECT count(1) FROM pg_extension WHERE extname = 'uuid-ossp';
</sqlCheck>
</preConditions>

<sql>
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
</sql>
<!--
I am intentionally not providing a rollback because we have two change logs: this one and
the one for swatch-contracts. Rolling back the extension in one changelog could adversely
affect the operations of the other changelog.
-->
</changeSet>

<changeSet id="202412041537-02" author="awood" dbms="postgresql">
<addColumn tableName="databasechangelog">
<column name="uuid" type="uuid" defaultValueComputed="uuid_generate_v4()">
<constraints primaryKey="true" nullable="false"/>
</column>
</addColumn>
</changeSet>

<changeSet id="202412041537-03" author="awood" dbms="postgresql">
<addColumn tableName="sku_child_sku">
<column name="id" type="uuid" defaultValueComputed="uuid_generate_v4()">
<constraints primaryKey="true" nullable="false"/>
</column>
</addColumn>
</changeSet>

<changeSet id="202412041537-04" author="awood" dbms="postgresql">
<addColumn tableName="sku_oid">
<column name="id" type="uuid" defaultValueComputed="uuid_generate_v4()">
<constraints primaryKey="true" nullable="false"/>
</column>
</addColumn>
</changeSet>

<changeSet id="202412041537-05" author="awood" dbms="postgresql">
<addColumn tableName="sku_product_tag">
<column name="id" type="uuid" defaultValueComputed="uuid_generate_v4()">
<constraints primaryKey="true" nullable="false"/>
</column>
</addColumn>
</changeSet>
</databaseChangeLog>
1 change: 1 addition & 0 deletions src/main/resources/liquibase/changelog.xml
Original file line number Diff line number Diff line change
Expand Up @@ -175,5 +175,6 @@
<include file="/liquibase/202410021300-update_usages_to_unknown.xml"/>
<include file="/liquibase/202410211200-retry-after-billable-usage-index.xml"/>
<include file="/liquibase/202410241408-clear-retryable.xml"/>
<include file="/liquibase/202412041537-primary-keys-on-all-tables.xml"/>
</databaseChangeLog>
<!-- vim: set expandtab sts=4 sw=4 ai: -->
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,15 @@
*/
package org.candlepin.testcontainers;

import com.github.dockerjava.api.command.InspectContainerResponse;
import java.io.IOException;
import java.util.UUID;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import lombok.EqualsAndHashCode;
import lombok.SneakyThrows;
import org.candlepin.testcontainers.exceptions.ExecuteStatementInContainerException;
import org.testcontainers.containers.ContainerLaunchException;
import org.testcontainers.containers.PostgreSQLContainer;
import org.testcontainers.containers.wait.strategy.Wait;
import org.testcontainers.utility.DockerImageName;
Expand Down Expand Up @@ -64,6 +67,30 @@ public void insertRow(String table, String[] columns, String[] values) {
+ ")");
}

@SneakyThrows(InterruptedException.class)
@Override
protected void containerIsStarted(InspectContainerResponse containerInfo) {
try {
super.containerIsStarted(containerInfo);
var result =
execInContainer(
"/usr/bin/psql",
"--user=postgres",
"--command=ALTER USER \"" + getUsername() + "\" WITH SUPERUSER;");
if (result.getExitCode() != 0) {
throw new ContainerLaunchException(
"Could not alter user "
+ getUsername()
+ "\nSTDOUT: "
+ result.getStdout()
+ "\nSTDERR: "
+ result.getStderr());
}
} catch (IOException e) {
throw new ContainerLaunchException("Could not launch container", e);
}
}

@Override
protected void configure() {
super.configure();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
<?xml version="1.0" encoding="UTF-8"?>
<databaseChangeLog
xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog
http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.20.xsd">
<!--
These changeSets are only for PostgreSQL because the primary keys we're adding are just to satisfy
PostgreSQL's requirements for logical replication. See
https://www.postgresql.org/docs/12/logical-replication-publication.html
Consequently, these keys aren't mapped in JPA so we don't need to worry about them during
in-memory DB tests.
-->
<changeSet id="202412051144-01" author="awood" dbms="postgresql">
<!--
Creating an extension requires superuser permissions. But in production and stage, we don't
have those permissions. We have to create the extension in an out-of-band migration.
The creation command checks permissions before it checks the extensions existence, so even an
invocation that would have no effect will cause the changeset to fail. Accordingly, we have to
have a pre-condition to check if we should even attempt to create the extension. That way we
can use the same changeset in both development and production.
-->
<preConditions onFail="MARK_RAN">
<sqlCheck expectedResult="0">
SELECT count(1) FROM pg_extension WHERE extname = 'uuid-ossp';
</sqlCheck>
</preConditions>
<sql>
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
</sql>
<!--
I am intentionally not providing a rollback because we have two change logs: this one and
the one for swatch-contracts. Rolling back the extension in one changelog could adversely
affect the operations of the other changelog.
-->
</changeSet>

<changeSet id="202412051144-02" author="awood" dbms="postgresql">
<addColumn tableName="databasechangelog_swatch_contracts">
<column name="uuid" type="uuid" defaultValueComputed="uuid_generate_v4()">
<constraints primaryKey="true" nullable="false"/>
</column>
</addColumn>
</changeSet>

<changeSet id="202412051144-03" author="awood" dbms="postgresql">
<addColumn tableName="contract_metrics">
<column name="id" type="uuid" defaultValueComputed="uuid_generate_v4()">
<constraints primaryKey="true" nullable="false"/>
</column>
</addColumn>
</changeSet>
</databaseChangeLog>
1 change: 1 addition & 0 deletions swatch-contracts/src/main/resources/db/changeLog.xml
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,5 @@
<include file="db/202406111405_change_billing_account_id_nullable.xml"/>
<include file="db/202407081616-add-level-columns-for-offering-table_h2_only.xml"/>
<include file="db/202410171500-move-subscription-capacity-view_h2_only.xml"/>
<include file="db/202412051144-primary-keys-on-changelog-table.xml"/>
</databaseChangeLog>

0 comments on commit 2b99b56

Please sign in to comment.