Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

✨ Migrate autoscaling (⚠️ devops) #3566

Merged
merged 155 commits into from
Nov 27, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
155 commits
Select commit Hold shift + click to select a range
78b98f4
deprecated parameters to isort
sanderegg Nov 15, 2022
4e17d81
added asgi-lifespan
sanderegg Nov 15, 2022
4974bb3
initial test
sanderegg Nov 15, 2022
b3cf9cb
define polling interval
sanderegg Nov 15, 2022
856bff6
create background task
sanderegg Nov 15, 2022
ef0e795
refactor
sanderegg Nov 15, 2022
e0e712d
test check that background task restarts
sanderegg Nov 15, 2022
631b1f1
check cancellation
sanderegg Nov 15, 2022
20666fe
rename
sanderegg Nov 15, 2022
1e782ec
initial test
sanderegg Nov 15, 2022
4232834
added docker for testing
sanderegg Nov 15, 2022
36e28e5
adding calls to mimick script
sanderegg Nov 15, 2022
1f87b3c
renaming
sanderegg Nov 15, 2022
6673897
fix check on needed resources
sanderegg Nov 15, 2022
b7ed79b
move fixture up
sanderegg Nov 15, 2022
90a4a4b
add pytest-helpers-namespace
sanderegg Nov 15, 2022
29dbe88
moved helper fct
sanderegg Nov 15, 2022
f90fe57
Revert "add pytest-helpers-namespace"
sanderegg Nov 15, 2022
945d4bb
make the assertion a fixture
sanderegg Nov 15, 2022
a60c3b8
added psutil for testing
sanderegg Nov 15, 2022
2943645
test evaluation of cluster resources
sanderegg Nov 15, 2022
d1d8997
rename
sanderegg Nov 15, 2022
fe678cd
test get labelized node resources
sanderegg Nov 15, 2022
d5d4815
rename
sanderegg Nov 15, 2022
fbb16a2
rename
sanderegg Nov 15, 2022
748dfe1
test compute used resources
sanderegg Nov 15, 2022
567fbbb
fix tests
sanderegg Nov 15, 2022
10f8929
cleanup
sanderegg Nov 15, 2022
4c45862
temp: adding function to get pending resources
sanderegg Nov 15, 2022
13a3b4d
more settings
sanderegg Nov 17, 2022
f494150
added some dedicated error
sanderegg Nov 17, 2022
99cbe9c
refactor
sanderegg Nov 17, 2022
3d622ba
add deepdiff
sanderegg Nov 17, 2022
a43cc90
reworking calls to get info on swarm
sanderegg Nov 17, 2022
bb50fbb
improve
sanderegg Nov 17, 2022
74bc856
pending service tasks method tested
sanderegg Nov 17, 2022
e5395a6
all tests there
sanderegg Nov 17, 2022
c98f735
make the whole faster
sanderegg Nov 17, 2022
5fafdcc
ensure container associated with service is really gone
sanderegg Nov 17, 2022
de4dcbe
typo
sanderegg Nov 17, 2022
8def947
not ready with aws
sanderegg Nov 17, 2022
1eea6f0
added moto
sanderegg Nov 17, 2022
1d81fcc
added boto3 stubs
sanderegg Nov 17, 2022
246feea
added type hints for ec2
sanderegg Nov 17, 2022
7052e92
fix reqs
sanderegg Nov 18, 2022
b4ad67f
adding mock ec2 server
sanderegg Nov 18, 2022
f2836ee
moved model
sanderegg Nov 18, 2022
0ad7470
testing aws utils
sanderegg Nov 18, 2022
8d2d403
renaming
sanderegg Nov 18, 2022
6deb9e5
ensure cpus are positive numbers
sanderegg Nov 18, 2022
918488b
actually non negative
sanderegg Nov 18, 2022
96ad5a8
more tests
sanderegg Nov 18, 2022
be2aed5
test best fitting ec2 instance
sanderegg Nov 18, 2022
b470829
code to launch AWS instances is now there
sanderegg Nov 18, 2022
454651c
set to info
sanderegg Nov 18, 2022
66f3ee6
use default policy
sanderegg Nov 18, 2022
0a197e9
moved fixtures
sanderegg Nov 18, 2022
227ff25
upgrade reqs
sanderegg Nov 18, 2022
5008fae
tests are passing
sanderegg Nov 18, 2022
3159e72
sonarcloud
sanderegg Nov 18, 2022
8d70523
use pydantic models
sanderegg Nov 19, 2022
f30288a
upgrade docker api models
sanderegg Nov 19, 2022
8ad3586
no verify for this file
sanderegg Nov 19, 2022
47ea555
fixed warnings
sanderegg Nov 19, 2022
c703cd1
renamed variables
sanderegg Nov 19, 2022
e3eaad1
mypy
sanderegg Nov 19, 2022
605529a
also typecheck autoscaling
sanderegg Nov 19, 2022
21d8bc1
ask for 1 instance per task
sanderegg Nov 19, 2022
62358fc
added test for getting resources from a docker task
sanderegg Nov 21, 2022
0834383
added docs
sanderegg Nov 21, 2022
4793fc7
cleanup
sanderegg Nov 21, 2022
94a385c
make it start some instances
sanderegg Nov 21, 2022
de59e3b
cleanup
sanderegg Nov 21, 2022
c0cddd7
typo
sanderegg Nov 21, 2022
c426ac8
cleanup
sanderegg Nov 21, 2022
950e7d6
cleaning up
sanderegg Nov 21, 2022
37e74cf
cleanup + use redis alpine
sanderegg Nov 21, 2022
9ef0d49
test creation of instance through moto
sanderegg Nov 21, 2022
6e8d8bf
pass env variables
sanderegg Nov 21, 2022
c0f2fed
cleanup
sanderegg Nov 21, 2022
285212d
properly mock settings
sanderegg Nov 21, 2022
1cccb31
pass tags correctly
sanderegg Nov 21, 2022
ee3bf8a
added placement and resources constraints
sanderegg Nov 21, 2022
c881beb
typing
sanderegg Nov 21, 2022
98615d0
added error when too many instances are started
sanderegg Nov 21, 2022
14c8140
added descriptions and max number of instances
sanderegg Nov 21, 2022
5a9f118
added check when already enough instances are up
sanderegg Nov 21, 2022
86b4d3e
added method to get docker swarm join script
sanderegg Nov 21, 2022
ab20c22
fix moto server not reset between tests
sanderegg Nov 21, 2022
854ea46
check return code
sanderegg Nov 21, 2022
fa05507
add some nicer tags
sanderegg Nov 21, 2022
6c5ebf6
fix check on process code
sanderegg Nov 21, 2022
25fda73
passing the startup script
sanderegg Nov 21, 2022
8158106
re-organizing settings
sanderegg Nov 21, 2022
31b35e1
renamed settings
sanderegg Nov 21, 2022
54d26ec
test cli
sanderegg Nov 21, 2022
03b9fb0
add test for cli/main
sanderegg Nov 21, 2022
3209edc
added httpx
sanderegg Nov 21, 2022
f4687f0
added test for route healthcheck
sanderegg Nov 21, 2022
30698de
allow to disable the autoscaling while doing nothing
sanderegg Nov 21, 2022
5e76ecc
better message
sanderegg Nov 21, 2022
264f7f1
typing
sanderegg Nov 21, 2022
0b8b38d
return the IP addres
sanderegg Nov 22, 2022
91c748b
add some more logs
sanderegg Nov 22, 2022
7624b93
added function to wait for a node and tag a node
sanderegg Nov 22, 2022
0b15e30
added new ENV to tag new nodes
sanderegg Nov 22, 2022
076bc1d
return the new dns
sanderegg Nov 22, 2022
3797a13
auto tag new node
sanderegg Nov 22, 2022
75835e1
fix test when there is no cluster
sanderegg Nov 22, 2022
e536c90
removed useless comments
sanderegg Nov 22, 2022
52ebc03
@GitHK review: add some more info to the doc
sanderegg Nov 22, 2022
dcb433c
@GitHK review: rename
sanderegg Nov 22, 2022
b034754
@GitHK review: simplify
sanderegg Nov 22, 2022
316bd67
@GitHK review: increase the sleep time
sanderegg Nov 22, 2022
f2e39ac
@pcrespov review: rename
sanderegg Nov 22, 2022
cd6e14a
@mrnicegyu11 review: raise AutoscalingConfigurationError if misconfig…
sanderegg Nov 23, 2022
5ae3fac
@mrnicegyu11 review: make docker join call clearer
sanderegg Nov 23, 2022
3c6c6d4
@mrnicegyu11 review: review logs when starting a new instance
sanderegg Nov 23, 2022
8a7f61d
@mrnicegyu11 review: use python version from ENV
sanderegg Nov 23, 2022
d295d4c
@mrnicegyu11 review: improve logs
sanderegg Nov 23, 2022
41babeb
@GitHK review: define what are these 2 variables that were not defined
sanderegg Nov 23, 2022
570c7f1
@mrnicegyu11 review: unbury fixture
sanderegg Nov 23, 2022
8625bb5
@pcrespov and @mrnicegyu11 reviews
sanderegg Nov 23, 2022
41a1b61
@pcrespov review: moved background task to service library
sanderegg Nov 24, 2022
6e8240e
use tenacity for periodic task
sanderegg Nov 24, 2022
c50f71d
added DockerLabelKey type with constrain
sanderegg Nov 24, 2022
8044125
@mrnicegyu11 review: add constraints on allowed docker labels
sanderegg Nov 24, 2022
d170bba
renaming
sanderegg Nov 24, 2022
2e6a698
new node label used now
sanderegg Nov 24, 2022
bc9d7e8
fix name of fct
sanderegg Nov 24, 2022
b2af9a7
refactor
sanderegg Nov 24, 2022
50f02ef
@mrnicegyu11 review: remove unused variable
sanderegg Nov 24, 2022
607b4a3
@mrnicegyu11 review: remove .env, useless
sanderegg Nov 24, 2022
16f7f9a
removed all ENV variables such that developers are happy
sanderegg Nov 24, 2022
19b2e9c
@mrnicegyu11 review: remove comment
sanderegg Nov 24, 2022
1673162
@mrnicegyu11 review: typo in filename
sanderegg Nov 24, 2022
22d35ec
@pcrespov review: use named capture tags
sanderegg Nov 24, 2022
e481ede
clean
sanderegg Nov 24, 2022
91cf3a2
mypy
sanderegg Nov 24, 2022
6392099
typos
sanderegg Nov 24, 2022
365b074
fix the retrial... without exception it does not retry ;)
sanderegg Nov 24, 2022
32637f2
install the docker-cli in the container
sanderegg Nov 24, 2022
097f30a
pylint
sanderegg Nov 25, 2022
a99d1d5
services/autoscaling version: 0.1.1 → 1.0.0
sanderegg Nov 25, 2022
7c09d47
remove alpha
sanderegg Nov 25, 2022
8c61f7f
dockerfile improvements
sanderegg Nov 25, 2022
65dbf3e
make info log to separate from boto3
sanderegg Nov 25, 2022
5b94b90
improving logs
sanderegg Nov 25, 2022
d86497c
logs
sanderegg Nov 25, 2022
788b1e5
use aioboto3 instead of boto3
sanderegg Nov 25, 2022
98e0468
private dns name contains more than I thought
sanderegg Nov 25, 2022
2a00443
deactivate waiting for status ok
sanderegg Nov 25, 2022
4577ddd
no confusing messages
sanderegg Nov 25, 2022
dd3beb3
check the limits as well when getting the task resources.
sanderegg Nov 25, 2022
a99ff1b
application config is info
sanderegg Nov 25, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions .github/workflows/ci-testing-deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -544,7 +544,10 @@ jobs:
run: ./ci/helpers/show_system_versions.bash
- name: install
run: ./ci/github/unit-testing/autoscaling.bash install
- name: typecheck
run: ./ci/github/unit-testing/autoscaling.bash typecheck
- name: test
if: always()
run: ./ci/github/unit-testing/autoscaling.bash test
- uses: codecov/[email protected]
with:
Expand Down Expand Up @@ -1567,7 +1570,7 @@ jobs:
- name: a previous integration-test job failed
if: ${{ contains(join(needs.*.result, ','), 'failure') }}
run: |
echo "::error title=ERROR::one of the unit-tests failed!"
echo "::error title=ERROR::one of the integration-tests failed!"
exit 1
- name: all the previous integration-tests were run successfully or skipped
if: ${{ !contains(join(needs.*.result, ','), 'failure') }}
Expand Down Expand Up @@ -1821,7 +1824,7 @@ jobs:
- name: a previous system-test job failed
if: ${{ contains(join(needs.*.result, ','), 'failure') }}
run: |
echo "::error title=ERROR::one of the unit-tests failed!"
echo "::error title=ERROR::one of the system-tests failed!"
exit 1
- name: all the previous system-tests were run successfully or skipped
if: ${{ !contains(join(needs.*.result, ','), 'failure') }}
Expand Down
6 changes: 4 additions & 2 deletions .vscode/settings.template.json
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,10 @@
"shellcheck.run": "onSave",
"shellcheck.enableQuickFix": true,
"python.formatting.provider": "black",
"python.sortImports.path": "${workspaceFolder}/.venv/bin/isort",
"python.sortImports.args": [
"isort.path": [
"${workspaceFolder}/.venv/bin/isort"
],
"isort.args": [
sanderegg marked this conversation as resolved.
Show resolved Hide resolved
"--settings-path=${workspaceFolder}/.isort.cfg"
]
}
13 changes: 12 additions & 1 deletion packages/models-library/src/models_library/docker.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,18 @@
from pydantic import constr
import re
from typing import Optional

