mirror of
https://github.com/corda/corda.git
synced 2025-03-01 04:16:21 +00:00
ENT-1456 Adding try-catch to jira ticket processing (#667)
* Adding try-catch to jira ticket processing * Addressing review comments * Addressing review comments * Refactoring getTransitionId method. * Addressing review comments * Refactoring to use requireNotNull * Refactoring to use more requireNotNull * Fixing missing map population
This commit is contained in:
parent
179e479aa0
commit
a320c8d49f
@ -31,8 +31,9 @@ class PersistentCertificateRevocationRequestStorage(private val database: CordaP
|
||||
return database.transaction(TransactionIsolationLevel.SERIALIZABLE) {
|
||||
// Get matching CSR
|
||||
validate(request)
|
||||
val csr = retrieveCsr(request.certificateSerialNumber, request.csrRequestId, request.legalName)
|
||||
csr ?: throw IllegalArgumentException("No CSR matching the given criteria was found")
|
||||
val csr = requireNotNull(retrieveCsr(request.certificateSerialNumber, request.csrRequestId, request.legalName)) {
|
||||
"No CSR matching the given criteria was found"
|
||||
}
|
||||
// Check if there is an entry for the given certificate serial number
|
||||
val revocation = uniqueEntityWhere<CertificateRevocationRequestEntity> { builder, path ->
|
||||
val serialNumberEqual = builder.equal(path.get<BigInteger>(CertificateRevocationRequestEntity::certificateSerialNumber.name), request.certificateSerialNumber)
|
||||
@ -168,8 +169,9 @@ class PersistentCertificateRevocationRequestStorage(private val database: CordaP
|
||||
// Even though, we have an assumption that there is always a single instance of the doorman service running,
|
||||
// the SERIALIZABLE isolation level is used here just to ensure data consistency between the updates.
|
||||
return database.transaction(TransactionIsolationLevel.SERIALIZABLE) {
|
||||
val request = getRevocationRequestEntity(requestId, RequestStatus.NEW)
|
||||
request ?: throw IllegalArgumentException("Error when creating request ticket with id: $requestId. Request does not exist or its status is not NEW.")
|
||||
val request = requireNotNull(getRevocationRequestEntity(requestId, RequestStatus.NEW)) {
|
||||
"Error when creating request ticket with id: $requestId. Request does not exist or its status is not NEW."
|
||||
}
|
||||
val update = request.copy(
|
||||
modifiedAt = Instant.now(),
|
||||
status = RequestStatus.TICKET_CREATED)
|
||||
|
@ -39,12 +39,11 @@ class PersistentCertificateSigningRequestStorage(private val database: CordaPers
|
||||
|
||||
override fun putCertificatePath(requestId: String, certPath: CertPath, signedBy: String) {
|
||||
return database.transaction(TransactionIsolationLevel.SERIALIZABLE) {
|
||||
val request = uniqueEntityWhere<CertificateSigningRequestEntity> { builder, path ->
|
||||
val request = requireNotNull(uniqueEntityWhere<CertificateSigningRequestEntity> { builder, path ->
|
||||
val requestIdEq = builder.equal(path.get<String>(CertificateSigningRequestEntity::requestId.name), requestId)
|
||||
val statusEq = builder.equal(path.get<String>(CertificateSigningRequestEntity::status.name), RequestStatus.APPROVED)
|
||||
builder.and(requestIdEq, statusEq)
|
||||
}
|
||||
request ?: throw IllegalArgumentException("Cannot retrieve 'APPROVED' certificate signing request for request id: $requestId")
|
||||
}) { "Cannot retrieve 'APPROVED' certificate signing request for request id: $requestId" }
|
||||
val certificateSigningRequest = request.copy(
|
||||
modifiedBy = signedBy,
|
||||
modifiedAt = Instant.now(),
|
||||
@ -97,9 +96,8 @@ class PersistentCertificateSigningRequestStorage(private val database: CordaPers
|
||||
}
|
||||
|
||||
override fun markRequestTicketCreated(requestId: String) {
|
||||
return database.transaction(TransactionIsolationLevel.SERIALIZABLE) {
|
||||
val request = findRequest(requestId, RequestStatus.NEW)
|
||||
request ?: throw IllegalArgumentException("Error when creating request ticket with id: $requestId. Request does not exist or its status is not NEW.")
|
||||
database.transaction(TransactionIsolationLevel.SERIALIZABLE) {
|
||||
val request = requireNotNull(findRequest(requestId, RequestStatus.NEW)) { "Error when creating request ticket with id: $requestId. Request does not exist or its status is not NEW." }
|
||||
val update = request.copy(
|
||||
modifiedAt = Instant.now(),
|
||||
status = RequestStatus.TICKET_CREATED)
|
||||
@ -108,7 +106,7 @@ class PersistentCertificateSigningRequestStorage(private val database: CordaPers
|
||||
}
|
||||
|
||||
override fun approveRequest(requestId: String, approvedBy: String) {
|
||||
return database.transaction(TransactionIsolationLevel.SERIALIZABLE) {
|
||||
database.transaction(TransactionIsolationLevel.SERIALIZABLE) {
|
||||
findRequest(requestId, RequestStatus.TICKET_CREATED)?.let {
|
||||
val update = it.copy(
|
||||
modifiedBy = approvedBy,
|
||||
@ -121,8 +119,7 @@ class PersistentCertificateSigningRequestStorage(private val database: CordaPers
|
||||
|
||||
override fun rejectRequest(requestId: String, rejectedBy: String, rejectReason: String?) {
|
||||
database.transaction(TransactionIsolationLevel.SERIALIZABLE) {
|
||||
val request = findRequest(requestId)
|
||||
request ?: throw IllegalArgumentException("Error when rejecting request with id: $requestId. Request does not exist.")
|
||||
val request = requireNotNull(findRequest(requestId)) { "Error when rejecting request with id: $requestId. Request does not exist." }
|
||||
val update = request.copy(
|
||||
modifiedBy = rejectedBy,
|
||||
modifiedAt = Instant.now(),
|
||||
|
@ -44,14 +44,8 @@ class CrrJiraClient(restClient: JiraRestClient, projectCode: String) : JiraClien
|
||||
.fail { CsrJiraClient.logger.error("Error processing request '${createdIssue.key}' : Exception when uploading attachment to JIRA.", it) }.claim()
|
||||
}
|
||||
|
||||
fun updateDoneCertificateRevocationRequests(doneRequests: List<String>) {
|
||||
doneRequests.forEach { id ->
|
||||
val issue = getIssueById(id)
|
||||
issue ?: throw IllegalStateException("Missing the JIRA ticket for the request ID: $id")
|
||||
if (doneTransitionId == -1) {
|
||||
doneTransitionId = restClient.issueClient.getTransitions(issue.transitionsUri).claim().single { it.name == "Done" }.id
|
||||
}
|
||||
restClient.issueClient.transition(issue, TransitionInput(doneTransitionId)).fail { logger.error("Exception when transiting JIRA status.", it) }.claim()
|
||||
}
|
||||
fun updateDoneCertificateRevocationRequest(requestId: String) {
|
||||
val issue = requireNotNull(getIssueById(requestId)) { "Missing the JIRA ticket for the request ID: $requestId" }
|
||||
restClient.issueClient.transition(issue, TransitionInput(getTransitionId(DONE_TRANSITION_KEY, issue))).fail { logger.error("Exception when transiting JIRA status.", it) }.claim()
|
||||
}
|
||||
}
|
||||
|
@ -75,19 +75,12 @@ class CsrJiraClient(restClient: JiraRestClient, projectCode: String) : JiraClien
|
||||
restClient.issueClient.createIssue(issue.build()).fail { logger.error("Exception when creating JIRA issue.", it) }.claim()
|
||||
}
|
||||
|
||||
fun updateDoneCertificateSigningRequests(signedRequests: Map<String, CertPath>) {
|
||||
fun updateDoneCertificateSigningRequest(requestId: String, certPath: CertPath) {
|
||||
// Retrieving certificates for signed CSRs to attach to the jira tasks.
|
||||
signedRequests.forEach { (id, certPath) ->
|
||||
val certificate = certPath.certificates.first()
|
||||
val issue = getIssueById(id)
|
||||
if (issue != null) {
|
||||
if (doneTransitionId == -1) {
|
||||
doneTransitionId = restClient.issueClient.getTransitions(issue.transitionsUri).claim().single { it.name == "Done" }.id
|
||||
}
|
||||
restClient.issueClient.transition(issue, TransitionInput(doneTransitionId)).fail { logger.error("Exception when transiting JIRA status.", it) }.claim()
|
||||
val issue = requireNotNull(getIssueById(requestId)) { "Cannot find the JIRA ticket `request ID` = $requestId" }
|
||||
restClient.issueClient.transition(issue, TransitionInput(getTransitionId(DONE_TRANSITION_KEY, issue))).fail { logger.error("Exception when transiting JIRA status.", it) }.claim()
|
||||
restClient.issueClient.addAttachment(issue.attachmentsUri, certificate.encoded.inputStream(), "${X509Utilities.CORDA_CLIENT_CA}.cer")
|
||||
.fail { logger.error("Error processing request '${issue.key}' : Exception when uploading attachment to JIRA.", it) }.claim()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -18,25 +18,29 @@ import com.atlassian.jira.rest.client.api.domain.Issue
|
||||
import com.atlassian.jira.rest.client.api.domain.IssueType
|
||||
import com.atlassian.jira.rest.client.api.domain.input.TransitionInput
|
||||
import net.corda.core.utilities.contextLogger
|
||||
import org.slf4j.Logger
|
||||
|
||||
abstract class JiraClient(protected val restClient: JiraRestClient, protected val projectCode: String) {
|
||||
companion object {
|
||||
val logger = contextLogger()
|
||||
|
||||
const val DONE_TRANSITION_KEY = "Done"
|
||||
const val START_TRANSITION_KEY = "Start Progress"
|
||||
const val STOP_TRANSITION_KEY = "Stop Progress"
|
||||
|
||||
}
|
||||
|
||||
// The JIRA project must have a Request ID and reject reason field, and the Task issue type.
|
||||
protected val requestIdField: Field = restClient.metadataClient.fields.claim().find { it.name == "Request ID" } ?: throw IllegalArgumentException("Request ID field not found in JIRA '$projectCode'")
|
||||
protected val taskIssueType: IssueType = restClient.metadataClient.issueTypes.claim().find { it.name == "Task" } ?: throw IllegalArgumentException("Task issue type field not found in JIRA '$projectCode'")
|
||||
protected val rejectReasonField: Field = restClient.metadataClient.fields.claim().find { it.name == "Reject Reason" } ?: throw IllegalArgumentException("Reject Reason field not found in JIRA '$projectCode'")
|
||||
protected val requestIdField: Field = requireNotNull(restClient.metadataClient.fields.claim().find { it.name == "Request ID" }) { "Request ID field not found in JIRA '$projectCode'" }
|
||||
protected val taskIssueType: IssueType = requireNotNull(restClient.metadataClient.issueTypes.claim().find { it.name == "Task" }) { "Task issue type field not found in JIRA '$projectCode'" }
|
||||
protected val rejectReasonField: Field = requireNotNull(restClient.metadataClient.fields.claim().find { it.name == "Reject Reason" }) { "Reject Reason field not found in JIRA '$projectCode'" }
|
||||
|
||||
protected var doneTransitionId: Int = -1
|
||||
private var canceledTransitionId: Int = -1
|
||||
private var startProgressTransitionId: Int = -1
|
||||
private val transitions = mutableMapOf<String, Int>()
|
||||
|
||||
fun getApprovedRequests(): List<ApprovedRequest> {
|
||||
val issues = restClient.searchClient.searchJql("project = $projectCode AND status = Approved").claim().issues
|
||||
return issues.mapNotNull { issue ->
|
||||
val requestId = issue.getField(requestIdField.id)?.value?.toString() ?: throw IllegalArgumentException("Error processing request '${issue.key}' : RequestId cannot be null.")
|
||||
val requestId = requireNotNull(issue.getField(requestIdField.id)?.value?.toString()) { "Error processing request '${issue.key}' : RequestId cannot be null." }
|
||||
// Issue retrieved via search doesn't contain change logs.
|
||||
val fullIssue = restClient.issueClient.getIssue(issue.key, listOf(IssueRestClient.Expandos.CHANGELOG)).claim()
|
||||
val approvedBy = fullIssue.changelog?.last { it.items.any { it.field == "status" && it.toString == "Approved" } }
|
||||
@ -47,7 +51,7 @@ abstract class JiraClient(protected val restClient: JiraRestClient, protected va
|
||||
fun getRejectedRequests(): List<RejectedRequest> {
|
||||
val issues = restClient.searchClient.searchJql("project = $projectCode AND status = Rejected").claim().issues
|
||||
return issues.mapNotNull { issue ->
|
||||
val requestId = issue.getField(requestIdField.id)?.value?.toString() ?: throw IllegalArgumentException("Error processing request '${issue.key}' : RequestId cannot be null.")
|
||||
val requestId = requireNotNull(issue.getField(requestIdField.id)?.value?.toString()) { "Error processing request '${issue.key}' : RequestId cannot be null." }
|
||||
val rejectedReason = issue.getField(rejectReasonField.id)?.value?.toString()
|
||||
// Issue retrieved via search doesn't contain comments.
|
||||
val fullIssue = restClient.issueClient.getIssue(issue.key, listOf(IssueRestClient.Expandos.CHANGELOG)).claim()
|
||||
@ -56,29 +60,38 @@ abstract class JiraClient(protected val restClient: JiraRestClient, protected va
|
||||
}
|
||||
}
|
||||
|
||||
fun updateRejectedRequests(rejectedRequests: List<String>) {
|
||||
rejectedRequests.mapNotNull { getIssueById(it) }
|
||||
.forEach { issue ->
|
||||
fun updateRejectedRequest(requestId: String) {
|
||||
val issue = requireNotNull(getIssueById(requestId)) { "Issue with the `request ID` = $requestId does not exist." }
|
||||
// Move status to in progress.
|
||||
if (startProgressTransitionId == -1) {
|
||||
startProgressTransitionId = restClient.issueClient.getTransitions(issue.transitionsUri).claim().single { it.name == "Start Progress" }.id
|
||||
}
|
||||
restClient.issueClient.transition(issue, TransitionInput(startProgressTransitionId)).fail { logger.error("Error processing request '${issue.key}' : Exception when transiting JIRA status.", it) }.claim()
|
||||
// Move status to cancelled.
|
||||
if (canceledTransitionId == -1) {
|
||||
canceledTransitionId = restClient.issueClient.getTransitions(issue.transitionsUri).claim().single { it.name == "Stop Progress" }.id
|
||||
}
|
||||
restClient.issueClient.transition(issue, TransitionInput(canceledTransitionId)).fail { logger.error("Error processing request '${issue.key}' : Exception when transiting JIRA status.", it) }.claim()
|
||||
restClient.issueClient.transition(issue, TransitionInput(getTransitionId(START_TRANSITION_KEY, issue))).fail { logger.error("Error processing request '${issue.key}' : Exception when transiting JIRA status.", it) }.claim()
|
||||
// Move status to stopped.
|
||||
restClient.issueClient.transition(issue, TransitionInput(getTransitionId(STOP_TRANSITION_KEY, issue))).fail { logger.error("Error processing request '${issue.key}' : Exception when transiting JIRA status.", it) }.claim()
|
||||
restClient.issueClient.addComment(issue.commentsUri, Comment.valueOf("Request cancelled by doorman.")).claim()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected fun getIssueById(requestId: String): Issue? {
|
||||
// Jira only support ~ (contains) search for custom textfield.
|
||||
return restClient.searchClient.searchJql("'Request ID' ~ $requestId").claim().issues.firstOrNull()
|
||||
}
|
||||
|
||||
protected fun getTransitionId(transitionKey: String, issue: Issue): Int {
|
||||
return transitions.computeIfAbsent(transitionKey, { key ->
|
||||
restClient.issueClient.getTransitions(issue.transitionsUri).claim().single { it.name == key }.id
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
data class ApprovedRequest(val requestId: String, val approvedBy: String)
|
||||
|
||||
data class RejectedRequest(val requestId: String, val rejectedBy: String, val reason: String?)
|
||||
|
||||
inline fun <T : Any> Iterable<T>.forEachWithExceptionLogging(logger: Logger, action: (T) -> Unit) {
|
||||
for (element in this) {
|
||||
try {
|
||||
action(element)
|
||||
} catch (e: Exception) {
|
||||
logger.error("Error while processing an element: $element", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -19,7 +19,6 @@ import net.corda.core.internal.exists
|
||||
import net.corda.nodeapi.internal.crypto.X509KeyStore
|
||||
import net.corda.nodeapi.internal.crypto.X509Utilities
|
||||
import org.slf4j.LoggerFactory
|
||||
import java.nio.file.NoSuchFileException
|
||||
import java.time.Instant
|
||||
import kotlin.system.exitProcess
|
||||
|
||||
@ -71,7 +70,7 @@ private fun processKeyStore(config: NetworkManagementServerConfig): Pair<CertPat
|
||||
|
||||
private fun rootKeyGenMode(cmdLineOptions: DoormanCmdLineOptions, config: NetworkManagementServerConfig) {
|
||||
generateRootKeyPair(
|
||||
config.rootStorePath ?: throw IllegalArgumentException("The 'rootStorePath' parameter must be specified when generating keys!"),
|
||||
requireNotNull(config.rootStorePath) { "The 'rootStorePath' parameter must be specified when generating keys!" },
|
||||
config.rootKeystorePassword,
|
||||
config.rootPrivateKeyPassword,
|
||||
cmdLineOptions.trustStorePassword
|
||||
@ -80,8 +79,8 @@ private fun rootKeyGenMode(cmdLineOptions: DoormanCmdLineOptions, config: Networ
|
||||
|
||||
private fun caKeyGenMode(config: NetworkManagementServerConfig) {
|
||||
generateSigningKeyPairs(
|
||||
config.keystorePath ?: throw IllegalArgumentException("The 'keystorePath' parameter must be specified when generating keys!"),
|
||||
config.rootStorePath ?: throw IllegalArgumentException("The 'rootStorePath' parameter must be specified when generating keys!"),
|
||||
requireNotNull(config.keystorePath) { "The 'keystorePath' parameter must be specified when generating keys!" },
|
||||
requireNotNull(config.rootStorePath) { "The 'rootStorePath' parameter must be specified when generating keys!" },
|
||||
config.rootKeystorePassword,
|
||||
config.rootPrivateKeyPassword,
|
||||
config.keystorePassword,
|
||||
|
@ -53,7 +53,7 @@ class DefaultCsrHandler(private val storage: CertificateSigningRequestStorage,
|
||||
return when (response?.status) {
|
||||
RequestStatus.NEW, RequestStatus.APPROVED, RequestStatus.TICKET_CREATED, null -> CertificateResponse.NotReady
|
||||
RequestStatus.REJECTED -> CertificateResponse.Unauthorised(response.remark ?: "Unknown reason")
|
||||
RequestStatus.DONE -> CertificateResponse.Ready(response.certData?.certPath ?: throw IllegalArgumentException("Certificate should not be null."))
|
||||
RequestStatus.DONE -> CertificateResponse.Ready(requireNotNull(response.certData?.certPath) { "Certificate should not be null." })
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -16,6 +16,7 @@ import com.r3.corda.networkmanage.common.persistence.RequestStatus
|
||||
import com.r3.corda.networkmanage.doorman.ApprovedRequest
|
||||
import com.r3.corda.networkmanage.doorman.CrrJiraClient
|
||||
import com.r3.corda.networkmanage.doorman.RejectedRequest
|
||||
import com.r3.corda.networkmanage.doorman.forEachWithExceptionLogging
|
||||
import net.corda.core.utilities.contextLogger
|
||||
import net.corda.nodeapi.internal.network.CertificateRevocationRequest
|
||||
|
||||
@ -50,24 +51,21 @@ class JiraCrrHandler(private val jiraClient: CrrJiraClient,
|
||||
private fun updateRequestStatuses(): Pair<List<ApprovedRequest>, List<RejectedRequest>> {
|
||||
// Update local request statuses.
|
||||
val approvedRequest = jiraClient.getApprovedRequests()
|
||||
approvedRequest.forEach { (id, approvedBy) -> crrStorage.approveRevocationRequest(id, approvedBy) }
|
||||
approvedRequest.forEachWithExceptionLogging(logger) { (id, approvedBy) -> crrStorage.approveRevocationRequest(id, approvedBy) }
|
||||
val rejectedRequest = jiraClient.getRejectedRequests()
|
||||
rejectedRequest.forEach { (id, rejectedBy, reason) -> crrStorage.rejectRevocationRequest(id, rejectedBy, reason) }
|
||||
rejectedRequest.forEachWithExceptionLogging(logger) { (id, rejectedBy, reason) -> crrStorage.rejectRevocationRequest(id, rejectedBy, reason) }
|
||||
return Pair(approvedRequest, rejectedRequest)
|
||||
}
|
||||
|
||||
private fun updateJiraTickets(approvedRequest: List<ApprovedRequest>, rejectedRequest: List<RejectedRequest>) {
|
||||
// Reconfirm request status and update jira status
|
||||
val doneRequests = approvedRequest.mapNotNull { crrStorage.getRevocationRequest(it.requestId) }
|
||||
approvedRequest.mapNotNull { crrStorage.getRevocationRequest(it.requestId) }
|
||||
.filter { it.status == RequestStatus.DONE }
|
||||
.map { it.requestId }
|
||||
.forEachWithExceptionLogging(logger) { jiraClient.updateDoneCertificateRevocationRequest(it.requestId) }
|
||||
|
||||
jiraClient.updateDoneCertificateRevocationRequests(doneRequests)
|
||||
|
||||
val rejectedRequestIDs = rejectedRequest.mapNotNull { crrStorage.getRevocationRequest(it.requestId) }
|
||||
rejectedRequest.mapNotNull { crrStorage.getRevocationRequest(it.requestId) }
|
||||
.filter { it.status == RequestStatus.REJECTED }
|
||||
.map { it.requestId }
|
||||
jiraClient.updateRejectedRequests(rejectedRequestIDs)
|
||||
.forEachWithExceptionLogging(logger) { jiraClient.updateRejectedRequest(it.requestId) }
|
||||
}
|
||||
|
||||
/**
|
||||
@ -77,12 +75,8 @@ class JiraCrrHandler(private val jiraClient: CrrJiraClient,
|
||||
* they might be left in the [RequestStatus.NEW] state if Jira is down.
|
||||
*/
|
||||
private fun createTickets() {
|
||||
crrStorage.getRevocationRequests(RequestStatus.NEW).forEach {
|
||||
try {
|
||||
crrStorage.getRevocationRequests(RequestStatus.NEW).forEachWithExceptionLogging(logger) {
|
||||
createTicket(it)
|
||||
} catch (e: Exception) {
|
||||
logger.warn("There were errors while creating Jira tickets for request '${it.requestId}'", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -17,12 +17,13 @@ import com.r3.corda.networkmanage.common.persistence.RequestStatus
|
||||
import com.r3.corda.networkmanage.doorman.ApprovedRequest
|
||||
import com.r3.corda.networkmanage.doorman.CsrJiraClient
|
||||
import com.r3.corda.networkmanage.doorman.RejectedRequest
|
||||
import com.r3.corda.networkmanage.doorman.forEachWithExceptionLogging
|
||||
import net.corda.core.utilities.contextLogger
|
||||
import org.bouncycastle.pkcs.PKCS10CertificationRequest
|
||||
|
||||
class JiraCsrHandler(private val jiraClient: CsrJiraClient, private val storage: CertificateSigningRequestStorage, private val delegate: CsrHandler) : CsrHandler by delegate {
|
||||
private companion object {
|
||||
val log = contextLogger()
|
||||
val logger = contextLogger()
|
||||
}
|
||||
|
||||
override fun saveRequest(rawRequest: PKCS10CertificationRequest): String {
|
||||
@ -34,7 +35,7 @@ class JiraCsrHandler(private val jiraClient: CsrJiraClient, private val storage:
|
||||
storage.markRequestTicketCreated(requestId)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
log.warn("There was an error while creating Jira tickets", e)
|
||||
logger.warn("There was an error while creating Jira tickets", e)
|
||||
} finally {
|
||||
return requestId
|
||||
}
|
||||
@ -50,24 +51,28 @@ class JiraCsrHandler(private val jiraClient: CsrJiraClient, private val storage:
|
||||
private fun updateRequestStatus(): Pair<List<ApprovedRequest>, List<RejectedRequest>> {
|
||||
// Update local request statuses.
|
||||
val approvedRequest = jiraClient.getApprovedRequests()
|
||||
approvedRequest.forEach { (id, approvedBy) -> storage.approveRequest(id, approvedBy) }
|
||||
approvedRequest.forEachWithExceptionLogging(logger) { (id, approvedBy) ->
|
||||
storage.approveRequest(id, approvedBy)
|
||||
}
|
||||
val rejectedRequest = jiraClient.getRejectedRequests()
|
||||
rejectedRequest.forEach { (id, rejectedBy, reason) -> storage.rejectRequest(id, rejectedBy, reason) }
|
||||
rejectedRequest.forEachWithExceptionLogging(logger) { (id, rejectedBy, reason) ->
|
||||
storage.rejectRequest(id, rejectedBy, reason)
|
||||
}
|
||||
return Pair(approvedRequest, rejectedRequest)
|
||||
}
|
||||
|
||||
private fun updateJiraTickets(approvedRequest: List<ApprovedRequest>, rejectedRequest: List<RejectedRequest>) {
|
||||
// Reconfirm request status and update jira status
|
||||
val signedRequests = approvedRequest.mapNotNull { storage.getRequest(it.requestId) }
|
||||
approvedRequest.mapNotNull { storage.getRequest(it.requestId) }
|
||||
.filter { it.status == RequestStatus.DONE && it.certData != null }
|
||||
.associateBy { it.requestId }
|
||||
.mapValues { it.value.certData!!.certPath }
|
||||
jiraClient.updateDoneCertificateSigningRequests(signedRequests)
|
||||
|
||||
val rejectedRequestIDs = rejectedRequest.mapNotNull { storage.getRequest(it.requestId) }
|
||||
.forEachWithExceptionLogging(logger) {
|
||||
jiraClient.updateDoneCertificateSigningRequest(it.requestId, it.certData!!.certPath)
|
||||
}
|
||||
rejectedRequest.mapNotNull { storage.getRequest(it.requestId) }
|
||||
.filter { it.status == RequestStatus.REJECTED }
|
||||
.map { it.requestId }
|
||||
jiraClient.updateRejectedRequests(rejectedRequestIDs)
|
||||
.forEachWithExceptionLogging(logger) {
|
||||
jiraClient.updateRejectedRequest(it.requestId)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -77,12 +82,8 @@ class JiraCsrHandler(private val jiraClient: CsrJiraClient, private val storage:
|
||||
* they might be left in the [RequestStatus.NEW] state if Jira is down.
|
||||
*/
|
||||
private fun createTickets() {
|
||||
storage.getRequests(RequestStatus.NEW).forEach {
|
||||
try {
|
||||
storage.getRequests(RequestStatus.NEW).forEachWithExceptionLogging(logger) {
|
||||
createTicket(it)
|
||||
} catch (e: Exception) {
|
||||
log.warn("There were errors while creating Jira tickets for request '${it.requestId}'", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -113,7 +113,7 @@ class NetworkMapWebService(private val nodeInfoStorage: NodeInfoStorage,
|
||||
return try {
|
||||
val signedParametersHash = input.readObject<SignedData<SecureHash>>()
|
||||
val hash = signedParametersHash.verified()
|
||||
networkMapStorage.getSignedNetworkParameters(hash) ?: throw IllegalArgumentException("No network parameters with hash $hash")
|
||||
requireNotNull(networkMapStorage.getSignedNetworkParameters(hash)) { "No network parameters with hash $hash" }
|
||||
logger.debug { "Received ack-parameters with $hash from ${signedParametersHash.sig.by}" }
|
||||
nodeInfoStorage.ackNodeInfoParametersUpdate(signedParametersHash.sig.by, hash)
|
||||
ok()
|
||||
|
@ -35,7 +35,7 @@ class ConsoleInputReader : InputReader {
|
||||
String(console.readPassword(format))
|
||||
} else {
|
||||
print(format)
|
||||
kotlin.io.readLine() ?: throw IllegalArgumentException("Password required")
|
||||
requireNotNull(kotlin.io.readLine()) { "Password required" }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -50,17 +50,19 @@ class CsrJiraClientTest {
|
||||
|
||||
@Test
|
||||
fun updateSignedRequests() {
|
||||
val requests = jiraClient.getApprovedRequests()
|
||||
val selfSignedCaCertPath = X509Utilities.buildCertPath(X509Utilities.createSelfSignedCACertificate(
|
||||
X500Principal("O=test,L=london,C=GB"),
|
||||
Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)))
|
||||
jiraClient.updateDoneCertificateSigningRequests(requests.associateBy({ it.requestId }, { selfSignedCaCertPath }))
|
||||
jiraClient.getApprovedRequests().forEach {
|
||||
jiraClient.updateDoneCertificateSigningRequest(it.requestId, selfSignedCaCertPath)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun updateRejectedRequests() {
|
||||
val requests = jiraClient.getRejectedRequests()
|
||||
jiraClient.updateRejectedRequests(requests.map { it.requestId })
|
||||
jiraClient.getRejectedRequests().forEach {
|
||||
jiraClient.updateRejectedRequest(it.requestId)
|
||||
}
|
||||
|
||||
assert(jiraClient.getRejectedRequests().isEmpty())
|
||||
}
|
||||
|
@ -144,8 +144,8 @@ class JiraCsrHandlerTest : TestBase() {
|
||||
assertEquals(RequestStatus.REJECTED, requests[id2]!!.status)
|
||||
|
||||
// Verify jira client get the correct call.
|
||||
verify(jiraClient).updateRejectedRequests(listOf(id2))
|
||||
verify(jiraClient).updateDoneCertificateSigningRequests(emptyMap())
|
||||
verify(jiraClient).updateRejectedRequest(id2)
|
||||
verify(jiraClient, never()).updateDoneCertificateSigningRequest(any(), any())
|
||||
|
||||
// Sign request 1
|
||||
val certPath = mock<CertPath>()
|
||||
@ -156,6 +156,6 @@ class JiraCsrHandlerTest : TestBase() {
|
||||
jiraCsrHandler.processRequests()
|
||||
|
||||
// Update signed request should be called.
|
||||
verify(jiraClient).updateDoneCertificateSigningRequests(mapOf(id1 to certPath))
|
||||
verify(jiraClient).updateDoneCertificateSigningRequest(id1, certPath)
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user