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  =============================================================================