From 72e01017462944e9d1b3ab23d4124a760a1d2be7 Mon Sep 17 00:00:00 2001 From: Lai Jiang Date: Thu, 2 Nov 2023 11:41:03 -0400 Subject: [PATCH] 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. --- .../registry/batch/WipeOutCloudSqlAction.java | 161 ------------------ .../backend/BackendRequestComponent.java | 3 - .../registry/batch/delete_expired_domain.xml | 17 ++ .../batch/WipeOutCloudSqlActionTest.java | 117 ------------- .../batch/WipeOutCloudSqlIntegrationTest.java | 89 ---------- .../module/backend/backend_routing.txt | 1 - 6 files changed, 17 insertions(+), 371 deletions(-) delete mode 100644 core/src/main/java/google/registry/batch/WipeOutCloudSqlAction.java create mode 100644 core/src/main/resources/google/registry/batch/delete_expired_domain.xml delete mode 100644 core/src/test/java/google/registry/batch/WipeOutCloudSqlActionTest.java delete mode 100644 core/src/test/java/google/registry/batch/WipeOutCloudSqlIntegrationTest.java diff --git a/core/src/main/java/google/registry/batch/WipeOutCloudSqlAction.java b/core/src/main/java/google/registry/batch/WipeOutCloudSqlAction.java deleted file mode 100644 index a3e9baacf..000000000 --- a/core/src/main/java/google/registry/batch/WipeOutCloudSqlAction.java +++ /dev/null @@ -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. - * - *

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 FORBIDDEN_ENVIRONMENTS = - ImmutableSet.of(RegistryEnvironment.PRODUCTION, RegistryEnvironment.SANDBOX); - - private final Supplier connectionSupplier; - private final Response response; - private final Retrier retrier; - - @Inject - WipeOutCloudSqlAction( - @SchemaManagerConnection Supplier 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 listTables(Connection connection) throws SQLException { - try (ResultSet resultSet = - connection.getMetaData().getTables(null, null, null, new String[] {"TABLE"})) { - ImmutableList.Builder 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 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 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 sequences = new ImmutableList.Builder<>(); - while (resultSet.next()) { - sequences.add('\"' + resultSet.getString(1) + '\"'); - } - return sequences.build(); - } - } - - static void dropAllSequences(Connection conn, ImmutableList 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."); - } - } - } - } -} diff --git a/core/src/main/java/google/registry/module/backend/BackendRequestComponent.java b/core/src/main/java/google/registry/module/backend/BackendRequestComponent.java index 5aba5714c..0f65a5d0d 100644 --- a/core/src/main/java/google/registry/module/backend/BackendRequestComponent.java +++ b/core/src/main/java/google/registry/module/backend/BackendRequestComponent.java @@ -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 diff --git a/core/src/main/resources/google/registry/batch/delete_expired_domain.xml b/core/src/main/resources/google/registry/batch/delete_expired_domain.xml new file mode 100644 index 000000000..8714f04b6 --- /dev/null +++ b/core/src/main/resources/google/registry/batch/delete_expired_domain.xml @@ -0,0 +1,17 @@ + + + + + %DOMAIN% + + + + + Non-renewing domain has reached expiration date. + false + + + ABC-12345 + + diff --git a/core/src/test/java/google/registry/batch/WipeOutCloudSqlActionTest.java b/core/src/test/java/google/registry/batch/WipeOutCloudSqlActionTest.java deleted file mode 100644 index 509944871..000000000 --- a/core/src/test/java/google/registry/batch/WipeOutCloudSqlActionTest.java +++ /dev/null @@ -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); - } -} diff --git a/core/src/test/java/google/registry/batch/WipeOutCloudSqlIntegrationTest.java b/core/src/test/java/google/registry/batch/WipeOutCloudSqlIntegrationTest.java deleted file mode 100644 index a3d785db5..000000000 --- a/core/src/test/java/google/registry/batch/WipeOutCloudSqlIntegrationTest.java +++ /dev/null @@ -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 tables = WipeOutCloudSqlAction.listTables(conn); - assertThat(tables).containsExactly("public.\"Domain\""); - } - } - - @Test - void dropAllTables() throws Exception { - try (Connection conn = getJdbcConnection()) { - ImmutableList 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 sequences = WipeOutCloudSqlAction.listSequences(conn); - assertThat(sequences).containsExactly("\"Domain_seq\""); - } - } - - @Test - void dropAllSequences() throws Exception { - try (Connection conn = getJdbcConnection()) { - ImmutableList sequences = WipeOutCloudSqlAction.listSequences(conn); - assertThat(sequences).isNotEmpty(); - WipeOutCloudSqlAction.dropAllSequences(conn, sequences); - assertThat(WipeOutCloudSqlAction.listSequences(conn)).isEmpty(); - } - } -} diff --git a/core/src/test/resources/google/registry/module/backend/backend_routing.txt b/core/src/test/resources/google/registry/module/backend/backend_routing.txt index a6b820400..6c0344bfc 100644 --- a/core/src/test/resources/google/registry/module/backend/backend_routing.txt +++ b/core/src/test/resources/google/registry/module/backend/backend_routing.txt @@ -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