URL Encode project name
Project name need to be URL encoded to allow Gerrit REST API
to find the resource.
Furthermore Docker compose doesn't like container names with '/',
hence we replace it with '-' and add a timestamp to make them unique.
Bug: Issue 9067
Change-Id: I4fe990ff20946a43e08a2f1505676d36b1514ffd
diff --git a/src/main/resources/static/js/analyticswizard.js b/src/main/resources/static/js/analyticswizard.js
index 0b0cc79..579285e 100644
--- a/src/main/resources/static/js/analyticswizard.js
+++ b/src/main/resources/static/js/analyticswizard.js
@@ -24,7 +24,7 @@
function submitDetailsForm() {
- var projectName = $("#input-project-name").val();
+ var projectName = encodeURIComponent($("#input-project-name").val());
$.ajax({
type : "PUT",
url : `/a/projects/${projectName}/analytics-wizard~stack`,
@@ -54,7 +54,7 @@
};
function dashboardService(command) {
- var projectName = $("#input-project-name").val();
+ var projectName = encodeURIComponent($("#input-project-name").val());
$.ajax({
type : "POST",
url : `/a/projects/${projectName}/analytics-wizard~server`,
diff --git a/src/main/scala/com/googlesource/gerrit/plugins/analytics/wizard/AnalyticDashboardSetup.scala b/src/main/scala/com/googlesource/gerrit/plugins/analytics/wizard/AnalyticDashboardSetup.scala
index 1c07435..f288fab 100644
--- a/src/main/scala/com/googlesource/gerrit/plugins/analytics/wizard/AnalyticDashboardSetup.scala
+++ b/src/main/scala/com/googlesource/gerrit/plugins/analytics/wizard/AnalyticDashboardSetup.scala
@@ -13,8 +13,7 @@
// limitations under the License.
package com.googlesource.gerrit.plugins.analytics.wizard
-import java.io.PrintWriter
-import java.nio.charset.{Charset, StandardCharsets}
+import java.nio.charset.StandardCharsets
import java.nio.file.{Files, Path}
trait ConfigWriter {
@@ -30,7 +29,13 @@
case class AnalyticDashboardSetup(name: String, dockerComposeYamlPath: Path)(
implicit val writer: ConfigWriter) {
- private val dockerComposeTemplate = { (name: String) =>
+ // Docker doesn't like container names with '/', hence the replace with '-'
+ // Furthermore timestamp has been added to avoid conflicts among container names, i.e.:
+ // A project named 'foo/bar' would be encoded as 'foo-bar' and thus its container
+ // would be potentially in conflict with another 'foo-bar' project's one
+ private val sanitisedName =
+ s"${name.replace("/", "-")}-${System.currentTimeMillis}"
+ private val dockerComposeTemplate = {
s"""
|version: '3'
|services:
@@ -45,7 +50,7 @@
|
| kibana:
| image: gerritforge/analytics-kibana:latest
- | container_name: "kibana-for-${name}-project"
+ | container_name: "kibana-for-${sanitisedName}-project"
| networks:
| - ek
| depends_on:
@@ -55,7 +60,7 @@
|
| elasticsearch:
| image: gerritforge/analytics-elasticsearch:latest
- | container_name: "es-for-${name}-project"
+ | container_name: "es-for-${sanitisedName}-project"
| networks:
| - ek
| environment:
@@ -69,7 +74,7 @@
}
def createDashboardSetupFile(): Unit = {
- writer.write(dockerComposeYamlPath, dockerComposeTemplate(name))
+ writer.write(dockerComposeYamlPath, dockerComposeTemplate)
}
}
diff --git a/src/main/scala/com/googlesource/gerrit/plugins/analytics/wizard/AnalyticsWizardActions.scala b/src/main/scala/com/googlesource/gerrit/plugins/analytics/wizard/AnalyticsWizardActions.scala
index f63447c..6763e3a 100644
--- a/src/main/scala/com/googlesource/gerrit/plugins/analytics/wizard/AnalyticsWizardActions.scala
+++ b/src/main/scala/com/googlesource/gerrit/plugins/analytics/wizard/AnalyticsWizardActions.scala
@@ -13,10 +13,12 @@
// limitations under the License.
package com.googlesource.gerrit.plugins.analytics.wizard
+import java.net.URLEncoder
import java.nio.charset.StandardCharsets.UTF_8
import java.nio.file.Path
import com.google.common.io.ByteStreams
+import com.google.gerrit.extensions.annotations.PluginData
import com.google.gerrit.extensions.restapi.{
Response,
RestApiException,
@@ -25,12 +27,10 @@
}
import com.google.gerrit.server.project.ProjectResource
import com.google.inject.Inject
-import AnalyticDashboardSetup.writer
-import com.google.gerrit.extensions.annotations.PluginData
+import com.googlesource.gerrit.plugins.analytics.wizard.AnalyticDashboardSetup.writer
-import scala.io.Source
-
-class GetAnalyticsStack @Inject()(@PluginData val dataPath: Path) extends RestReadView[ProjectResource] {
+class GetAnalyticsStack @Inject()(@PluginData val dataPath: Path)
+ extends RestReadView[ProjectResource] {
override def apply(
resource: ProjectResource): Response[AnalyticDashboardSetup] = {
@@ -50,8 +50,15 @@
input: Input): Response[String] = {
val projectName = resource.getControl.getProject.getName
- AnalyticDashboardSetup(projectName, dataPath.resolve(s"docker-compose.${projectName}.yaml")).createDashboardSetupFile()
- Response.created(s"Dashboard configuration created for $projectName!")
+ val encodedName = AnalyticsWizardActions
+ .encodedName(projectName)
+
+ AnalyticDashboardSetup(
+ projectName,
+ dataPath.resolve(s"docker-compose.${encodedName}.yaml"))
+ .createDashboardSetupFile()
+ Response.created(s"Dashboard configuration created for $encodedName!")
+
}
}
@@ -62,16 +69,20 @@
input: DockerComposeCommand): Response[String] = {
val projectName = resource.getControl.getProject.getName
+ val encodedName = AnalyticsWizardActions
+ .encodedName(projectName)
+
val pb = new ProcessBuilder(
"docker-compose",
"-f",
- s"${dataPath.toFile.getAbsolutePath}/docker-compose.${projectName}.yaml",
+ s"${dataPath.toFile.getAbsolutePath}/docker-compose.${encodedName}.yaml",
input.action.toLowerCase)
pb.redirectErrorStream(true)
val ps: Process = pb.start
ps.getOutputStream.close
- val output = new String(ByteStreams.toByteArray(ps.getInputStream), UTF_8)
+ val output =
+ new String(ByteStreams.toByteArray(ps.getInputStream), UTF_8)
ps.waitFor
ps.exitValue match {
@@ -83,3 +94,14 @@
}
}
+
+object AnalyticsWizardActions {
+ // URLEncoder could potentially throw UnsupportedEncodingException,
+ // but UTF-8 will *always* be resolved, otherwise, Gerrit wouldn't work at all
+ def encodedName(name: String) =
+ try {
+ URLEncoder.encode(name, "UTF-8")
+ } catch {
+ case e: Throwable => throw new RuntimeException(e)
+ }
+}