Skip to content

Commit

Permalink
JPERF-273: Hook into Jira provisioning
Browse files Browse the repository at this point in the history
  • Loading branch information
dagguh committed Feb 19, 2021
1 parent e6483fb commit 77ef790
Show file tree
Hide file tree
Showing 30 changed files with 840 additions and 7 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package com.atlassian.performance.tools.infrastructure.api.jira.install.hook

import com.atlassian.performance.tools.infrastructure.api.jira.install.TcpServer
import com.atlassian.performance.tools.infrastructure.api.jira.report.Report
import com.atlassian.performance.tools.infrastructure.api.jira.start.StartedJira
import com.atlassian.performance.tools.infrastructure.api.jira.start.hook.PostStartHook
import com.atlassian.performance.tools.infrastructure.api.jira.start.hook.PostStartHooks
import com.atlassian.performance.tools.ssh.api.SshConnection
import java.net.URI

class AsyncProfilerHook : PreInstallHook {

override fun call(
ssh: SshConnection,
server: TcpServer,
hooks: PreInstallHooks
) {
val directory = "async-profiler"
val downloads = URI("https://github.com/jvm-profiling-tools/async-profiler/releases/download/")
val distribution = downloads.resolve("v1.4/async-profiler-1.4-linux-x64.tar.gz")
ssh.execute("wget -q $distribution")
ssh.execute("mkdir $directory")
ssh.execute("tar -xzf async-profiler-1.4-linux-x64.tar.gz -C $directory")
ssh.execute("sudo sh -c 'echo 1 > /proc/sys/kernel/perf_event_paranoid'")
ssh.execute("sudo sh -c 'echo 0 > /proc/sys/kernel/kptr_restrict'")
val profilerPath = "./$directory/profiler.sh"
val profiler = InstalledAsyncProfiler(profilerPath)
hooks.postStart.insert(profiler)
}
}

private class InstalledAsyncProfiler(
private val profilerPath: String
) : PostStartHook {

override fun call(
ssh: SshConnection,
jira: StartedJira,
hooks: PostStartHooks
) {
ssh.execute("$profilerPath -b 20000000 start ${jira.pid}")
val profiler = StartedAsyncProfiler(jira.pid, profilerPath)
hooks.reports.add(profiler)
}
}

