package runtime // transitionKey stores one `(from, to)` pair in the allowed-transitions // table. type transitionKey struct { from Status to Status } // allowedTransitions stores the set of permitted `(from, to)` status // pairs. The four pairs mirror the lifecycle flows frozen in // `galaxy/rtmanager/README.md §Lifecycles`: // // - running → stopped: graceful stop, observed Docker exit, or // reconcile observing an exited container. // - running → removed: reconcile_dispose when Docker no longer reports // the container at all. // - stopped → running: restart and patch inner start steps. // - stopped → removed: cleanup_container, both the periodic TTL worker // and the admin DELETE endpoint. var allowedTransitions = map[transitionKey]struct{}{ {StatusRunning, StatusStopped}: {}, {StatusRunning, StatusRemoved}: {}, {StatusStopped, StatusRunning}: {}, {StatusStopped, StatusRemoved}: {}, } // AllowedTransitions returns a copy of the `(from, to)` allowed // transitions table used by Transition. The returned map is safe to // mutate; callers should not rely on iteration order. func AllowedTransitions() map[Status][]Status { result := make(map[Status][]Status) for key := range allowedTransitions { result[key.from] = append(result[key.from], key.to) } return result } // Transition reports whether from may transition to next. The function // returns nil when the pair is permitted, and an *InvalidTransitionError // wrapping ErrInvalidTransition otherwise. It does not touch any store // and is safe to call from any layer. func Transition(from Status, next Status) error { if !from.IsKnown() || !next.IsKnown() { return &InvalidTransitionError{From: from, To: next} } if _, ok := allowedTransitions[transitionKey{from: from, to: next}]; !ok { return &InvalidTransitionError{From: from, To: next} } return nil }