momotor.shared.resources
¶
Resources are used to match jobs with workers. A job can request resources, workers provide certain resources. Either job and workers can also explicitly reject certain resources.
The momotor.shared.resources
module contains the code to match requested resources with provided resources.
Currently, resources are boolean tags (ie. a worker can indicate it provides the resource “Python 3”). A future update could make it possible to use resources with numeric values (eg. a worker can indicate it can provide up to 4 GiB of memory for the job)
Resource definition syntax¶
A worker defines the resources it can provide, whereas a job defines the resources it requires. The syntax for both these definitions is the same:
group[":"]item[","item]*
The group
is the name of a group, consisting of a series of alphanumeric ASCII characters, dashes (-
),
underscores (_
), dots (.
) and/or whitespace. Any other character can be escaped with a backslash
character (\
). It is also possible to use a quotes, where both single ('
) and double quotes ("
)
can be used. Within quotes, any character is valid. Quotes can start and end anywhere in
the string, but need to be matched in pairs. Whitespace is normally stripped from the beginning
and end of group names, but using quotes it will be retained.
The following are all valid group names:
name
- Nothing special heredotted.name
- The dot is validspaced name
- Whitespace is also valid as part of the group name"email@example.com"
- The@
is not an allowed character, so the string needs to be quotedemail"@"example.com
- Only quoting the@
email\@example.com
- Escaping the@
backslashed\\name
- The backslash itself also needs to be escaped"trailing whitespace "
- The whitespace at the end is retained
The first character that is not a valid character for a group name ends the group name field, so for example
a colon (:
), a tilde (~
) or a less-than (<
) character all end the group name field.
A group name field is followed by an optional colon (:
) and a list of items. The colon is only needed
if otherwise the transition from the group name field to the item list is indeterminate.
Items are separated by comma’s (,
). At least one item is required. A semi-colon (;
), newline character
or end of string ends the list of items.
The item
is the definition for an item. Items can contain any character except comma’s (,
),
colons (:
), semi-colons (;
), single ('
) and double quotes ("
), and backslashes (\
).
Any of these characters can be escaped using the backslash (\
), or included in quotes.
Just like with group names, whitespace is stripped, but will be retained within quotes.
The following are all valid items:
string
- Nothing special here< 1000
- The<
and space are both valid characters within an itemfive<6
- So this is valid toolist",of,strings"
- We need to quote the string to use comma’s in an item, item value will belist,of,strings
list\,of\,strings
- The comma’s can also be escaped, item value will also belist,of,strings
Multiple groups can be separated by a newline character or a semi-colon (;
)
These are all valid full resource definitions:
lang: python, java
- A group namedlang
, containing two itemspython
andjava
The colon is needed to separate the group name from the items herememory < 1 GiB
- A group namedmemory
, containing one item< 1 GiB
A colon separating the group name from the item is not needed here, but would be allowedversion <3, >=5
- A group namedversion
, containing two items<3
and>=5
test case: "one; two, or more"
- A group namedtest case
, containing one itemone; two, or more
one: 1; two: 2
- Two groups, one namedone
containing the item1
, and one namedtwo
containing the item2
one: 1 two: 2
Identical to
one: 1; two: 2
Tag type resources¶
There are three types of tags:
required tags: defined as a name without prefix:
tag
optional tags: prefixed with a question mark:
?tag
excluded tags: prefixed with a tilde:
~tag
Workers provide tag resource. The worker can indicate tags it requires from the jobs, tags that are optional, and excluded tags that it will not accept.
Jobs require tag resources. The job can indicate tags it requires from the worker, tags that are optional, and excluded tags that it does not want from workers.
Matches have a strength, indicated as a floating point number ranging from negative infinity to positive infinity, making it possible to compare them. The strongest possible match is represented as negative infinity, and the weakest match is positive infinity.
If both the worker and job define the same required tag, this is considered the strongest possible match. If both worker and job define the tag as optional the match is the weakest possible match.
If a tag is excluded by either of the parties, while the other requires or optionally defines the tag, the match is rejected. If both exclude the tag, the tag is ignored.
The following table describes all possible matches:
task \ worker |
- |
|
|
|
- |
||||
|
||||
|
||||
|
-: worker or task does not have this tag defined
blank cell: ignore, no change in match value
NoMatch
: indicates theNoMatch
exception will be raisedany other value: corresponding value for the match.
If every resource tag match is a blank cell in the above table, the final match will be
NEUTRAL
which is weaker than a strong match, but stronger than a weak match.
If multiple tags within the same resource group match, the strongest match is returned.
If multiple resource groups match, the weakest group determines the final value.
Note that the constants are defined the other way around:
WEAKEST
> STRONGEST
.
The reason for these counter intuitive values is the planned handling of value type resources, where a lower valued
match will indicate a better match.
Example: Matching programming languages¶
The worker defines the following tags
language: ?java, ?python
java: ?8, ?11, ?12, ?13
python: ?3.6, ?3.7
This worker indicates it can process Java and Python, and which versions for each
The jobs:
language: java java: 12
This job indicates it wants Java 12. The
language
group matchesSTRONG
, thejava
group matchesNEUTRAL
, so the total match isNEUTRAL
, because the weakest group defines the total match. Since the job does not have apython
requirement, and the worker defines allpython
group tags as optional, this is not considered at all for the match.language: java java: 14
This job indicates it wants Java 14. The
language
group matchesSTRONG
, however, thejava
group produces aNoMatch
language: java java: ?14
This job indicates it would like Java 14. The
language
group match matchesSTRONG
again, thejava
group matchesNEUTRAL
, so the total match isNEUTRAL
againarch: x86
This job does not mention any programming language, it just asks for an
arch
tag ofx86
. The worker does not define aarch
resource at all, so this will be aNoMatch
.arch: ?x86
This job also does not mention any programming language, it just asks for an optional
arch
tag ofx86
. The worker does not define aarch
resource group at all, it does not exclude it either. The final match will beNEUTRAL
arch: ~x86
This job explicitly rejects
arch
ofx86
. However, since our worker does not define anarch
resource, this will also result in aNEUTRAL
match
Value type resources¶
Not implemented yet.
This could be used to match dynamic resources like memory or disk space.
An example of a required values definition would be:
ram >= 1 GiB
- request a worker with at least 1 GiB of free RAM
An example of a provided values definition would be:
ram = 2147483648
- the worker has this amount of available RAM
Class documentation¶
- class momotor.shared.resources.Resources(definition=None)¶
Manage resources for a task and worker.
resource value handling:
boolean items:
tag: required tag
?tag: optional tag
~tag: excluded tag
The following table indicates the match value for boolean tags of given type,
NoMatch
indicates that theNoMatch
exception is raised, any other value indicates that that value is returned.-: worker or task does not have this tag defined
blank cell: ignore, no change in match value
TODO numeric items
- Parameters:
definition (
dict
[str
,ResourceGroup
]) – A dictionary of group names to resource groups
- as_str(*, multiline=False, compact=False)¶
Convert these resources into a string that can be parsed back into a
Resources
object usingfrom_string()
- classmethod from_dict(definition)¶
Factory to create a
Resources
object from a dict of group names to group string definitions- Return type:
Self
- classmethod from_string(value)¶
Factory to create a
Resources
object from one or more strings- Parameters:
value (
str
|Iterable
[str
]) – A string or iterable of strings containing resource definitions including a group name- Return type:
Self
- Returns:
The parsed resources
- Raises:
ValueError
if the string is an invalid resources definition
- get(key)¶
Get the
ResourceGroup
by name- Parameters:
key (
str
) – Group name- Return type:
- Returns:
The resource group matching the group name
- match(worker_resource)¶
Returns the match between these resources and the provided worker’s resources.
- Parameters:
worker_resource (
Resources
) – The worker’s resources- Return type:
- Returns:
match value, the lower the value, the better the match is (ranges from
-inf
to+inf
). If nothing matches, but also nothing is excluded, will returnNEUTRAL
- Raises:
NoMatch
if no match can be made (eg. due to an exclude)
- class momotor.shared.resources.group.ResourceGroup(items=None)¶
A group of
resources
.- classmethod create(value)¶
- Return type:
Self
- match(worker_group)¶
Returns the match between this resource group and the provided worker’s resource group
- classmethod union(*groups)¶
Merge multiple resource groups into a new one
- Return type:
Self
- property items: tuple[ResourceItem]¶
- class momotor.shared.resources.item.ResourceItem(value, required, excluded)¶
-
- compare(worker)¶
. worker task
required
optional
excluded
required
optional
excluded
- classmethod compare_missing(worker)¶
. worker task
required
optional
excluded
-
- class momotor.shared.resources.tag.Tag(value)¶
-
- compare(worker)¶
. worker task
required
optional
excluded
required
optional
excluded
- classmethod compare_missing(worker)¶
. worker task
required
optional
excluded
-
- class momotor.shared.resources.NoMatch¶
Raised when no match is possible
- momotor.shared.resources.const.NEUTRAL = 0.0¶
Match value for tags.
NEUTRAL
indicates there are no matching tags between task and worker.
- momotor.shared.resources.const.STRONG = -1.0¶
Match value for tags.
STRONG
indicates a good match: the task requires this tag, for the worker it is optional
- momotor.shared.resources.const.STRONGEST = -inf¶
Match value for tags.
STRONGEST
indicates the best possible match: both task and worker require this tag
- momotor.shared.resources.const.WEAK = 1.0¶
Match value for tags.
WEAK
indicates a slightly worst match: the worker requires the tag, for the task it is optional
- momotor.shared.resources.const.WEAKEST = inf¶
Match value for tags.
WEAKEST
indicates a worst possible match: for both worker and task the tag is optional