github.com/kaisenlinux/docker.io@v0.0.0-20230510090727-ea55db55fac7/swarmkit/design/tla/Types.tla (about) 1 ------------------------------- MODULE Types ------------------------------- 2 3 EXTENDS Naturals, FiniteSets 4 5 (* A generic operator to get the range of a function (the set of values in a map): *) 6 Range(S) == { S[i] : i \in DOMAIN S } 7 8 (* The set of worker nodes. 9 10 Note: a CONSTANT is an input to the model. The model should work with any set of nodes you provide. 11 12 TODO: should cope with this changing at runtime, and with draining nodes. *) 13 CONSTANT Node 14 15 (* A special value indicating that a task is not yet assigned to a node. 16 17 Note: this TLA+ CHOOSE idiom just says to pick some value that isn't a Node (e.g. `null'). *) 18 unassigned == CHOOSE n : n \notin Node 19 20 (* The type (set) of service IDs (e.g. `Int' or `String'). 21 When model checking, this will be some small set (e.g. {"s1", "s2"}). *) 22 CONSTANT ServiceId 23 24 (* The type of task IDs. *) 25 CONSTANT TaskId 26 27 (* The maximum possible value for `replicas' in ServiceSpec. *) 28 CONSTANT maxReplicas 29 ASSUME maxReplicas \in Nat 30 Slot == 1..maxReplicas \* Possible slot numbers 31 32 (* A special value (e.g. `-1') indicating that we want one replica running on each node: *) 33 global == CHOOSE x : x \notin Nat 34 35 (* The type of a description of a service (a struct/record). 36 This is provided by, and only changed by, the user. *) 37 ServiceSpec == [ 38 (* The replicas field is either a count giving the desired number of replicas, 39 or the special value `global'. *) 40 replicas : 0..maxReplicas \union {global}, 41 remove : BOOLEAN \* The user wants to remove this service 42 ] 43 44 (* The possible states for a task: *) 45 new == "new" 46 pending == "pending" 47 assigned == "assigned" 48 accepted == "accepted" 49 preparing == "preparing" 50 ready == "ready" 51 starting == "starting" 52 running == "running" 53 complete == "complete" 54 shutdown == "shutdown" 55 failed == "failed" 56 rejected == "rejected" 57 remove == "remove" \* Only used as a ``desired state'', not an actual state 58 orphaned == "orphaned" 59 60 (* Every state has a rank. It is only possible for a task to change 61 state to a state with a higher rank (later in this sequence). *) 62 order == << new, pending, assigned, accepted, 63 preparing, ready, starting, 64 running, 65 complete, shutdown, failed, rejected, 66 remove, orphaned >> 67 68 (* Maps a state to its position in `order' (e.g. StateRank(new) = 1): *) 69 StateRank(s) == CHOOSE i \in DOMAIN order : order[i] = s 70 71 (* Convenient notation for comparing states: *) 72 s1 \prec s2 == StateRank(s1) < StateRank(s2) 73 s1 \preceq s2 == StateRank(s1) <= StateRank(s2) 74 75 (* The set of possible states ({new, pending, ...}): *) 76 TaskState == Range(order) \ {remove} 77 78 (* Possibly this doesn't need to be a record, but we might want to add extra fields later. *) 79 TaskStatus == [ 80 state : TaskState 81 ] 82 83 (* The state that SwarmKit wants to the task to be in. *) 84 DesiredState == { ready, running, shutdown, remove } 85 86 (* This has every field mentioned in `task_model.md' except for `spec', which 87 it doesn't seem to use for anything. 88 89 `desired_state' can be any state, although currently we only ever set it to one of 90 {ready, running, shutdown, remove}. *) 91 Task == [ 92 id : TaskId, \* To uniquely identify this task 93 service : ServiceId, \* The service that owns the task 94 status : TaskStatus, \* The current state 95 desired_state : DesiredState, \* The state requested by the orchestrator 96 node : Node \union {unassigned}, \* The node on which the task should be run 97 slot : Slot \union {global} \* A way of tracking related tasks 98 ] 99 100 (* The current state of task `t'. *) 101 State(t) == t.status.state 102 103 (* A task is runnable if it is running or could become running in the future. *) 104 Runnable(t) == State(t) \preceq running 105 106 (* A task's ``virtual slot'' is its actual slot for replicated services, 107 but its node for global ones. *) 108 VSlot(t) == 109 IF t.slot = global THEN t.node ELSE t.slot 110 111 (* In the real SwarmKit, a task's ID is just its taskId field. 112 However, this requires lots of IDs, which is expensive for model checking. 113 So instead, we will identify tasks by their << serviceId, vSlot, taskId >> 114 triple, and only require taskId to be unique within its vslot. *) 115 ModelTaskId == ServiceId \X (Slot \union Node) \X TaskId 116 117 (* A unique identifier for a task, which never changes. *) 118 Id(t) == 119 << t.service, VSlot(t), t.id >> \* A ModelTaskId 120 121 (* The ModelTaskIds of a set of tasks. *) 122 IdSet(S) == { Id(t) : t \in S } 123 124 =============================================================================