-
Notifications
You must be signed in to change notification settings - Fork 23
Issue/jperf 273 transplant ssh jira nodes #7
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from 26 commits
0a4e1f0
2d91665
1946c51
41b1f87
6d1ffef
ce3b38a
f032696
06bee9a
336c278
eec3e10
2e3a2a9
d129d08
58ba182
1984d8e
7192b70
fac32ba
ebf7325
d311c65
c87d198
f036201
13a0c5c
1156aae
23a7138
c18a5b0
26bdabb
2742b75
a336862
8dc645b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,2 +1,3 @@ | ||
| [*.{kt,kts}] | ||
| indent_size = 4 | ||
| [*.{kt, kts}] | ||
| indent_size = 4 | ||
| insert_final_newline = true |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| package com.atlassian.performance.tools.infrastructure.api.database | ||
|
|
||
| import com.atlassian.performance.tools.infrastructure.api.Sed | ||
| import com.atlassian.performance.tools.infrastructure.api.jira.hook.install.PostInstallHooks | ||
| import com.atlassian.performance.tools.infrastructure.api.jira.hook.install.InstalledJira | ||
| import com.atlassian.performance.tools.infrastructure.api.jira.hook.install.PostInstallHook | ||
| import com.atlassian.performance.tools.ssh.api.SshConnection | ||
|
|
||
| class DatabaseIpConfig( | ||
| private val databaseIp: String | ||
| ) : PostInstallHook { | ||
|
|
||
| override fun call( | ||
| ssh: SshConnection, | ||
| jira: InstalledJira, | ||
| hooks: PostInstallHooks | ||
| ) { | ||
| Sed().replace( | ||
| connection = ssh, | ||
| expression = "(<url>.*(@(//)?|//))" + "([^:/]+)" + "(.*</url>)", | ||
| output = """\1$databaseIp\5""", | ||
| file = "${jira.home}/dbconfig.xml" | ||
| ) | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -61,4 +61,4 @@ class MySqlDatabase( | |
| Thread.sleep(Duration.ofSeconds(10).toMillis()) | ||
| } | ||
| } | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,35 @@ | ||
| package com.atlassian.performance.tools.infrastructure.api.database | ||
|
|
||
| import com.atlassian.performance.tools.infrastructure.api.jira.hook.install.PostInstallHooks | ||
| import com.atlassian.performance.tools.infrastructure.api.jira.hook.install.InstalledJira | ||
| import com.atlassian.performance.tools.infrastructure.api.jira.hook.install.PostInstallHook | ||
| import com.atlassian.performance.tools.jvmtasks.api.Backoff | ||
| import com.atlassian.performance.tools.jvmtasks.api.IdempotentAction | ||
| import com.atlassian.performance.tools.ssh.api.SshConnection | ||
| import java.time.Duration | ||
|
|
||
| class MysqlConnector : PostInstallHook { | ||
|
|
||
| override fun call( | ||
| ssh: SshConnection, | ||
| jira: InstalledJira, | ||
| hooks: PostInstallHooks | ||
| ) { | ||
| val connector = "https://dev.mysql.com/get/Downloads/Connector-J/mysql-connector-java-5.1.40.tar.gz" | ||
| IdempotentAction( | ||
| description = "Download MySQL connector", | ||
| action = { ssh.execute("wget -q $connector") } | ||
| ).retry( | ||
| maxAttempts = 3, | ||
| backoff = StaticBackoff(Duration.ofSeconds(5)) | ||
| ) | ||
| ssh.execute("tar -xzf mysql-connector-java-5.1.40.tar.gz") | ||
| ssh.execute("cp mysql-connector-java-5.1.40/mysql-connector-java-5.1.40-bin.jar ${jira.installation}/lib") | ||
| } | ||
| } | ||
|
|
||
| private class StaticBackoff( | ||
| private val backOff: Duration | ||
| ) : Backoff { | ||
| override fun backOff(attempt: Int): Duration = backOff | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,51 @@ | ||
| package com.atlassian.performance.tools.infrastructure.api.database | ||
|
|
||
| import com.atlassian.performance.tools.infrastructure.DockerImage | ||
| import com.atlassian.performance.tools.infrastructure.api.dataset.DatasetPackage | ||
| import com.atlassian.performance.tools.ssh.api.SshConnection | ||
| import org.apache.logging.log4j.LogManager | ||
| import org.apache.logging.log4j.Logger | ||
| import java.net.URI | ||
| import java.time.Duration | ||
|
|
||
| class PostgresDatabase( | ||
| private val source: DatasetPackage, | ||
| private val maxConnections: Int | ||
| ) : Database { | ||
| private val logger: Logger = LogManager.getLogger(this::class.java) | ||
|
|
||
| private val image: DockerImage = DockerImage( | ||
| name = "postgres:9.6.15", | ||
| pullTimeout = Duration.ofMinutes(5) | ||
| ) | ||
|
|
||
| constructor( | ||
| source: DatasetPackage | ||
| ) : this( | ||
| source = source, | ||
| maxConnections = 200 | ||
| ) | ||
|
|
||
| override fun setup(ssh: SshConnection): String { | ||
| val data = source.download(ssh) | ||
| val containerName = image.run( | ||
| ssh = ssh, | ||
| // TODO Dataset for Postgres | ||
| // parameters = "-p 5432:5432 -v `realpath $data`:/", | ||
| parameters = "-p 5432:5432", | ||
| arguments = "-c 'listen_addresses='*'' -c 'max_connections=$maxConnections'" | ||
| ) | ||
| Thread.sleep(Duration.ofSeconds(15).toMillis()) | ||
| logger.debug("Postgres - creating jira user and database") | ||
| ssh.execute("sudo docker exec -u postgres $containerName psql --command \"CREATE USER jira WITH NOSUPERUSER INHERIT NOCREATEROLE NOCREATEDB LOGIN PASSWORD 'jira';\"") | ||
| ssh.execute("sudo docker exec -u postgres $containerName createdb -E UNICODE -l C -T template0 -O jira jira") | ||
| return data | ||
| } | ||
|
|
||
| override fun start(jira: URI, ssh: SshConnection) { | ||
| // TODO Check logs for the following entry | ||
| // LOG: database system is ready to accept connections | ||
| Thread.sleep(Duration.ofSeconds(15).toMillis()) | ||
| } | ||
|
|
||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| package com.atlassian.performance.tools.infrastructure.api.jira | ||
|
|
||
| import com.atlassian.performance.tools.ssh.api.SshConnection | ||
|
|
||
| class EmptyJiraHome : JiraHomeSource { | ||
| override fun download(ssh: SshConnection): String { | ||
| val jiraHome = "jira-home" | ||
| ssh.execute("mkdir $jiraHome") | ||
| return jiraHome | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| package com.atlassian.performance.tools.infrastructure.api.jira.hook | ||
|
|
||
| import com.atlassian.performance.tools.infrastructure.api.jira.JiraNodeConfig | ||
| import com.atlassian.performance.tools.infrastructure.api.jira.hook.install.DefaultPostInstallHook | ||
| import com.atlassian.performance.tools.infrastructure.api.jira.hook.install.PreInstallHooks | ||
| import com.atlassian.performance.tools.infrastructure.api.jira.hook.start.DefaultPostStartHook | ||
| import net.jcip.annotations.ThreadSafe | ||
|
|
||
| @ThreadSafe | ||
| class JiraNodeHooks { | ||
|
dagguh marked this conversation as resolved.
Outdated
|
||
|
|
||
| val preInstall = PreInstallHooks() | ||
| val postInstall = preInstall.postInstall | ||
| val preStart = postInstall.preStart | ||
| val postStart = preStart.postStart | ||
| val reports = postStart.reports | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These are all already available via hooks.preInstall.postInstall.preStart.postStart.reports.list()After: |
||
|
|
||
| companion object { | ||
| fun default(): JiraNodeHooks = JiraNodeHooks() | ||
| .apply { postStart.insert(DefaultPostStartHook()) } | ||
| .apply { postInstall.insert(DefaultPostInstallHook(JiraNodeConfig.Builder().build())) } | ||
|
|
||
| fun empty(): JiraNodeHooks = JiraNodeHooks() | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,55 @@ | ||
| package com.atlassian.performance.tools.infrastructure.api.jira.hook.install | ||
|
|
||
| import com.atlassian.performance.tools.infrastructure.api.jira.hook.start.PostStartHooks | ||
| import com.atlassian.performance.tools.infrastructure.api.jira.hook.report.Report | ||
| import com.atlassian.performance.tools.infrastructure.api.jira.hook.start.PostStartHook | ||
| import com.atlassian.performance.tools.ssh.api.SshConnection | ||
| import java.net.URI | ||
|
|
||
| class AsyncProfilerHook : PreInstallHook { | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @mzyromski-atlassian This is one of the more advanced usage of hooks. |
||
|
|
||
| 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,23 @@ | ||
| package com.atlassian.performance.tools.infrastructure.api.jira.hook.install | ||
|
|
||
| import com.atlassian.performance.tools.infrastructure.api.jira.SharedHome | ||
| 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 // 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,27 @@ | ||
| package com.atlassian.performance.tools.infrastructure.api.jira.hook.install | ||
|
|
||
| import com.atlassian.performance.tools.infrastructure.api.jira.JiraNodeConfig | ||
| import com.atlassian.performance.tools.infrastructure.jira.hook.install.ProfilerHook | ||
| import com.atlassian.performance.tools.infrastructure.jira.hook.install.SplunkForwarderHook | ||
| import com.atlassian.performance.tools.ssh.api.SshConnection | ||
|
|
||
| class DefaultPostInstallHook( | ||
| private val config: JiraNodeConfig | ||
| ) : PostInstallHook { | ||
|
|
||
| override fun call( | ||
| ssh: SshConnection, | ||
| jira: InstalledJira, | ||
| hooks: PostInstallHooks | ||
| ) { | ||
| listOf( | ||
| JiraHomeProperty(), | ||
| DisabledAutoBackup(), | ||
| JvmConfig(config), | ||
| ProfilerHook(config.profiler), | ||
| SplunkForwarderHook(config.splunkForwarder), | ||
| JiraLogs(), | ||
| LateUbuntuSysstat() | ||
| ).forEach { it.call(ssh, jira, hooks) } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| package com.atlassian.performance.tools.infrastructure.api.jira.hook.install | ||
|
|
||
| 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}/jira-config.properties") | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| package com.atlassian.performance.tools.infrastructure.api.jira.hook.install | ||
|
|
||
| import com.atlassian.performance.tools.ssh.api.SshConnection | ||
|
|
||
| class HookedJiraInstallation( | ||
| private val installation: JiraInstallation, | ||
| private val hooks: PreInstallHooks | ||
| ) : JiraInstallation { | ||
|
|
||
| override fun install( | ||
| ssh: SshConnection, | ||
| server: TcpServer | ||
| ): InstalledJira { | ||
| hooks.call(ssh, server) | ||
| val installed = installation.install(ssh, server) | ||
| 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.hook.install | ||
|
|
||
| import com.atlassian.performance.tools.infrastructure.api.jvm.JavaDevelopmentKit | ||
|
|
||
| class InstalledJira( | ||
| /** | ||
| * E.g. it contains `./dbconfig.xml` | ||
| */ | ||
| val home: String, | ||
| /** | ||
| * E.g. it contains `./conf/server.xml` | ||
| */ | ||
| val installation: String, | ||
| val jdk: JavaDevelopmentKit, | ||
| val server: TcpServer | ||
| ) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| package com.atlassian.performance.tools.infrastructure.api.jira.hook.install | ||
|
|
||
| import com.atlassian.performance.tools.ssh.api.SshConnection | ||
|
|
||
| class JiraHomeProperty : PostInstallHook { | ||
|
|
||
| override fun call( | ||
| ssh: SshConnection, | ||
| jira: InstalledJira, | ||
| hooks: PostInstallHooks | ||
| ) { | ||
| val properties = "${jira.installation}/atlassian-jira/WEB-INF/classes/jira-application.properties" | ||
| ssh.execute("echo jira.home=`realpath ${jira.home}` > $properties") | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a test to cover this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, but right now it's externalized.
We can include this coverage in here via
SshUbuntu