private class StartedAsyncProfiler(
private val pid: Int,
private val profilerPath: String
) : Report {

override fun locate(ssh: SshConnection): List<String> {
val flameGraphFile = "flamegraph.svg"
ssh.execute("$profilerPath stop $pid -o svg > $flameGraphFile")
return listOf(flameGraphFile)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.atlassian.performance.tools.infrastructure.api.jira.install.hook

import com.atlassian.performance.tools.infrastructure.api.jira.SharedHome
import com.atlassian.performance.tools.infrastructure.api.jira.install.InstalledJira
import com.atlassian.performance.tools.ssh.api.SshConnection

class DataCenterHook(
private val nodeId: String,
private val sharedHome: SharedHome
) : PostInstallHook {

override fun call(
ssh: SshConnection,
jira: InstalledJira,
hooks: PostInstallHooks
) {
val localSharedHome = sharedHome.localSharedHome
sharedHome.mount(ssh)
val jiraHome = jira.home.path // TODO what's the difference between localSharedHome and jiraHome? should both be hookable?
ssh.execute("echo ehcache.object.port = 40011 >> $jiraHome/cluster.properties")
ssh.execute("echo jira.node.id = $nodeId >> $jiraHome/cluster.properties")
ssh.execute("echo jira.shared.home = `realpath $localSharedHome` >> $jiraHome/cluster.properties")
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.atlassian.performance.tools.infrastructure.api.jira.install.hook

import com.atlassian.performance.tools.infrastructure.api.jira.install.InstalledJira
import com.atlassian.performance.tools.ssh.api.SshConnection

class DisabledAutoBackup : PostInstallHook {

override fun call(
ssh: SshConnection,
jira: InstalledJira,
hooks: PostInstallHooks
) {
ssh.execute("echo jira.autoexport=false > ${jira.home.path}/jira-config.properties")
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.atlassian.performance.tools.infrastructure.api.jira.install.hook

import com.atlassian.performance.tools.infrastructure.api.jira.install.InstalledJira
import com.atlassian.performance.tools.infrastructure.api.jira.install.JiraInstallation
import com.atlassian.performance.tools.infrastructure.api.jira.install.TcpServer

class HookedJiraInstallation(
private val installation: JiraInstallation,
private val hooks: PreInstallHooks
) : JiraInstallation {

override fun install(
server: TcpServer
): InstalledJira {
server.ssh.newConnection().use { ssh ->
hooks.call(ssh, server)
}
val installed = installation.install(server)
server.ssh.newConnection().use { ssh ->
hooks.postInstall.call(ssh, installed)
}
return installed
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.atlassian.performance.tools.infrastructure.api.jira.install.hook

import com.atlassian.performance.tools.infrastructure.api.jira.install.InstalledJira
import com.atlassian.performance.tools.ssh.api.SshConnection

class JiraHomeProperty : PostInstallHook {

override fun call(
ssh: SshConnection,
jira: InstalledJira,
hooks: PostInstallHooks
) {
val properties = "${jira.installation.path}/atlassian-jira/WEB-INF/classes/jira-application.properties"
ssh.execute("echo jira.home=`realpath ${jira.home.path}` > $properties")
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package com.atlassian.performance.tools.infrastructure.api.jira.install.hook

import com.atlassian.performance.tools.infrastructure.api.jira.install.InstalledJira
import com.atlassian.performance.tools.infrastructure.api.jira.report.StaticReport
import com.atlassian.performance.tools.ssh.api.SshConnection
import java.nio.file.Path
import java.nio.file.Paths

class JiraLogs : PostInstallHook {

override fun call(ssh: SshConnection, jira: InstalledJira, hooks: PostInstallHooks) {
listOf(
"${jira.home.path}/log/atlassian-jira.log",
"${jira.installation.path}/logs/catalina.out"
)
.onEach { ensureFile(Paths.get(it), ssh) }
.map { StaticReport(it) }
.forEach { hooks.reports.add(it) }
}

private fun ensureFile(
path: Path,
ssh: SshConnection
) {
ssh.execute("mkdir -p ${path.parent!!}")
ssh.execute("touch $path")
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package com.atlassian.performance.tools.infrastructure.api.jira.install.hook

import com.atlassian.performance.tools.infrastructure.api.jira.JiraGcLog
import com.atlassian.performance.tools.infrastructure.api.jira.JiraNodeConfig
import com.atlassian.performance.tools.infrastructure.api.jira.SetenvSh
import com.atlassian.performance.tools.infrastructure.api.jira.install.InstalledJira
import com.atlassian.performance.tools.infrastructure.api.jira.report.FileListing
import com.atlassian.performance.tools.ssh.api.SshConnection

class JvmConfig(
private val config: JiraNodeConfig
) : PostInstallHook {

override fun call(
ssh: SshConnection,
jira: InstalledJira,
hooks: PostInstallHooks
) {
val gcLog = JiraGcLog(jira.installation.path)
SetenvSh(jira.installation.path).setup(
connection = ssh,
config = config,
gcLog = gcLog,
jiraIp = jira.server.ip
)
val report = FileListing(gcLog.path("*"))
hooks.reports.add(report)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package com.atlassian.performance.tools.infrastructure.api.jira.install.hook

import com.atlassian.performance.tools.infrastructure.Iostat
import com.atlassian.performance.tools.infrastructure.api.jira.install.InstalledJira
import com.atlassian.performance.tools.infrastructure.api.jira.start.StartedJira
import com.atlassian.performance.tools.infrastructure.api.jira.start.hook.PostStartHook
import com.atlassian.performance.tools.infrastructure.api.jira.start.hook.PostStartHooks
import com.atlassian.performance.tools.infrastructure.api.os.OsMetric
import com.atlassian.performance.tools.infrastructure.api.os.Ubuntu
import com.atlassian.performance.tools.infrastructure.api.os.Vmstat
import com.atlassian.performance.tools.infrastructure.jira.report.RemoteMonitoringProcessReport
import com.atlassian.performance.tools.ssh.api.SshConnection

class LateUbuntuSysstat : PostInstallHook {
override fun call(
ssh: SshConnection,
jira: InstalledJira,
hooks: PostInstallHooks
) {
val ubuntu = Ubuntu()
ubuntu.install(ssh, listOf("sysstat"))
listOf(Vmstat(), Iostat())
.map { PostStartOsMetric(it) }
.forEach { hooks.postStart.insert(it) }
}
}

private class PostStartOsMetric(
private val metric: OsMetric
) : PostStartHook {
override fun call(ssh: SshConnection, jira: StartedJira, hooks: PostStartHooks) {
val process = metric.start(ssh)
hooks.reports.add(RemoteMonitoringProcessReport(process))
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.atlassian.performance.tools.infrastructure.api.jira.install.hook

import com.atlassian.performance.tools.infrastructure.api.jira.install.InstalledJira
import com.atlassian.performance.tools.ssh.api.SshConnection

/**
* Intercepts a call after Jira is installed.
*/
interface PostInstallHook {

/**
* @param [ssh] connects to the [jira]
* @param [jira] points to the installed Jira
* @param [hooks] inserts future hooks and reports
*/
fun call(
ssh: SshConnection,
jira: InstalledJira,
hooks: PostInstallHooks
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package com.atlassian.performance.tools.infrastructure.api.jira.install.hook

import com.atlassian.performance.tools.infrastructure.api.jira.JiraNodeConfig
import com.atlassian.performance.tools.infrastructure.api.jira.install.InstalledJira
import com.atlassian.performance.tools.infrastructure.api.jira.start.hook.PreStartHooks
import com.atlassian.performance.tools.infrastructure.jira.install.hook.ProfilerHook
import com.atlassian.performance.tools.infrastructure.jira.install.hook.SplunkForwarderHook
import com.atlassian.performance.tools.ssh.api.SshConnection
import java.util.*
import java.util.concurrent.ConcurrentLinkedQueue

class PostInstallHooks private constructor(
val preStart: PreStartHooks
) {

private val hooks: Queue<PostInstallHook> = ConcurrentLinkedQueue()
val postStart = preStart.postStart
val reports = postStart.reports

fun insert(
hook: PostInstallHook
) {
hooks.add(hook)
}

internal fun call(
ssh: SshConnection,
jira: InstalledJira
) {
while (true) {
hooks
.poll()
?.call(ssh, jira, this)
?: break
}
}

companion object Factory {
fun default(): PostInstallHooks = PostInstallHooks(PreStartHooks.default()).apply {
val config = JiraNodeConfig.Builder().build()
listOf(
JiraHomeProperty(),
DisabledAutoBackup(),
JvmConfig(config),
ProfilerHook(config.profiler),
SplunkForwarderHook(config.splunkForwarder),
JiraLogs(),
LateUbuntuSysstat()
).forEach { insert(it) }
}

fun empty(): PostInstallHooks = PostInstallHooks(PreStartHooks.empty())
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.atlassian.performance.tools.infrastructure.api.jira.install.hook

import com.atlassian.performance.tools.infrastructure.api.jira.install.TcpServer
import com.atlassian.performance.tools.ssh.api.SshConnection

/**
* Intercepts a call before Jira is installed.
*/
interface PreInstallHook {

/**
* @param [ssh] connects to the [server]
* @param [server] will install Jira
* @param [hooks] inserts future hooks and reports
*/
fun call(
ssh: SshConnection,
server: TcpServer,
hooks: PreInstallHooks
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package com.atlassian.performance.tools.infrastructure.api.jira.install.hook

import com.atlassian.performance.tools.infrastructure.api.jira.install.TcpServer
import com.atlassian.performance.tools.ssh.api.SshConnection
import java.util.*
import java.util.concurrent.ConcurrentLinkedQueue

class PreInstallHooks private constructor(
val postInstall: PostInstallHooks
) {

private val hooks: Queue<PreInstallHook> = ConcurrentLinkedQueue()
val preStart = postInstall.preStart
val postStart = preStart.postStart
val reports = postStart.reports

fun insert(
hook: PreInstallHook
) {
hooks.add(hook)
}

internal fun call(
ssh: SshConnection,
server: TcpServer
) {
while (true) {
hooks
.poll()
?.call(ssh, server, this)
?: break
}
}

companion object Factory {
fun default(): PreInstallHooks = PreInstallHooks(PostInstallHooks.default())

fun empty(): PreInstallHooks = PreInstallHooks(PostInstallHooks.empty())
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.atlassian.performance.tools.infrastructure.api.jira.install.hook

import com.atlassian.performance.tools.infrastructure.api.jira.report.Report
import com.atlassian.performance.tools.ssh.api.SshConnection

class SystemLog : Report {

override fun locate(ssh: SshConnection): List<String> {
return listOf("/var/log/syslog")
}
}
Loading

0 comments on commit 77ef790

Please sign in to comment.