mirror of
https://github.com/google/nomulus.git
synced 2025-05-13 16:07:15 +02:00
Use -dot- subdomain notation in MapReduce console links
appspot.com is not provisioned with a multi-level wildcard SSL certificate, so URLs of the form https://service.projectid.appspot.com/path need to be rewritten as https://service-dot-projectid.appspot.com/path (and same for version names). This is a follow-up to [] ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=231418795
This commit is contained in:
parent
6e0b8f2cfd
commit
3812c2ceda
7 changed files with 85 additions and 6 deletions
|
@ -284,7 +284,10 @@ public class MapreduceRunner {
|
||||||
|
|
||||||
private String renderMapreduceConsoleLink(String jobId) {
|
private String renderMapreduceConsoleLink(String jobId) {
|
||||||
return String.format(
|
return String.format(
|
||||||
MAPREDUCE_CONSOLE_LINK_FORMAT, appEngineServiceUtils.getServiceHostname("backend"), jobId);
|
MAPREDUCE_CONSOLE_LINK_FORMAT,
|
||||||
|
appEngineServiceUtils.convertToSingleSubdomain(
|
||||||
|
appEngineServiceUtils.getServiceHostname("backend")),
|
||||||
|
jobId);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -301,7 +304,7 @@ public class MapreduceRunner {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void sendLinkToMapreduceConsole(Response response) {
|
public void sendLinkToMapreduceConsole(Response response) {
|
||||||
response.setPayload(getLinkToMapreduceConsole());
|
response.setPayload(getLinkToMapreduceConsole() + "\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getLinkToMapreduceConsole() {
|
public String getLinkToMapreduceConsole() {
|
||||||
|
|
|
@ -38,6 +38,25 @@ public interface AppEngineServiceUtils {
|
||||||
/** Returns a host name to use for the given service and version. */
|
/** Returns a host name to use for the given service and version. */
|
||||||
String getVersionHostname(String service, String version);
|
String getVersionHostname(String service, String version);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a multi-level App Engine host name (not URL) to the -dot- single subdomain format.
|
||||||
|
*
|
||||||
|
* <p>This is needed because appspot.com only has a single wildcard SSL certificate, so the native
|
||||||
|
* App Engine URLs of the form service.projectid.appspot.com or
|
||||||
|
* version.service.projectid.appspot.com won't work over HTTPS when being fetched from outside of
|
||||||
|
* GCP. The work-around is to change all of the "." subdomain markers to "-dot-". E.g.:
|
||||||
|
*
|
||||||
|
* <ul>
|
||||||
|
* <li>tools.projectid.appspot.com --> tools-dot-projectid.appspot.com
|
||||||
|
* <li>version.backend.projectid.appspot.com --> version-dot-backend-dot-projectid.appspot.com
|
||||||
|
* </ul>
|
||||||
|
*
|
||||||
|
* @see <a
|
||||||
|
* href="https://cloud.google.com/appengine/docs/standard/java/how-requests-are-routed">How
|
||||||
|
* App Engine requests are routed</a>
|
||||||
|
*/
|
||||||
|
String convertToSingleSubdomain(String hostname);
|
||||||
|
|
||||||
/** Set the number of instances at runtime for a given service and version. */
|
/** Set the number of instances at runtime for a given service and version. */
|
||||||
void setNumInstances(String service, String version, long numInstances);
|
void setNumInstances(String service, String version, long numInstances);
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,11 +18,18 @@ import static com.google.common.base.Preconditions.checkArgument;
|
||||||
import static google.registry.util.PreconditionsUtils.checkArgumentNotNull;
|
import static google.registry.util.PreconditionsUtils.checkArgumentNotNull;
|
||||||
|
|
||||||
import com.google.appengine.api.modules.ModulesService;
|
import com.google.appengine.api.modules.ModulesService;
|
||||||
|
import com.google.common.flogger.FluentLogger;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
/** A wrapper for {@link ModulesService} that provides a saner API. */
|
/** A wrapper for {@link ModulesService} that provides a saner API. */
|
||||||
public class AppEngineServiceUtilsImpl implements AppEngineServiceUtils {
|
public class AppEngineServiceUtilsImpl implements AppEngineServiceUtils {
|
||||||
|
|
||||||
|
private static final Pattern APPSPOT_HOSTNAME_PATTERN =
|
||||||
|
Pattern.compile("^(.*)\\.appspot\\.com$");
|
||||||
|
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
|
||||||
|
|
||||||
private final ModulesService modulesService;
|
private final ModulesService modulesService;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
|
@ -56,4 +63,14 @@ public class AppEngineServiceUtilsImpl implements AppEngineServiceUtils {
|
||||||
checkArgument(numInstances > 0, "Number of instances must be greater than 0");
|
checkArgument(numInstances > 0, "Number of instances must be greater than 0");
|
||||||
modulesService.setNumInstances(service, version, numInstances);
|
modulesService.setNumInstances(service, version, numInstances);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String convertToSingleSubdomain(String hostname) {
|
||||||
|
Matcher matcher = APPSPOT_HOSTNAME_PATTERN.matcher(hostname);
|
||||||
|
if (!matcher.matches()) {
|
||||||
|
logger.atWarning().log("Skipping conversion because hostname can't be parsed: %s", hostname);
|
||||||
|
return hostname;
|
||||||
|
}
|
||||||
|
return matcher.group(1).replace(".", "-dot-") + ".appspot.com";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -94,7 +94,8 @@ public class ExportDomainListsActionTest extends MapreduceTestCase<ExportDomainL
|
||||||
runMapreduce();
|
runMapreduce();
|
||||||
assertThat(response.getPayload())
|
assertThat(response.getPayload())
|
||||||
.startsWith(
|
.startsWith(
|
||||||
"Mapreduce console: https://backend.hostname.tld/_ah/pipeline/status.html?root=");
|
"Mapreduce console: https://backend-dot-projectid.appspot.com"
|
||||||
|
+ "/_ah/pipeline/status.html?root=");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
|
@ -20,6 +20,7 @@ import static org.mockito.Mockito.mock;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
import com.google.appengine.api.blobstore.dev.LocalBlobstoreService;
|
import com.google.appengine.api.blobstore.dev.LocalBlobstoreService;
|
||||||
|
import com.google.appengine.api.modules.ModulesService;
|
||||||
import com.google.appengine.api.taskqueue.dev.LocalTaskQueue;
|
import com.google.appengine.api.taskqueue.dev.LocalTaskQueue;
|
||||||
import com.google.appengine.api.taskqueue.dev.QueueStateInfo;
|
import com.google.appengine.api.taskqueue.dev.QueueStateInfo;
|
||||||
import com.google.appengine.api.taskqueue.dev.QueueStateInfo.HeaderWrapper;
|
import com.google.appengine.api.taskqueue.dev.QueueStateInfo.HeaderWrapper;
|
||||||
|
@ -38,6 +39,7 @@ import google.registry.testing.FakeClock;
|
||||||
import google.registry.testing.MockitoJUnitRule;
|
import google.registry.testing.MockitoJUnitRule;
|
||||||
import google.registry.testing.ShardableTestCase;
|
import google.registry.testing.ShardableTestCase;
|
||||||
import google.registry.util.AppEngineServiceUtils;
|
import google.registry.util.AppEngineServiceUtils;
|
||||||
|
import google.registry.util.AppEngineServiceUtilsImpl;
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.ObjectInputStream;
|
import java.io.ObjectInputStream;
|
||||||
import java.io.UnsupportedEncodingException;
|
import java.io.UnsupportedEncodingException;
|
||||||
|
@ -84,16 +86,19 @@ public abstract class MapreduceTestCase<T> extends ShardableTestCase {
|
||||||
|
|
||||||
@Rule public final MockitoJUnitRule mocks = MockitoJUnitRule.create();
|
@Rule public final MockitoJUnitRule mocks = MockitoJUnitRule.create();
|
||||||
|
|
||||||
@Mock
|
|
||||||
AppEngineServiceUtils appEngineServiceUtils;
|
AppEngineServiceUtils appEngineServiceUtils;
|
||||||
|
|
||||||
|
@Mock ModulesService modulesService;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() {
|
public void setUp() {
|
||||||
taskQueue = LocalTaskQueueTestConfig.getLocalTaskQueue();
|
taskQueue = LocalTaskQueueTestConfig.getLocalTaskQueue();
|
||||||
ApiProxyLocal proxy = (ApiProxyLocal) ApiProxy.getDelegate();
|
ApiProxyLocal proxy = (ApiProxyLocal) ApiProxy.getDelegate();
|
||||||
// Creating files is not allowed in some test execution environments, so don't.
|
// Creating files is not allowed in some test execution environments, so don't.
|
||||||
proxy.setProperty(LocalBlobstoreService.NO_STORAGE_PROPERTY, "true");
|
proxy.setProperty(LocalBlobstoreService.NO_STORAGE_PROPERTY, "true");
|
||||||
when(appEngineServiceUtils.getServiceHostname("backend")).thenReturn("backend.hostname.tld");
|
appEngineServiceUtils = new AppEngineServiceUtilsImpl(modulesService);
|
||||||
|
when(modulesService.getVersionHostname("backend", null))
|
||||||
|
.thenReturn("version.backend.projectid.appspot.com");
|
||||||
}
|
}
|
||||||
|
|
||||||
protected MapreduceRunner makeDefaultRunner() {
|
protected MapreduceRunner makeDefaultRunner() {
|
||||||
|
|
|
@ -132,7 +132,8 @@ public class GenerateZoneFilesActionTest extends MapreduceTestCase<GenerateZoneF
|
||||||
assertThat(response).containsKey("mapreduceConsoleLink");
|
assertThat(response).containsKey("mapreduceConsoleLink");
|
||||||
assertThat(response.get("mapreduceConsoleLink").toString())
|
assertThat(response.get("mapreduceConsoleLink").toString())
|
||||||
.startsWith(
|
.startsWith(
|
||||||
"Mapreduce console: https://backend.hostname.tld/_ah/pipeline/status.html?root=");
|
"Mapreduce console: https://backend-dot-projectid.appspot.com"
|
||||||
|
+ "/_ah/pipeline/status.html?root=");
|
||||||
|
|
||||||
executeTasksUntilEmpty("mapreduce");
|
executeTasksUntilEmpty("mapreduce");
|
||||||
|
|
||||||
|
|
|
@ -110,4 +110,37 @@ public class AppEngineServiceUtilsImplTest {
|
||||||
() -> appEngineServiceUtils.setNumInstances("service", "version", -10L));
|
() -> appEngineServiceUtils.setNumInstances("service", "version", -10L));
|
||||||
assertThat(thrown).hasMessageThat().isEqualTo("Number of instances must be greater than 0");
|
assertThat(thrown).hasMessageThat().isEqualTo("Number of instances must be greater than 0");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_convertToSingleSubdomain_doesNothingWithoutServiceOrHostname() {
|
||||||
|
assertThat(appEngineServiceUtils.convertToSingleSubdomain("projectid.appspot.com"))
|
||||||
|
.isEqualTo("projectid.appspot.com");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_convertToSingleSubdomain_doesNothingWhenItCannotParseCorrectly() {
|
||||||
|
assertThat(appEngineServiceUtils.convertToSingleSubdomain("garbage.notrealhost.example"))
|
||||||
|
.isEqualTo("garbage.notrealhost.example");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_convertToSingleSubdomain_convertsWithServiceName() {
|
||||||
|
assertThat(appEngineServiceUtils.convertToSingleSubdomain("service.projectid.appspot.com"))
|
||||||
|
.isEqualTo("service-dot-projectid.appspot.com");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_convertToSingleSubdomain_convertsWithVersionAndServiceName() {
|
||||||
|
assertThat(
|
||||||
|
appEngineServiceUtils.convertToSingleSubdomain("version.service.projectid.appspot.com"))
|
||||||
|
.isEqualTo("version-dot-service-dot-projectid.appspot.com");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_convertToSingleSubdomain_convertsWithInstanceAndVersionAndServiceName() {
|
||||||
|
assertThat(
|
||||||
|
appEngineServiceUtils.convertToSingleSubdomain(
|
||||||
|
"instanceid.version.service.projectid.appspot.com"))
|
||||||
|
.isEqualTo("instanceid-dot-version-dot-service-dot-projectid.appspot.com");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue