mirror of
https://github.com/google/nomulus.git
synced 2025-08-03 00:12:11 +02:00
Delete unused actions (#2197)
Both actions have not been used for a while (the wipe out action actually caused problems when it ran unintentionally and wiped out QA). Keeping them around is a burden when refactoring efforts have to take them into consideration. It is always possible to resurrect them form git history should the need arises.
This commit is contained in:
parent
3090df9a78
commit
72e0101746
6 changed files with 17 additions and 371 deletions
|
@ -1,161 +0,0 @@
|
|||
// Copyright 2021 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package google.registry.batch;
|
||||
|
||||
import static com.google.common.net.MediaType.PLAIN_TEXT_UTF_8;
|
||||
import static javax.servlet.http.HttpServletResponse.SC_FORBIDDEN;
|
||||
import static javax.servlet.http.HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
|
||||
import static javax.servlet.http.HttpServletResponse.SC_OK;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.flogger.FluentLogger;
|
||||
import google.registry.config.RegistryEnvironment;
|
||||
import google.registry.persistence.PersistenceModule.SchemaManagerConnection;
|
||||
import google.registry.request.Action;
|
||||
import google.registry.request.Response;
|
||||
import google.registry.request.auth.Auth;
|
||||
import google.registry.util.Retrier;
|
||||
import java.sql.Connection;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
import java.util.function.Supplier;
|
||||
import javax.inject.Inject;
|
||||
|
||||
/**
|
||||
* Wipes out all Cloud SQL data in a Nomulus GCP environment.
|
||||
*
|
||||
* <p>This class is created for the QA environment, where migration testing with production data
|
||||
* will happen. A regularly scheduled wipeout is a prerequisite to using production data there.
|
||||
*/
|
||||
@Action(
|
||||
service = Action.Service.BACKEND,
|
||||
path = "/_dr/task/wipeOutCloudSql",
|
||||
auth = Auth.AUTH_API_ADMIN)
|
||||
public class WipeOutCloudSqlAction implements Runnable {
|
||||
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
|
||||
|
||||
private static final ImmutableSet<RegistryEnvironment> FORBIDDEN_ENVIRONMENTS =
|
||||
ImmutableSet.of(RegistryEnvironment.PRODUCTION, RegistryEnvironment.SANDBOX);
|
||||
|
||||
private final Supplier<Connection> connectionSupplier;
|
||||
private final Response response;
|
||||
private final Retrier retrier;
|
||||
|
||||
@Inject
|
||||
WipeOutCloudSqlAction(
|
||||
@SchemaManagerConnection Supplier<Connection> connectionSupplier,
|
||||
Response response,
|
||||
Retrier retrier) {
|
||||
this.connectionSupplier = connectionSupplier;
|
||||
this.response = response;
|
||||
this.retrier = retrier;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
response.setContentType(PLAIN_TEXT_UTF_8);
|
||||
|
||||
if (FORBIDDEN_ENVIRONMENTS.contains(RegistryEnvironment.get())) {
|
||||
response.setStatus(SC_FORBIDDEN);
|
||||
response.setPayload("Wipeout is not allowed in " + RegistryEnvironment.get());
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
retrier.callWithRetry(
|
||||
() -> {
|
||||
try (Connection conn = connectionSupplier.get()) {
|
||||
dropAllTables(conn, listTables(conn));
|
||||
dropAllSequences(conn, listSequences(conn));
|
||||
}
|
||||
return null;
|
||||
},
|
||||
e -> !(e instanceof SQLException));
|
||||
response.setStatus(SC_OK);
|
||||
response.setPayload("Wiped out Cloud SQL in " + RegistryEnvironment.get());
|
||||
} catch (RuntimeException e) {
|
||||
logger.atSevere().withCause(e).log("Failed to wipe out Cloud SQL data.");
|
||||
response.setStatus(SC_INTERNAL_SERVER_ERROR);
|
||||
response.setPayload("Failed to wipe out Cloud SQL in " + RegistryEnvironment.get());
|
||||
}
|
||||
}
|
||||
|
||||
/** Returns a list of all tables in the public schema of a Postgresql database. */
|
||||
static ImmutableList<String> listTables(Connection connection) throws SQLException {
|
||||
try (ResultSet resultSet =
|
||||
connection.getMetaData().getTables(null, null, null, new String[] {"TABLE"})) {
|
||||
ImmutableList.Builder<String> tables = new ImmutableList.Builder<>();
|
||||
while (resultSet.next()) {
|
||||
String schema = resultSet.getString("TABLE_SCHEM");
|
||||
if (schema == null || !schema.equalsIgnoreCase("public")) {
|
||||
continue;
|
||||
}
|
||||
String tableName = resultSet.getString("TABLE_NAME");
|
||||
tables.add("public.\"" + tableName + "\"");
|
||||
}
|
||||
return tables.build();
|
||||
}
|
||||
}
|
||||
|
||||
static void dropAllTables(Connection conn, ImmutableList<String> tables) throws SQLException {
|
||||
if (tables.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
try (Statement statement = conn.createStatement()) {
|
||||
for (String table : tables) {
|
||||
statement.addBatch(String.format("DROP TABLE IF EXISTS %s CASCADE;", table));
|
||||
}
|
||||
for (int code : statement.executeBatch()) {
|
||||
if (code == Statement.EXECUTE_FAILED) {
|
||||
throw new RuntimeException("Failed to drop some tables. Please check.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Returns a list of all sequences in a Postgresql database. */
|
||||
static ImmutableList<String> listSequences(Connection conn) throws SQLException {
|
||||
try (Statement statement = conn.createStatement();
|
||||
ResultSet resultSet =
|
||||
statement.executeQuery("SELECT c.relname FROM pg_class c WHERE c.relkind = 'S';")) {
|
||||
ImmutableList.Builder<String> sequences = new ImmutableList.Builder<>();
|
||||
while (resultSet.next()) {
|
||||
sequences.add('\"' + resultSet.getString(1) + '\"');
|
||||
}
|
||||
return sequences.build();
|
||||
}
|
||||
}
|
||||
|
||||
static void dropAllSequences(Connection conn, ImmutableList<String> sequences)
|
||||
throws SQLException {
|
||||
if (sequences.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
try (Statement statement = conn.createStatement()) {
|
||||
for (String sequence : sequences) {
|
||||
statement.addBatch(String.format("DROP SEQUENCE IF EXISTS %s CASCADE;", sequence));
|
||||
}
|
||||
for (int code : statement.executeBatch()) {
|
||||
if (code == Statement.EXECUTE_FAILED) {
|
||||
throw new RuntimeException("Failed to drop some sequences. Please check.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -26,7 +26,6 @@ import google.registry.batch.RelockDomainAction;
|
|||
import google.registry.batch.ResaveAllEppResourcesPipelineAction;
|
||||
import google.registry.batch.ResaveEntityAction;
|
||||
import google.registry.batch.SendExpiringCertificateNotificationEmailAction;
|
||||
import google.registry.batch.WipeOutCloudSqlAction;
|
||||
import google.registry.batch.WipeOutContactHistoryPiiAction;
|
||||
import google.registry.cron.CronModule;
|
||||
import google.registry.cron.TldFanoutAction;
|
||||
|
@ -178,8 +177,6 @@ interface BackendRequestComponent {
|
|||
|
||||
UpdateRegistrarRdapBaseUrlsAction updateRegistrarRdapBaseUrlsAction();
|
||||
|
||||
WipeOutCloudSqlAction wipeOutCloudSqlAction();
|
||||
|
||||
WipeOutContactHistoryPiiAction wipeOutContactHistoryPiiAction();
|
||||
|
||||
@Subcomponent.Builder
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
|
||||
<command>
|
||||
<delete>
|
||||
<domain:delete
|
||||
xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
|
||||
<domain:name>%DOMAIN%</domain:name>
|
||||
</domain:delete>
|
||||
</delete>
|
||||
<extension>
|
||||
<metadata:metadata xmlns:metadata="urn:google:params:xml:ns:metadata-1.0">
|
||||
<metadata:reason>Non-renewing domain has reached expiration date.</metadata:reason>
|
||||
<metadata:requestedByRegistrar>false</metadata:requestedByRegistrar>
|
||||
</metadata:metadata>
|
||||
</extension>
|
||||
<clTRID>ABC-12345</clTRID>
|
||||
</command>
|
||||
</epp>
|
|
@ -1,117 +0,0 @@
|
|||
// Copyright 2021 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package google.registry.batch;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static javax.servlet.http.HttpServletResponse.SC_FORBIDDEN;
|
||||
import static javax.servlet.http.HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
|
||||
import static javax.servlet.http.HttpServletResponse.SC_OK;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.ArgumentMatchers.nullable;
|
||||
import static org.mockito.Mockito.doThrow;
|
||||
import static org.mockito.Mockito.lenient;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyNoInteractions;
|
||||
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import google.registry.config.RegistryEnvironment;
|
||||
import google.registry.testing.FakeClock;
|
||||
import google.registry.testing.FakeResponse;
|
||||
import google.registry.testing.FakeSleeper;
|
||||
import google.registry.util.Retrier;
|
||||
import java.sql.Connection;
|
||||
import java.sql.DatabaseMetaData;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
|
||||
/** Unit tests for {@link WipeOutCloudSqlAction}. */
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
public class WipeOutCloudSqlActionTest {
|
||||
|
||||
@Mock private Statement stmt;
|
||||
@Mock private Connection conn;
|
||||
@Mock private DatabaseMetaData metaData;
|
||||
@Mock private ResultSet resultSet;
|
||||
|
||||
private FakeResponse response = new FakeResponse();
|
||||
private Retrier retrier = new Retrier(new FakeSleeper(new FakeClock()), 2);
|
||||
|
||||
@BeforeEach
|
||||
void beforeEach() throws Exception {
|
||||
lenient().when(conn.createStatement()).thenReturn(stmt);
|
||||
lenient().when(conn.getMetaData()).thenReturn(metaData);
|
||||
lenient()
|
||||
.when(
|
||||
metaData.getTables(
|
||||
nullable(String.class),
|
||||
nullable(String.class),
|
||||
nullable(String.class),
|
||||
nullable(String[].class)))
|
||||
.thenReturn(resultSet);
|
||||
lenient().when(stmt.executeQuery(anyString())).thenReturn(resultSet);
|
||||
lenient().when(resultSet.next()).thenReturn(false);
|
||||
}
|
||||
|
||||
@Test
|
||||
void run_projectAllowed() throws Exception {
|
||||
WipeOutCloudSqlAction action = new WipeOutCloudSqlAction(() -> conn, response, retrier);
|
||||
action.run();
|
||||
assertThat(response.getStatus()).isEqualTo(SC_OK);
|
||||
verify(stmt, times(1)).executeQuery(anyString());
|
||||
verify(stmt, times(1)).close();
|
||||
verifyNoMoreInteractions(stmt);
|
||||
}
|
||||
|
||||
@Test
|
||||
void run_projectNotAllowed() {
|
||||
try {
|
||||
RegistryEnvironment.SANDBOX.setup();
|
||||
WipeOutCloudSqlAction action = new WipeOutCloudSqlAction(() -> conn, response, retrier);
|
||||
action.run();
|
||||
assertThat(response.getStatus()).isEqualTo(SC_FORBIDDEN);
|
||||
verifyNoInteractions(stmt);
|
||||
} finally {
|
||||
RegistryEnvironment.UNITTEST.setup();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void run_nonRetrieableFailure() throws Exception {
|
||||
doThrow(new SQLException()).when(conn).getMetaData();
|
||||
WipeOutCloudSqlAction action = new WipeOutCloudSqlAction(() -> conn, response, retrier);
|
||||
action.run();
|
||||
assertThat(response.getStatus()).isEqualTo(SC_INTERNAL_SERVER_ERROR);
|
||||
verifyNoInteractions(stmt);
|
||||
}
|
||||
|
||||
@Test
|
||||
void run_retrieableFailure() throws Exception {
|
||||
when(conn.getMetaData()).thenThrow(new RuntimeException()).thenReturn(metaData);
|
||||
WipeOutCloudSqlAction action = new WipeOutCloudSqlAction(() -> conn, response, retrier);
|
||||
action.run();
|
||||
assertThat(response.getStatus()).isEqualTo(SC_OK);
|
||||
verify(stmt, times(1)).executeQuery(anyString());
|
||||
verify(stmt, times(1)).close();
|
||||
verifyNoMoreInteractions(stmt);
|
||||
}
|
||||
}
|
|
@ -1,89 +0,0 @@
|
|||
// Copyright 2021 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package google.registry.batch;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import google.registry.persistence.NomulusPostgreSql;
|
||||
import java.sql.Connection;
|
||||
import java.sql.Statement;
|
||||
import java.util.Properties;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.testcontainers.containers.PostgreSQLContainer;
|
||||
import org.testcontainers.junit.jupiter.Container;
|
||||
import org.testcontainers.junit.jupiter.Testcontainers;
|
||||
|
||||
/** Tests the database wipeout mechanism used by {@link WipeOutCloudSqlAction}. */
|
||||
@Testcontainers
|
||||
public class WipeOutCloudSqlIntegrationTest {
|
||||
|
||||
@Container
|
||||
PostgreSQLContainer container = new PostgreSQLContainer(NomulusPostgreSql.getDockerTag());
|
||||
|
||||
private Connection getJdbcConnection() throws Exception {
|
||||
Properties properties = new Properties();
|
||||
properties.setProperty("user", container.getUsername());
|
||||
properties.setProperty("password", container.getPassword());
|
||||
return container.getJdbcDriverInstance().connect(container.getJdbcUrl(), properties);
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
void beforeEach() throws Exception {
|
||||
try (Connection conn = getJdbcConnection();
|
||||
Statement statement = conn.createStatement()) {
|
||||
statement.addBatch("CREATE TABLE public.\"Domain\" (value int);");
|
||||
statement.addBatch("CREATE SEQUENCE public.\"Domain_seq\"");
|
||||
statement.executeBatch();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void listTables() throws Exception {
|
||||
try (Connection conn = getJdbcConnection()) {
|
||||
ImmutableList<String> tables = WipeOutCloudSqlAction.listTables(conn);
|
||||
assertThat(tables).containsExactly("public.\"Domain\"");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void dropAllTables() throws Exception {
|
||||
try (Connection conn = getJdbcConnection()) {
|
||||
ImmutableList<String> tables = WipeOutCloudSqlAction.listTables(conn);
|
||||
assertThat(tables).isNotEmpty();
|
||||
WipeOutCloudSqlAction.dropAllTables(conn, tables);
|
||||
assertThat(WipeOutCloudSqlAction.listTables(conn)).isEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void listAllSequences() throws Exception {
|
||||
try (Connection conn = getJdbcConnection()) {
|
||||
ImmutableList<String> sequences = WipeOutCloudSqlAction.listSequences(conn);
|
||||
assertThat(sequences).containsExactly("\"Domain_seq\"");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void dropAllSequences() throws Exception {
|
||||
try (Connection conn = getJdbcConnection()) {
|
||||
ImmutableList<String> sequences = WipeOutCloudSqlAction.listSequences(conn);
|
||||
assertThat(sequences).isNotEmpty();
|
||||
WipeOutCloudSqlAction.dropAllSequences(conn, sequences);
|
||||
assertThat(WipeOutCloudSqlAction.listSequences(conn)).isEmpty();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -35,5 +35,4 @@ PATH CLASS
|
|||
/_dr/task/tmchDnl TmchDnlAction POST y API APP ADMIN
|
||||
/_dr/task/tmchSmdrl TmchSmdrlAction POST y API APP ADMIN
|
||||
/_dr/task/updateRegistrarRdapBaseUrls UpdateRegistrarRdapBaseUrlsAction GET y API APP ADMIN
|
||||
/_dr/task/wipeOutCloudSql WipeOutCloudSqlAction GET n API APP ADMIN
|
||||
/_dr/task/wipeOutContactHistoryPii WipeOutContactHistoryPiiAction GET n API APP ADMIN
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue