diff --git a/keel-core/src/main/kotlin/com/netflix/spinnaker/keel/persistence/ResourceRepository.kt b/keel-core/src/main/kotlin/com/netflix/spinnaker/keel/persistence/ResourceRepository.kt index 5048c57568..baafe9de74 100644 --- a/keel-core/src/main/kotlin/com/netflix/spinnaker/keel/persistence/ResourceRepository.kt +++ b/keel-core/src/main/kotlin/com/netflix/spinnaker/keel/persistence/ResourceRepository.kt @@ -166,5 +166,6 @@ enum class ResourceStatus { PAUSED, RESUMED, UNKNOWN, - DIFF_NOT_ACTIONABLE + DIFF_NOT_ACTIONABLE, + WAITING } diff --git a/keel-core/src/main/kotlin/com/netflix/spinnaker/keel/services/ResourceStatusService.kt b/keel-core/src/main/kotlin/com/netflix/spinnaker/keel/services/ResourceStatusService.kt index be13ec9c72..2537b3a34b 100644 --- a/keel-core/src/main/kotlin/com/netflix/spinnaker/keel/services/ResourceStatusService.kt +++ b/keel-core/src/main/kotlin/com/netflix/spinnaker/keel/services/ResourceStatusService.kt @@ -30,6 +30,7 @@ import com.netflix.spinnaker.keel.persistence.ResourceStatus.PAUSED import com.netflix.spinnaker.keel.persistence.ResourceStatus.RESUMED import com.netflix.spinnaker.keel.persistence.ResourceStatus.UNHAPPY import com.netflix.spinnaker.keel.persistence.ResourceStatus.UNKNOWN +import com.netflix.spinnaker.keel.persistence.ResourceStatus.WAITING import org.springframework.stereotype.Component /** @@ -66,6 +67,7 @@ class ResourceStatusService( history.isError() -> ERROR history.isCreated() -> CREATED history.isResumed() -> RESUMED + history.isWaiting() -> WAITING // must be before CURRENTLY_UNRESOLVABLE because it's a special case of that status history.isCurrentlyUnresolvable() -> CURRENTLY_UNRESOLVABLE else -> UNKNOWN } @@ -93,6 +95,12 @@ class ResourceStatusService( return first() is ResourceCreated } + private fun List.isWaiting(): Boolean { + // we expect to have only two events, but we will accept several different "unresolvable" events + // in order to be less brittle and show the user this status instead of an error + return size < 5 && all { it is ResourceCreated || it is ResourceCheckUnresolvable } + } + private fun List.isDiff(): Boolean { return first() is ResourceDeltaDetected || first() is ResourceMissing } diff --git a/keel-core/src/test/kotlin/com/netflix/spinnaker/keel/services/ResourceStatusServiceTests.kt b/keel-core/src/test/kotlin/com/netflix/spinnaker/keel/services/ResourceStatusServiceTests.kt index 8fca926fe0..f91fa8f348 100644 --- a/keel-core/src/test/kotlin/com/netflix/spinnaker/keel/services/ResourceStatusServiceTests.kt +++ b/keel-core/src/test/kotlin/com/netflix/spinnaker/keel/services/ResourceStatusServiceTests.kt @@ -27,6 +27,7 @@ import com.netflix.spinnaker.keel.persistence.ResourceStatus.MISSING_DEPENDENCY import com.netflix.spinnaker.keel.persistence.ResourceStatus.PAUSED import com.netflix.spinnaker.keel.persistence.ResourceStatus.RESUMED import com.netflix.spinnaker.keel.persistence.ResourceStatus.UNHAPPY +import com.netflix.spinnaker.keel.persistence.ResourceStatus.WAITING import com.netflix.spinnaker.keel.test.resource import com.netflix.spinnaker.kork.exceptions.SpinnakerException import dev.minutest.junit.JUnit5Minutests @@ -214,12 +215,41 @@ class ResourceStatusServiceTests : JUnit5Minutests { } context("when last event is ResourceCheckUnresolvable") { - before { - events.add(ResourceCheckUnresolvable(resource, object : ResourceCurrentlyUnresolvable("") {})) + context("only created and unresolvable events") { + before { + events.clear() + events.add(ResourceCreated(resource)) + events.add(ResourceCheckUnresolvable(resource, object : ResourceCurrentlyUnresolvable("") {})) + } + + test("returns WAITING") { + expectThat(subject.getStatus(resource.id)).isEqualTo(WAITING) + } + } + + context("too many created and unresolvable events") { + before { + events.clear() + events.add(ResourceCreated(resource)) + repeat (8) { + events.add(ResourceCheckUnresolvable(resource, object : ResourceCurrentlyUnresolvable("") {})) + } + } + + test("returns CURRENTLY_UNRESOLVABLE") { + expectThat(subject.getStatus(resource.id)).isEqualTo(CURRENTLY_UNRESOLVABLE) + } } - test("returns CURRENTLY_UNRESOLVABLE") { - expectThat(subject.getStatus(resource.id)).isEqualTo(CURRENTLY_UNRESOLVABLE) + context("more than created and unresolvable events") { + before { + events.add(ResourceDeltaResolved(resource)) + events.add(ResourceCheckUnresolvable(resource, object : ResourceCurrentlyUnresolvable("") {})) + } + + test("returns CURRENTLY_UNRESOLVABLE") { + expectThat(subject.getStatus(resource.id)).isEqualTo(CURRENTLY_UNRESOLVABLE) + } } }