from pydantic import ConstrainedStr, constr

DOCKER_IMAGE_KEY_RE = r"[\w/-]+"
DOCKER_IMAGE_VERSION_RE = r"[\w/.]+"

DockerImageKey = constr(regex=DOCKER_IMAGE_KEY_RE)
DockerImageVersion = constr(regex=DOCKER_IMAGE_VERSION_RE)


class DockerLabelKey(ConstrainedStr):
# NOTE: https://docs.docker.com/config/labels-custom-metadata/#key-format-recommendations
# good practice: use reverse DNS notation
regex: Optional[re.Pattern[str]] = re.compile(
r"^(?!(\.|\-|com.docker\.|io.docker\.|org.dockerproject\.))(?!.*(--|\.\.))[a-z0-9\.-]+$"
)
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# generated by datamodel-codegen:
# filename: https://docs.docker.com/engine/api/v1.41.yaml
# timestamp: 2022-05-12T20:15:58+00:00
# timestamp: 2022-11-19T13:23:51+00:00

from __future__ import annotations

Expand Down Expand Up @@ -577,7 +577,14 @@ class Isolation(Enum):

class ContainerConfig(BaseModel):
"""
Configuration for a container that is portable between hosts.
Configuration for a container that is portable between hosts.

When used as `ContainerConfig` field in an image, `ContainerConfig` is an
optional field containing the configuration of the container that was last
committed when creating the image.

Previous versions of Docker builder used this field to store build cache,
and it is not in active use anymore.

"""

