Skip to content

Instantly share code, notes, and snippets.

@octavioranieri
Created October 24, 2025 19:46
Show Gist options
  • Select an option

  • Save octavioranieri/b6e05a3659e4dd7679f20713f92068b9 to your computer and use it in GitHub Desktop.

Select an option

Save octavioranieri/b6e05a3659e4dd7679f20713f92068b9 to your computer and use it in GitHub Desktop.
import org.apache.pekko.http.scaladsl.model.headers.BasicHttpCredentials
import com.fasterxml.jackson.databind.node.ObjectNode
import no.found.bootstrap.BootstrapUtils
import no.found.json._
import no.found.util.Secrets.generateRandomString
import no.found.zookeeper.CloudResourceModel._
import no.found.zookeeper.models._
import no.found.zookeeper.models.clusters._
import no.found.zookeeper.models.clusters.elasticsearch._
import no.found.zookeeper.models.services._
import org.mindrot.jbcrypt.BCrypt
import scala.concurrent._
import scala.concurrent.duration._
import no.found.syntax.JsonSyntax._
// IMPORTANT
// Before running, please make sure you have a logging-and-metrics deployment with system_owned property set to true
def getElasticsearchAndKibanaIds(): (String, String) = {
val deployments = zk"/deployments".list().result().get.values
val loggingAndMetricsDeploymentNode = deployments.find { deployment =>
val name = zk"${deployment.path}".read().result().get.value.path("name")
name.asText() == "logging-and-metrics"
}
val loggingAndMetricsObjectNode = loggingAndMetricsDeploymentNode.get.read().result().get.value
val deploymentResources = loggingAndMetricsObjectNode.path("resources").as[List[ObjectNode]]
val loggingAndMetricsElasticsearchClusterId = deploymentResources.find( _.path("kind").asText() == "elasticsearch").map(_.path("id")).map(_.asText()).get
println(s"The logging-and-metrics' cluster's Elasticsearch ID is $loggingAndMetricsElasticsearchClusterId")
val loggingAndMetricsKibanaId = deploymentResources.find( _.path("kind").asText() == "kibana").map(_.path("id")).map(_.asText()).get
println(s"The logging-and-metrics' cluster's Kibana ID is $loggingAndMetricsKibanaId")
(loggingAndMetricsElasticsearchClusterId, loggingAndMetricsKibanaId)
}
def rebuildLoggingMetrics(): Unit = {
val (elasticsearchClusterId, kibanaClusterId) = getElasticsearchAndKibanaIds()
// That's in order for the ApplyElasticsearchSystemClusterAssets and ApplyKibanaSystemClusterAssets constructor steps to work:
val metricbeatSettingsAfterInitialUpdate = zk"/services/metricbeat/settings".update(settingsObjNode => {
settingsObjNode.put("cluster_id", elasticsearchClusterId)
settingsObjNode.put("kibana_cluster_id", kibanaClusterId)
}).result().get.value
println(s"Initial update of metricbeat settings to point to the logging-and-metrics cluster: ${metricbeatSettingsAfterInitialUpdate}.")
println("Now stop for a moment and go apply a plan on the logging-and-metrics cluster. Check the constructor logs for traces of ApplyElasticsearchSystemClusterAssets and ApplyKibanaSystemClusterAssets.")
scala.io.StdIn.readLine()
println("Just checking - type something again if you want to continue ;-)")
scala.io.StdIn.readLine()
val cluster = ElasticsearchCluster(elasticsearchClusterId)
val (clusterSettings, _) = Await.result(cluster.getData(), 1.minute)
val bootstrapConfig = BootstrapUtils.newTemporaryShieldAdminUser
ShieldConfigUtils.injectUserIntoClusterMetadata(
bootstrapConfig,
clusterSettings
)(mapper, ToJson.DefaultOptions)
val ingestUser = ShieldUser.defaultLoggingAndMetricsUsername
val ingestPassword = generateRandomString(32)
val ingestConfig = ShieldUser(
username = ingestUser,
password = Some(ingestPassword),
passwordHash = BCrypt.hashpw(ingestPassword, BCrypt.gensalt()),
roles = List(ShieldUser.defaultLoggingAndMetricsRole),
validUntil = None
)
ShieldConfigUtils.injectUserIntoClusterMetadata(
ingestConfig,
clusterSettings
)(mapper, ToJson.DefaultOptions)
val consoleUser = ShieldUser.defaultLoggingAndMetricsConsoleAPIUsername
val consolePassword = generateRandomString(32)
val consoleConfig = ShieldUser(
username = consoleUser,
password = Some(consolePassword),
passwordHash = BCrypt.hashpw(consolePassword, BCrypt.gensalt()),
roles = List(ShieldUser.defaultLoggingAndMetricsConsoleAPIRole),
validUntil = None
)
ShieldConfigUtils.injectUserIntoClusterMetadata(
consoleConfig.copy(password = None),
clusterSettings
)(mapper, ToJson.DefaultOptions)
Await.result(cluster.updateData(_ => clusterSettings, None), 1.minute)
val serviceSettings = new ServiceSettings(
ingestUser,
ingestPassword,
"containerhost:9244",
cluster.name,
Some(kibanaClusterId)
).toJson(mapper)
val filebeatSettings = zk"/services/filebeat/settings".update(_ => serviceSettings).result().get.value
println(s"Updated filebeat settings: $filebeatSettings")
val metricbeatSettings = zk"/services/metricbeat/settings".update(_ => serviceSettings).result().get.value
println(s"Updated metricbeat settings: $metricbeatSettings")
val allocatorMetricbeatSettings = zk"/services/allocator-metricbeat/settings".update(_ => serviceSettings).result().get.value
println(s"Updated allocator-metricbeat settings: $allocatorMetricbeatSettings")
val adminconsoleSettings = zk"/services/adminconsole/settings".read().result().get.value
val basicAuthCreds = BasicHttpCredentials(consoleConfig.username, consoleConfig.password.get)
val lmSettings = adminconsoleSettings.path("found").path("adminconsole").path("regions").path("ece-region").path("metrics-cluster").path("additional_headers").asInstanceOf[ObjectNode]
lmSettings.put("X-Found-Cluster", elasticsearchClusterId)
lmSettings.put("Authorization", basicAuthCreds.value)
val updatedAdminConsoleSettings = zk"/services/adminconsole/settings".update(_ => adminconsoleSettings).result().get.value
println(s"Updated admin-console settings: $updatedAdminConsoleSettings")
println("Logging and metrics data rebuilt")
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment