Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b282038949 | ||
|
|
4de506a2af |
@@ -0,0 +1,10 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import "net/http"
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
_ = http.ListenAndServe(":8088", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
_, _ = w.Write([]byte("lifeboat-ready\n"))
|
||||||
|
}))
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
package commit
|
||||||
|
|
||||||
|
type ExecutorResult string
|
||||||
|
type AmbiguityState string
|
||||||
|
|
||||||
|
const (
|
||||||
|
ExecutorAccepted ExecutorResult = "ACCEPTED"
|
||||||
|
ExecutorReportedSuccess ExecutorResult = "REPORTED_SUCCESS"
|
||||||
|
ExecutorReportedFailure ExecutorResult = "REPORTED_FAILURE"
|
||||||
|
ExecutorNoResponse ExecutorResult = "NO_RESPONSE"
|
||||||
|
ExecutorAmbiguous ExecutorResult = "AMBIGUOUS"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ExecutionReceipt struct {
|
||||||
|
ID string
|
||||||
|
ActionAttemptRef ActionAttemptID
|
||||||
|
ExecutorImplementationRef string
|
||||||
|
ExternalOperationRef string
|
||||||
|
ExternalRequestID string
|
||||||
|
RequestDigest string
|
||||||
|
ResponseDigest string
|
||||||
|
DispatchAtUnixMillis int64
|
||||||
|
CompletedAtUnixMillis *int64
|
||||||
|
ExecutorResult ExecutorResult
|
||||||
|
Ambiguity AmbiguityState
|
||||||
|
ReconciliationKey string
|
||||||
|
RawArtifactRef string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r ExecutionReceipt) Valid() bool {
|
||||||
|
return r.ID != "" && r.ActionAttemptRef != "" && r.ExecutorImplementationRef != "" && r.RequestDigest != "" && r.ExecutorResult != "" && r.ReconciliationKey != "" && r.DispatchAtUnixMillis > 0
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
package epistemics
|
||||||
|
|
||||||
|
type WorldOutcomeState string
|
||||||
|
|
||||||
|
const (
|
||||||
|
OutcomeVerifiedSuccess WorldOutcomeState = "VERIFIED_SUCCESS"
|
||||||
|
OutcomeVerifiedPartial WorldOutcomeState = "VERIFIED_PARTIAL"
|
||||||
|
OutcomeVerifiedFailure WorldOutcomeState = "VERIFIED_FAILURE"
|
||||||
|
OutcomeUnverified WorldOutcomeState = "UNVERIFIED"
|
||||||
|
OutcomeUnknownState WorldOutcomeState = "UNKNOWN"
|
||||||
|
OutcomeConflicted WorldOutcomeState = "CONFLICTED"
|
||||||
|
)
|
||||||
|
|
||||||
|
type WorldOutcomeAssessment struct {
|
||||||
|
ID string
|
||||||
|
PrincipalID string
|
||||||
|
ActionAttemptRef string
|
||||||
|
ExecutionReceiptRefs []string
|
||||||
|
ExpectedEffectRef string
|
||||||
|
ObservationRefs []ObservationID
|
||||||
|
ClaimRefs []ClaimID
|
||||||
|
State WorldOutcomeState
|
||||||
|
ConfidenceMillis int64
|
||||||
|
EvidenceRefs []EvidenceRef
|
||||||
|
AssessedAt int64
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a WorldOutcomeAssessment) Valid() bool {
|
||||||
|
return a.ID != "" && a.PrincipalID != "" && a.ActionAttemptRef != "" && a.State != "" && a.ConfidenceMillis >= 0 && a.ConfidenceMillis <= 1000 && a.AssessedAt > 0
|
||||||
|
}
|
||||||
@@ -1 +1 @@
|
|||||||
{"task_file":"dev/tasks/GEN2-019-add-consequence-risk-assessment-without-artificial-capability-blacklist.json","task_id":"GEN2-019","task_revision":1}
|
{"task_file":"dev/tasks/GEN2-021-add-independent-supervisor-lifeboat-for-release-health-and-rollback.json","task_id":"GEN2-021","task_revision":1}
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
package supervisor
|
||||||
|
|
||||||
|
type ReleaseState string
|
||||||
|
|
||||||
|
const (
|
||||||
|
ReleaseCandidate ReleaseState = "CANDIDATE"
|
||||||
|
ReleaseHealthy ReleaseState = "HEALTHY"
|
||||||
|
ReleaseFailed ReleaseState = "FAILED"
|
||||||
|
ReleaseRolledBack ReleaseState = "ROLLED_BACK"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Release struct {
|
||||||
|
ID string
|
||||||
|
Version string
|
||||||
|
State ReleaseState
|
||||||
|
LastKnownGood bool
|
||||||
|
}
|
||||||
|
type Observation struct {
|
||||||
|
ReleaseID string
|
||||||
|
Ready bool
|
||||||
|
Reason string
|
||||||
|
ObservedAtUnixMillis int64
|
||||||
|
}
|
||||||
|
type Lifeboat struct {
|
||||||
|
Current Release
|
||||||
|
LastKnownGood Release
|
||||||
|
Observations []Observation
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *Lifeboat) Start(candidate Release) bool {
|
||||||
|
if candidate.ID == "" || candidate.Version == "" {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
candidate.State = ReleaseCandidate
|
||||||
|
l.Current = candidate
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
func (l *Lifeboat) Record(o Observation) bool {
|
||||||
|
if o.ReleaseID == "" {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
l.Observations = append(l.Observations, o)
|
||||||
|
if o.ReleaseID != l.Current.ID {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if o.Ready {
|
||||||
|
l.Current.State = ReleaseHealthy
|
||||||
|
l.Current.LastKnownGood = true
|
||||||
|
l.LastKnownGood = l.Current
|
||||||
|
} else {
|
||||||
|
l.Current.State = ReleaseFailed
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
func (l *Lifeboat) Rollback() bool {
|
||||||
|
if l.LastKnownGood.ID == "" {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
l.Current = l.LastKnownGood
|
||||||
|
l.Current.State = ReleaseRolledBack
|
||||||
|
return true
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
package supervisor_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"git.cin.su/m/Assistant/runtime/supervisor"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestLifeboatRollsBackCandidateToLastKnownGood(t *testing.T) {
|
||||||
|
l := supervisor.Lifeboat{}
|
||||||
|
l.Start(supervisor.Release{ID: "good", Version: "1"})
|
||||||
|
l.Record(supervisor.Observation{ReleaseID: "good", Ready: true})
|
||||||
|
l.Start(supervisor.Release{ID: "candidate", Version: "2"})
|
||||||
|
l.Record(supervisor.Observation{ReleaseID: "candidate", Ready: false})
|
||||||
|
if !l.Rollback() || l.Current.ID != "good" || l.Current.State != supervisor.ReleaseRolledBack {
|
||||||
|
t.Fatalf("%#v", l)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
package execution_outcome_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"git.cin.su/m/Assistant/contracts/commit"
|
||||||
|
"git.cin.su/m/Assistant/contracts/epistemics"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestReportedExecutionSuccessIsNotWorldVerification(t *testing.T) {
|
||||||
|
r := commit.ExecutionReceipt{ID: "r", ActionAttemptRef: "a", ExecutorImplementationRef: "impl", RequestDigest: "d", ExecutorResult: commit.ExecutorReportedSuccess, ReconciliationKey: "k", DispatchAtUnixMillis: 1}
|
||||||
|
if !r.Valid() {
|
||||||
|
t.Fatal("receipt invalid")
|
||||||
|
}
|
||||||
|
o := epistemics.WorldOutcomeAssessment{ID: "o", PrincipalID: "p", ActionAttemptRef: "a", State: epistemics.OutcomeUnverified, ConfidenceMillis: 0, AssessedAt: 1}
|
||||||
|
if !o.Valid() {
|
||||||
|
t.Fatal("unverified assessment invalid")
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user