Expand Down Expand Up @@ -783,7 +790,7 @@ class ImageInspect(BaseModel):

Id: Optional[str] = Field(
None,
description="ID is the content-addressable ID of an image.\n\nThis identified is a content-addressable digest calculated from the\nimage's configuration (which includes the digests of layers used by\nthe image).\n\nNote that this digest differs from the `RepoDigests` below, which\nholds digests of image manifests that reference the image.\n",
description="ID is the content-addressable ID of an image.\n\nThis identifier is a content-addressable digest calculated from the\nimage's configuration (which includes the digests of layers used by\nthe image).\n\nNote that this digest differs from the `RepoDigests` below, which\nholds digests of image manifests that reference the image.\n",
example="sha256:ec3f0931a6e6b6855d76b2d7b0be30e81860baccd891b2e243280bf1cd8ad710",
)
RepoTags: Optional[list[str]] = Field(
Expand Down Expand Up @@ -878,16 +885,67 @@ class ImageInspect(BaseModel):


class ImageSummary(BaseModel):
Id: str
ParentId: str
RepoTags: list[str]
RepoDigests: list[str]
Created: int
Size: int
SharedSize: int
VirtualSize: int
Labels: dict[str, str]
Containers: int
Id: str = Field(
...,
description="ID is the content-addressable ID of an image.\n\nThis identifier is a content-addressable digest calculated from the\nimage's configuration (which includes the digests of layers used by\nthe image).\n\nNote that this digest differs from the `RepoDigests` below, which\nholds digests of image manifests that reference the image.\n",
example="sha256:ec3f0931a6e6b6855d76b2d7b0be30e81860baccd891b2e243280bf1cd8ad710",
)
ParentId: str = Field(
...,
description="ID of the parent image.\n\nDepending on how the image was created, this field may be empty and\nis only set for images that were built/created locally. This field\nis empty if the image was pulled from an image registry.\n",
example="",
)
RepoTags: list[str] = Field(
...,
description='List of image names/tags in the local image cache that reference this\nimage.\n\nMultiple image tags can refer to the same imagem and this list may be\nempty if no tags reference the image, in which case the image is\n"untagged", in which case it can still be referenced by its ID.\n',
example=[
"example:1.0",
"example:latest",
"example:stable",
"internal.registry.example.com:5000/example:1.0",
],
)
RepoDigests: list[str] = Field(
...,
description="List of content-addressable digests of locally available image manifests\nthat the image is referenced from. Multiple manifests can refer to the\nsame image.\n\nThese digests are usually only available if the image was either pulled\nfrom a registry, or if the image was pushed to a registry, which is when\nthe manifest is generated and its digest calculated.\n",
example=[
"example@sha256:afcc7f1ac1b49db317a7196c902e61c6c3c4607d63599ee1a82d702d249a0ccb",
"internal.registry.example.com:5000/example@sha256:b69959407d21e8a062e0416bf13405bb2b71ed7a84dde4158ebafacfa06f5578",
],
)
Created: int = Field(
...,
description="Date and time at which the image was created as a Unix timestamp\n(number of seconds sinds EPOCH).\n",
example="1644009612",
)
Size: int = Field(
...,
description="Total size of the image including all layers it is composed of.\n",
example=172064416,
)
SharedSize: int = Field(
...,
description="Total size of image layers that are shared between this image and other\nimages.\n\nThis size is not calculated by default. `-1` indicates that the value\nhas not been set / calculated.\n",
example=1239828,
)
VirtualSize: int = Field(
...,
description="Total size of the image including all layers it is composed of.\n\nIn versions of Docker before v1.10, this field was calculated from\nthe image itself and all of its parent images. Docker v1.10 and up\nstore images self-contained, and no longer use a parent-chain, making\nthis field an equivalent of the Size field.\n\nThis field is kept for backward compatibility, but may be removed in\na future version of the API.\n",
example=172064416,
)
Labels: dict[str, str] = Field(
...,
description="User-defined key/value metadata.",
example={
"com.example.some-label": "some-value",
"com.example.some-other-label": "some-other-value",
},
)
Containers: int = Field(
...,
description="Number of containers using this image. Includes both stopped and running\ncontainers.\n\nThis size is not calculated by default, and depends on which API endpoint\nis used. `-1` indicates that the value has not been set / calculated.\n",
example=2,
)


class AuthConfig(BaseModel):
Expand Down Expand Up @@ -1022,15 +1080,54 @@ class NetworkContainer(BaseModel):
IPv6Address: Optional[str] = None


class Type4(Enum):
"""
Cache record type.

"""

internal = "internal"
frontend = "frontend"
source_local = "source.local"
source_git_checkout = "source.git.checkout"
exec_cachemount = "exec.cachemount"
regular = "regular"


class BuildCache(BaseModel):
ID: Optional[str] = None
Parent: Optional[str] = None
Type: Optional[str] = None
Description: Optional[str] = None
InUse: Optional[bool] = None
Shared: Optional[bool] = None
"""
BuildCache contains information about a build cache record.

"""

ID: Optional[str] = Field(
None,
description="Unique ID of the build cache record.\n",
example="ndlpt0hhvkqcdfkputsk4cq9c",
)
Parent: Optional[str] = Field(
None,
description="ID of the parent build cache record.\n",
example="hw53o5aio51xtltp5xjp8v7fx",
)
Type: Optional[Type4] = Field(
None, description="Cache record type.\n", example="regular"
)
Description: Optional[str] = Field(
None,
description="Description of the build-step that produced the build cache.\n",
example="mount / from exec /bin/sh -c echo 'Binary::apt::APT::Keep-Downloaded-Packages \"true\";' > /etc/apt/apt.conf.d/keep-cache",
)
InUse: Optional[bool] = Field(
None, description="Indicates if the build cache is in use.\n", example=False
)
Shared: Optional[bool] = Field(
None, description="Indicates if the build cache is shared.\n", example=True
)
Size: Optional[int] = Field(
None, description="Amount of disk space used by the build cache (in bytes).\n"
None,
description="Amount of disk space used by the build cache (in bytes).\n",
example=51,
)
CreatedAt: Optional[str] = Field(
None,
Expand All @@ -1042,7 +1139,7 @@ class BuildCache(BaseModel):
description="Date and time at which the build cache was last used in\n[RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) format with nano-seconds.\n",
example="2017-08-09T07:09:37.632105588Z",
)
UsageCount: Optional[int] = None
UsageCount: Optional[int] = Field(None, example=26)


class ImageID(BaseModel):
Expand Down Expand Up @@ -2741,7 +2838,7 @@ class EventActor(BaseModel):
)


