Skip to content
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

Harden status parsing #191

Merged
merged 7 commits into from
Jun 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,14 @@ Adding a requirement of a major version of a dependency is breaking a contract.
Dropping a requirement of a major version of a dependency is a new contract.

## [Unreleased]
[Unreleased]: https://github.com/atlassian/aws-infrastructure/compare/release-3.1.6...master
[Unreleased]: https://github.com/atlassian/aws-infrastructure/compare/release-3.2.0...master

### Fixed
- Harden `JiraStatus` parsing.
- Reduce `JiraStatus` log spam.

## [3.2.0] - 2024-06-24
[3.2.0]: https://github.com/atlassian/aws-infrastructure/compare/release-3.1.4...release-3.2.0

## 3.1.7 - 2024-06-24
## 3.1.6 - 2024-06-12
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -413,6 +413,9 @@ class DataCenterFormula private constructor(

fun accessRequester(accessRequester: AccessRequester) = apply { this.accessRequester = accessRequester }

/**
* @since 3.2.0
*/
fun waitForRunning(waitForRunning: Boolean) = apply { this.waitForRunning = waitForRunning }

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,9 @@ class StandaloneFormula private constructor(

fun accessRequester(accessRequester: AccessRequester) = apply { this.accessRequester = accessRequester }

/**
* @since 3.2.0
*/
fun waitForRunning(waitForRunning: Boolean) = apply { this.waitForRunning = waitForRunning }
fun waitForUpgrades(waitForUpgrades: Boolean) = apply { this.waitForUpgrades = waitForUpgrades }

Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package com.atlassian.performance.tools.awsinfrastructure.jira

import org.apache.logging.log4j.LogManager
import java.io.StringReader
import javax.json.Json
import kotlin.streams.asSequence

/**
* https://confluence.atlassian.com/jirakb/jira-status-endpoint-response-meanings-1116294680.html
Expand All @@ -17,16 +17,19 @@ enum class JiraStatus {

object Parser {

private val LOG = LogManager.getLogger(this::class.java)

fun parseResponse(response: String): JiraStatus? {
return Json.createParser(StringReader(response)).use { jsonParser ->
jsonParser
.valueStream
.asSequence()
.firstOrNull()
?.asJsonObject()
?.getString("state")
?.let { state -> JiraStatus.values().find { it.name == state } }
val state = try {
Json.createReader(StringReader(response))
.read()
.asJsonObject()
.getString("state")
} catch (e: Exception) {
LOG.warn("Invalid JSON state: '$response'", e)
return null
}
return JiraStatus.values().find { it.name == state }
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,14 @@ import com.atlassian.performance.tools.infrastructure.api.process.RemoteMonitori
import com.atlassian.performance.tools.infrastructure.api.profiler.Profiler
import com.atlassian.performance.tools.ssh.api.Ssh
import com.atlassian.performance.tools.ssh.api.SshConnection
import org.apache.logging.log4j.Level
import org.apache.logging.log4j.LogManager
import org.apache.logging.log4j.Logger
import java.io.StringReader
import java.net.URI
import java.time.Duration
import java.time.Duration.ofMinutes
import java.time.Duration.ofSeconds
import java.time.Instant.now
import javax.json.Json

internal class StandaloneStoppedNode(
private val name: String,
Expand Down Expand Up @@ -118,8 +117,13 @@ internal class StandaloneStoppedNode(
threadDump,
"RUNNING state"
) {
val response = ssh.safeExecute("curl $statusEndpoint", launchTimeouts.unresponsivenessTimeout).output
JiraStatus.Parser.parseResponse(response) == JiraStatus.RUNNING
val curl = ssh.safeExecute(
"curl --silent $statusEndpoint",
launchTimeouts.unresponsivenessTimeout,
stdout = Level.DEBUG,
stderr = Level.DEBUG
)
curl.isSuccessful() && JiraStatus.Parser.parseResponse(curl.output) == JiraStatus.RUNNING
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,19 @@
package com.atlassian.performance.tools.awsinfrastructure.jira

import com.atlassian.performance.tools.awsinfrastructure.LogConfigurationFactory
import com.atlassian.performance.tools.workspace.api.RootWorkspace
import org.apache.logging.log4j.core.config.ConfigurationFactory
import org.assertj.core.api.Assertions.assertThat
import org.junit.Before
import org.junit.Test

class JiraStatusTest {

@Before
fun setUpLogs() {
ConfigurationFactory.setConfigurationFactory(LogConfigurationFactory(RootWorkspace().currentTask))
}

@Test
fun shouldParseRunning() {
val actual = JiraStatus.Parser.parseResponse("""{"state":"RUNNING"}""")
Expand Down Expand Up @@ -44,4 +54,25 @@ class JiraStatusTest {

assertThat(actual).isNull()
}

@Test
fun shouldParseGarbled() {
val actual = JiraStatus.Parser.parseResponse("""<html>SURPRISE</html>""")

assertThat(actual).isNull()
}

@Test
fun shouldParseRandomJson() {
val actual = JiraStatus.Parser.parseResponse("""[{"banana": "sure"}]""")

assertThat(actual).isNull()
}

@Test
fun shouldParseRandomJsonObject() {
val actual = JiraStatus.Parser.parseResponse("""{"hello": "it's me"}""")

assertThat(actual).isNull()
}
}
Loading