class Type4(Enum):
class Type5(Enum):
"""
The type of object emitting the event
"""
Expand Down Expand Up @@ -2776,7 +2873,7 @@ class SystemEventsResponse(BaseModel):

"""

Type: Optional[Type4] = Field(
Type: Optional[Type5] = Field(
None, description="The type of object emitting the event", example="container"
)
Action: Optional[str] = Field(
Expand Down Expand Up @@ -3187,7 +3284,7 @@ class Resources1(BaseModel):
"""

Limits: Optional[Limit] = Field(None, description="Define resources limits.")
Reservation: Optional[ResourceObject] = Field(
Reservations: Optional[ResourceObject] = Field(
None, description="Define resources reservation."
)

Expand Down Expand Up @@ -3409,7 +3506,7 @@ class ContainerWaitResponse(BaseModel):
"""

StatusCode: int = Field(..., description="Exit code of the container")
Error: ContainerWaitExitError
Error: Optional[ContainerWaitExitError] = None


class RegistryServiceConfig(BaseModel):
Expand Down Expand Up @@ -3491,7 +3588,7 @@ class SwarmInfo(BaseModel):
description="IP address at which this node can be reached by other nodes in the\nswarm.\n",
example="10.0.0.46",
)
LocalNodeState: Optional[LocalNodeState] = None
LocalNodeState: Optional[LocalNodeState] = ""
ControlAvailable: Optional[bool] = Field(False, example=True)
Error: Optional[str] = ""
RemoteManagers: Optional[list[PeerNode]] = Field(
Expand Down Expand Up @@ -3929,3 +4026,6 @@ class SystemInfo(BaseModel):
"WARNING: bridge-nf-call-ip6tables is disabled",
],
)


# nopycln: file
37 changes: 37 additions & 0 deletions packages/models-library/tests/test_docker.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# pylint: disable=redefined-outer-name
# pylint: disable=unused-argument
# pylint: disable=unused-variable

import pytest
from models_library.docker import DockerLabelKey
from pydantic import ValidationError, parse_obj_as


@pytest.mark.parametrize(
"label_key, valid",
(
(".com.docker.hello", False),
("_com.docker.hello", False),
("com.docker_man.hello", False),
("io.docker.hello", False),
("org.dockerproject.hello", False),
("com.hey-hey.hello", True),
("com.hey--hey.hello", False),
("com.hey..hey.hello", False),
("com.hey_hey.hello", False),
("node.labels.standard_worker", False),
("Node.labels.standard_worker", False),
("Node.labels.standard_worker", False),
("Node.labels.standardworker", False),
("node.labels.standardworker", True),
("io.osparc.auto-scaler", True),
),
)
def test_docker_label_key(label_key: str, valid: bool):
# NOTE: https://docs.docker.com/config/labels-custom-metadata/#key-format-recommendations
if valid:
instance = parse_obj_as(DockerLabelKey, label_key)
assert instance
else:
with pytest.raises(ValidationError):
parse_obj_as(DockerLabelKey, label_key)
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
#
# monkeypatch using dict
#
def setenvs_from_dict(monkeypatch: MonkeyPatch, envs: EnvVarsDict):
def setenvs_from_dict(monkeypatch: MonkeyPatch, envs: EnvVarsDict) -> EnvVarsDict:
for key, value in envs.items():
assert value is not None # None keys cannot be is defined w/o value
monkeypatch.setenv(key, str(value))
Expand Down
Loading