diff --git a/.github/workflows/sleeper.yml b/.github/workflows/sleeper.yml index e02688dc..4f47fc66 100644 --- a/.github/workflows/sleeper.yml +++ b/.github/workflows/sleeper.yml @@ -22,25 +22,22 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - python: [3.8] + python: [3.11] os: [ubuntu-22.04] - node: [10] + node: [16] fail-fast: false steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: setup python environment - uses: actions/setup-python@v2 + uses: actions/setup-python@v5 with: python-version: ${{ matrix.python }} + cache: "pip" + cache-dependency-path: "**/requirements.txt" + - name: install uv + uses: yezz123/setup-uv@v1 - name: show versions run: ./ci/helpers/show_system_versions.bash - - uses: actions/cache@v2 - name: getting cached data - with: - path: ~/.cache/pip - key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }} - restore-keys: | - ${{ runner.os }}-pip- - name: set owner variable run: echo "OWNER=${GITHUB_REPOSITORY%/*}" >> $GITHUB_ENV - name: set docker image tag @@ -74,13 +71,13 @@ jobs: make push-version - name: set up QEMU id: qemu - uses: docker/setup-qemu-action@v1 + uses: docker/setup-qemu-action@v3 with: image: tonistiigi/binfmt:latest platforms: all - name: setup docker buildx id: buildx - uses: docker/setup-buildx-action@v1 + uses: docker/setup-buildx-action@v3 with: version: ${{ matrix.docker_buildx }} driver: docker-container # a must for multi-arch buildsplatform diff --git a/services/sleeper/.cookiecutterrc b/services/sleeper/.cookiecutterrc index cfb75a04..d2060b91 100644 --- a/services/sleeper/.cookiecutterrc +++ b/services/sleeper/.cookiecutterrc @@ -34,4 +34,4 @@ default_context: project_slug: "sleeper" project_type: "computational" release_date: "2020" - version: "2.1.6" + version: "2.2.0" diff --git a/services/sleeper/Makefile b/services/sleeper/Makefile index 836dfa7b..a3b53f6a 100644 --- a/services/sleeper/Makefile +++ b/services/sleeper/Makefile @@ -32,24 +32,22 @@ LOCAL_REGISTRY = ${LOCAL_REGISTRY_HOST}/${COMP_ITIS_PATH} # ENVIRON ---------------------------------- .PHONY: devenv .venv: - python3 -m venv $@ + uv venv $@ # upgrading package managers - $@/bin/pip3 install --upgrade \ + uv pip install --upgrade \ pip \ wheel \ setuptools - # tooling - $@/bin/pip3 install pip-tools requirements.txt: .venv requirements.in # freezes requirements - $/dev/null 2>&1 || - (echo "ERROR: You must mount '${INPUT_FOLDER}' to deduce user and group ids" && exit 1) + (echo "$ERROR" "You must mount '${INPUT_FOLDER}' to deduce user and group ids" && exit 1) stat "${OUTPUT_FOLDER}" >/dev/null 2>&1 || - (echo "ERROR: You must mount '${OUTPUT_FOLDER}' to deduce user and group ids" && exit 1) + (echo "$ERROR" "You must mount '${OUTPUT_FOLDER}' to deduce user and group ids" && exit 1) # NOTE: expects docker run ... -v /path/to/input/folder:${INPUT_FOLDER} # check input/output folders are owned by the same user if [ "$(stat -c %u "${INPUT_FOLDER}")" -ne "$(stat -c %u "${OUTPUT_FOLDER}")" ]; then - echo "ERROR: '${INPUT_FOLDER}' and '${OUTPUT_FOLDER}' have different user id's. not allowed" && exit 1 + echo "$ERROR" "'${INPUT_FOLDER}' and '${OUTPUT_FOLDER}' have different user id's. not allowed" && exit 1 fi # check input/outputfolders are owned by the same group if [ "$(stat -c %g "${INPUT_FOLDER}")" -ne "$(stat -c %g "${OUTPUT_FOLDER}")" ]; then - echo "ERROR: '${INPUT_FOLDER}' and '${OUTPUT_FOLDER}' have different group id's. not allowed" && exit 1 + echo "$ERROR" "'${INPUT_FOLDER}' and '${OUTPUT_FOLDER}' have different group id's. not allowed" && exit 1 fi -echo "setting correct user id/group id..." +echo "$INFO" "setting correct user id/group id..." HOST_USERID=$(stat --format=%u "${INPUT_FOLDER}") HOST_GROUPID=$(stat --format=%g "${INPUT_FOLDER}") CONT_GROUPNAME=$(getent group "${HOST_GROUPID}" | cut --delimiter=: --fields=1) if [ "$HOST_USERID" -eq 0 ]; then - echo "Warning: Folder mounted owned by root user... adding $SC_USER_NAME to root..." + echo "$WARNING" "Folder mounted owned by root user... adding $SC_USER_NAME to root..." adduser "$SC_USER_NAME" root else echo "Folder mounted owned by user $HOST_USERID:$HOST_GROUPID-'$CONT_GROUPNAME'..." # take host's credentials in $SC_USER_NAME if [ -z "$CONT_GROUPNAME" ]; then - echo "Creating new group my$SC_USER_NAME" + echo "$INFO" "Creating new group my$SC_USER_NAME" CONT_GROUPNAME=my$SC_USER_NAME addgroup --gid "$HOST_GROUPID" "$CONT_GROUPNAME" else - echo "group already exists" + echo "$INFO" "group already exists" fi - echo "adding $SC_USER_NAME to group $CONT_GROUPNAME..." + echo "$INFO" "adding $SC_USER_NAME to group $CONT_GROUPNAME..." adduser "$SC_USER_NAME" "$CONT_GROUPNAME" - echo "changing $SC_USER_NAME:$SC_USER_NAME ($SC_USER_ID:$SC_USER_ID) to $SC_USER_NAME:$CONT_GROUPNAME ($HOST_USERID:$HOST_GROUPID)" + echo "$INFO" "changing $SC_USER_NAME:$SC_USER_NAME ($SC_USER_ID:$SC_USER_ID) to $SC_USER_NAME:$CONT_GROUPNAME ($HOST_USERID:$HOST_GROUPID)" usermod --uid "$HOST_USERID" --gid "$HOST_GROUPID" "$SC_USER_NAME" - echo "Changing group properties of files around from $SC_USER_ID to group $CONT_GROUPNAME" + echo "$INFO" "Changing group properties of files around from $SC_USER_ID to group $CONT_GROUPNAME" find / \( -path /proc -o -path /sys \) -prune -o -group "$SC_USER_ID" -exec chgrp --no-dereference "$CONT_GROUPNAME" {} \; # change user property of files already around - echo "Changing ownership properties of files around from $SC_USER_ID to group $CONT_GROUPNAME" + echo "$INFO" "Changing ownership properties of files around from $SC_USER_ID to group $CONT_GROUPNAME" find / \( -path /proc -o -path /sys \) -prune -o -user "$SC_USER_ID" -exec chown --no-dereference "$SC_USER_NAME" {} \; fi -echo "Starting $* ..." -echo " $SC_USER_NAME rights : $(id "$SC_USER_NAME")" -echo " local dir : $(ls -al)" -echo " input dir : $(ls -al "${INPUT_FOLDER}")" -echo " output dir : $(ls -al "${OUTPUT_FOLDER}")" - -# properly activate conda enviornment -# . /opt/conda/etc/profile.d/conda.sh -# conda activate base +echo "$INFO" "Starting $* ..." +echo "$INFO" " $SC_USER_NAME rights : $(id "$SC_USER_NAME")" +echo "$INFO" " local dir : $(ls -al)" +echo "$INFO" " input dir : $(ls -al "${INPUT_FOLDER}")" +echo "$INFO" " output dir : $(ls -al "${OUTPUT_FOLDER}")" -su --command "export PATH=${PATH}:/home/$SC_USER_NAME/service.cli; $*" "$SC_USER_NAME" +exec gosu "$SC_USER_NAME" "$@" diff --git a/services/sleeper/metadata/metadata-gpu.yml b/services/sleeper/metadata/metadata-gpu.yml deleted file mode 100644 index 6e28ba1d..00000000 --- a/services/sleeper/metadata/metadata-gpu.yml +++ /dev/null @@ -1,70 +0,0 @@ -name: sleeper-gpu -key: simcore/services/comp/itis/sleeper-gpu -type: computational -integration-version: 1.0.0 -version: 2.1.4 -description: A service which awaits for time to pass, two times. -contact: neagu@itis.swiss -authors: - - name: "Manuel Guidon" - email: guidon@itis.swiss - affiliation: "IT'IS Foundation" - - name: "Odei Maiz" - email: maiz@itis.swiss - affiliation: "IT'IS Foundation" - - name: "Andrei Neagu" - email: neagu@itis.swiss - affiliation: "IT'IS Foundation" -inputs: - input_1: - displayOrder: 1 - label: File with int number - description: Pick a file containing only one integer - type: "data:text/plain" - fileToKeyMap: - single_number.txt: input_1 - input_2: - displayOrder: 2 - label: Sleep interval - description: Choose an amount of time to sleep in range [0-5] - defaultValue: 2 - type: ref_contentSchema - contentSchema: - title: Sleep interval - type: integer - x_unit: second - minimum: 0 - maximum: 5 - input_3: - displayOrder: 3 - label: Fail after sleep - description: If set to true will cause service to fail after it sleeps - type: boolean - defaultValue: false - input_4: - displayOrder: 4 - label: Distance to bed - description: It will first walk the distance to bed - defaultValue: 0 - type: ref_contentSchema - contentSchema: - title: Distance to bed - type: integer - x_unit: meter -outputs: - output_1: - displayOrder: 1 - label: File containing one random integer - description: Integer is generated in range [1-9] - type: "data:text/plain" - fileToKeyMap: - single_number.txt: output_1 - output_2: - displayOrder: 2 - label: Random sleep interval - description: Interval is generated in range [1-9] - type: ref_contentSchema - contentSchema: - title: Random sleep interval - type: integer - x_unit: second diff --git a/services/sleeper/metadata/metadata-mpi.yml b/services/sleeper/metadata/metadata-mpi.yml deleted file mode 100644 index 34c7bcab..00000000 --- a/services/sleeper/metadata/metadata-mpi.yml +++ /dev/null @@ -1,70 +0,0 @@ -name: sleeper-mpi -key: simcore/services/comp/itis/sleeper-mpi -type: computational -integration-version: 1.0.0 -version: 2.1.4 -description: A service which awaits for time to pass, two times. -contact: neagu@itis.swiss -authors: - - name: "Manuel Guidon" - email: guidon@itis.swiss - affiliation: "IT'IS Foundation" - - name: "Odei Maiz" - email: maiz@itis.swiss - affiliation: "IT'IS Foundation" - - name: "Andrei Neagu" - email: neagu@itis.swiss - affiliation: "IT'IS Foundation" -inputs: - input_1: - displayOrder: 1 - label: File with int number - description: Pick a file containing only one integer - type: "data:text/plain" - fileToKeyMap: - single_number.txt: input_1 - input_2: - displayOrder: 2 - label: Sleep interval - description: Choose an amount of time to sleep in range [0-5] - defaultValue: 2 - type: ref_contentSchema - contentSchema: - title: Sleep interval - type: integer - x_unit: second - minimum: 0 - maximum: 5 - input_3: - displayOrder: 3 - label: Fail after sleep - description: If set to true will cause service to fail after it sleeps - type: boolean - defaultValue: false - input_4: - displayOrder: 4 - label: Distance to bed - description: It will first walk the distance to bed - defaultValue: 0 - type: ref_contentSchema - contentSchema: - title: Distance to bed - type: integer - x_unit: meter -outputs: - output_1: - displayOrder: 1 - label: File containing one random integer - description: Integer is generated in range [1-9] - type: "data:text/plain" - fileToKeyMap: - single_number.txt: output_1 - output_2: - displayOrder: 2 - label: Random sleep interval - description: Interval is generated in range [1-9] - type: ref_contentSchema - contentSchema: - title: Random sleep interval - type: integer - x_unit: second diff --git a/services/sleeper/metadata/metadata.yml b/services/sleeper/metadata/metadata.yml index 0b992928..b6144962 100644 --- a/services/sleeper/metadata/metadata.yml +++ b/services/sleeper/metadata/metadata.yml @@ -1,8 +1,6 @@ -name: sleeper -key: simcore/services/comp/itis/sleeper type: computational integration-version: 1.0.0 -version: 2.1.6 +version: 2.2.0 description: A service which awaits for time to pass, two times. contact: maiz@itis.swiss authors: @@ -15,6 +13,9 @@ authors: - name: "Andrei Neagu" email: neagu@itis.swiss affiliation: "IT'IS Foundation" + - name: "Sylvain Anderegg" + email: anderegg@itis.swiss + affiliation: "IT'IS Foundation" inputs: input_1: displayOrder: 1 @@ -26,7 +27,7 @@ inputs: input_2: displayOrder: 2 label: Sleep interval - description: Choose an amount of time to sleep in range [0-65] + description: Choose an amount of time to sleep in range [0:] defaultValue: 2 type: ref_contentSchema contentSchema: @@ -34,7 +35,6 @@ inputs: type: integer x_unit: second minimum: 0 - maximum: 65 input_3: displayOrder: 3 label: Fail after sleep @@ -51,6 +51,17 @@ inputs: title: Distance to bed type: integer x_unit: meter + input_5: + displayOrder: 5 + label: Dream (or nightmare) of the night + description: Defines the size of the dream that will be generated [0:] + defaultValue: 0 + type: ref_contentSchema + contentSchema: + title: Dream of the night + type: integer + x_unit: bytes + minimum: 0 outputs: output_1: displayOrder: 1 @@ -68,3 +79,10 @@ outputs: title: Random sleep interval type: integer x_unit: second + output_3: + displayOrder: 3 + label: Dream output + description: Contains some random data representing a dream + type: "data:text/plain" + fileToKeyMap: + dream.txt: output_3 diff --git a/services/sleeper/requirements.txt b/services/sleeper/requirements.txt index 6e5647dd..77b15084 100644 --- a/services/sleeper/requirements.txt +++ b/services/sleeper/requirements.txt @@ -1,118 +1,91 @@ -# -# This file is autogenerated by pip-compile with python 3.6 -# To update, run: -# -# pip-compile --output-file=requirements.txt -# -arrow==1.2.2 - # via jinja2-time -attrs==21.4.0 +# This file was autogenerated by uv via the following command: +# uv pip compile --upgrade --build-isolation requirements.in --output-file requirements.txt +arrow==1.3.0 + # via cookiecutter +attrs==23.2.0 # via # jsonschema - # pytest + # referencing binaryornot==0.4.4 # via cookiecutter -certifi==2021.10.8 +certifi==2024.2.2 # via requests -chardet==4.0.0 +chardet==5.2.0 # via binaryornot -charset-normalizer==2.0.12 +charset-normalizer==3.3.2 # via requests -click==8.0.4 +click==8.1.7 # via cookiecutter -cookiecutter==1.7.3 +cookiecutter==2.6.0 # via pytest-cookies -coverage[toml]==6.2 - # via - # -r requirements.in - # pytest-cov -docker==5.0.3 - # via -r requirements.in -idna==3.3 +coverage==7.4.2 + # via pytest-cov +docker==7.0.0 +idna==3.6 # via requests -importlib-metadata==4.8.3 - # via - # click - # jsonschema - # pluggy - # pytest -iniconfig==1.1.1 +iniconfig==2.0.0 # via pytest -jinja2==3.0.3 - # via - # cookiecutter - # jinja2-time -jinja2-time==0.2.0 +jinja2==3.1.3 # via cookiecutter -jsonschema==3.2.0 - # via -r requirements.in -markupsafe==2.0.1 +jsonschema==4.21.1 +jsonschema-specifications==2023.12.1 + # via jsonschema +markdown-it-py==3.0.0 + # via rich +markupsafe==2.1.5 # via jinja2 -packaging==21.3 +mdurl==0.1.2 + # via markdown-it-py +packaging==23.2 # via + # docker # pytest # pytest-sugar -pluggy==1.0.0 - # via pytest -poyo==0.5.0 - # via cookiecutter -py==1.11.0 +pluggy==1.4.0 # via pytest -pyparsing==3.0.8 - # via packaging -pyrsistent==0.18.0 - # via jsonschema -pytest==7.0.1 +pygments==2.17.2 + # via rich +pytest==8.0.1 # via - # -r requirements.in # pytest-cookies # pytest-cov # pytest-instafail # pytest-mock # pytest-sugar -pytest-cookies==0.6.1 - # via -r requirements.in -pytest-cov==3.0.0 - # via -r requirements.in -pytest-instafail==0.4.2 - # via -r requirements.in -pytest-mock==3.6.1 - # via -r requirements.in -pytest-sugar==0.9.4 - # via -r requirements.in +pytest-cookies==0.7.0 +pytest-cov==4.1.0 +pytest-instafail==0.5.0 +pytest-mock==3.12.0 +pytest-sugar==1.0.0 python-dateutil==2.8.2 # via arrow -python-slugify==6.1.1 +python-slugify==8.0.4 + # via cookiecutter +pyyaml==6.0.1 # via cookiecutter -pyyaml==6.0 - # via -r requirements.in -requests==2.27.1 +referencing==0.33.0 + # via + # jsonschema + # jsonschema-specifications +requests==2.31.0 # via # cookiecutter # docker -six==1.16.0 +rich==13.7.0 + # via cookiecutter +rpds-py==0.18.0 # via - # cookiecutter # jsonschema - # python-dateutil -termcolor==1.1.0 + # referencing +six==1.16.0 + # via python-dateutil +termcolor==2.4.0 # via pytest-sugar text-unidecode==1.3 # via python-slugify -tomli==1.2.3 - # via - # coverage - # pytest -typing-extensions==4.1.1 +types-python-dateutil==2.8.19.20240106 + # via arrow +urllib3==2.2.1 # via - # arrow - # importlib-metadata -urllib3==1.26.9 - # via requests -websocket-client==1.3.1 - # via docker -zipp==3.6.0 - # via importlib-metadata - -# The following packages are considered to be unsafe in a requirements file: -# setuptools + # docker + # requests diff --git a/services/sleeper/service.cli/execute.sh b/services/sleeper/service.cli/execute.sh index c4abd3e6..52e50f5a 100755 --- a/services/sleeper/service.cli/execute.sh +++ b/services/sleeper/service.cli/execute.sh @@ -7,11 +7,9 @@ IFS=$(printf '\n\t') cd /home/scu/sleeper echo "starting service as" -echo User : "$(id "$(whoami)")" -echo Workdir : "$(pwd)" +echo "User : $(id "$(whoami)")" +echo "Workdir : $(pwd)" echo "..." echo python3 main.py - - diff --git a/services/sleeper/service.cli/run b/services/sleeper/service.cli/run index ce7e9f7c..de00b0fb 100755 --- a/services/sleeper/service.cli/run +++ b/services/sleeper/service.cli/run @@ -1,4 +1,3 @@ - #!/bin/sh #--------------------------------------------------------------- # AUTO-GENERATED CODE, do not modify this will be overwritten!!! @@ -9,15 +8,16 @@ set -o nounset IFS=$(printf '\n\t') cd "$(dirname "$0")" json_input=$INPUT_FOLDER/inputs.json - + INPUT_1=$INPUT_FOLDER/single_number.txt export INPUT_1 -INPUT_2=$(< "$json_input" jq '.input_2') +INPUT_2=$(jq <"$json_input" '.input_2') export INPUT_2 -INPUT_3=$(< "$json_input" jq '.input_3') +INPUT_3=$(jq <"$json_input" '.input_3') export INPUT_3 -INPUT_4=$(< "$json_input" jq '.input_4') +INPUT_4=$(jq <"$json_input" '.input_4') export INPUT_4 +INPUT_5=$(jq <"$json_input" '.input_5') +export INPUT_5 exec execute.sh - \ No newline at end of file diff --git a/services/sleeper/src/sleeper/main.py b/services/sleeper/src/sleeper/main.py index a82ec7f7..9d9e1495 100644 --- a/services/sleeper/src/sleeper/main.py +++ b/services/sleeper/src/sleeper/main.py @@ -1,6 +1,7 @@ import os import json import random +import string import time import subprocess @@ -24,7 +25,7 @@ def cast_bool(value: str) -> bool: def ensure_sleep_policy(sleep_interval: int) -> int: - """If the sleep interval is negative a value + """If the sleep interval is negative a value in range [1:9] is returned, otherwise the original value""" return sleep_interval if sleep_interval >= 0 else get_random_sleep() @@ -50,16 +51,37 @@ def test_gpu_cuda_code() -> None: # search the history for the CUDA implementation -def walk_to_bed( - amount_to_walk: int = 0 -) -> None: +def walk_to_bed(amount_to_walk: int = 0) -> None: if amount_to_walk > 0: print(f"So tired, I first need to walk {amount_to_walk} meters to bed") - for step in range(2*amount_to_walk): + for step in range(2 * amount_to_walk): print(f"Step {step+1}") time.sleep(0.5) +def generate_random_words(word_length, total_length): + words = [] + while total_length > 0: + word = "".join( + random.choices( + string.ascii_lowercase + string.ascii_uppercase, k=word_length + ) + ) + spacer = " " if total_length > word_length else "" + words.append(word + spacer) + total_length -= word_length + len(spacer) + return "".join(words) + + +def dream(output_folder: Path, dream_size_bytes: int) -> None: + output_3_file = output_folder / "dream.txt" + with output_3_file.open("wb") as fp: + psychedelic_content = generate_random_words(6, dream_size_bytes).encode() + fp.write(psychedelic_content) + fp.truncate(dream_size_bytes) + print(f"What a dream! it was {dream_size_bytes}!! Amazing!") + + def sleep_with_payload( amount_to_sleep: int, target_payload: Optional[Callable] = None ) -> None: @@ -83,8 +105,8 @@ def sleep_with_payload( def main() -> None: """ - Will sleep a random amount between INPUT_1 and INPUT_2 values. If - these are not provided or are negative random values between + Will sleep a random amount between INPUT_1 and INPUT_2 values. If + these are not provided or are negative random values between 1 and 9 will be used. INPUT_3 will cause this script to fail after sleeping. @@ -96,6 +118,7 @@ def main() -> None: sleep_interval = int(get_from_environ("INPUT_2", get_random_sleep())) fail_after_sleep = cast_bool(get_from_environ("INPUT_3", "false")) walk_distance = int(get_from_environ("INPUT_4", 0)) + dream_size_bytes = int(get_from_environ("INPUT_5", 0)) output_folder = Path(get_from_environ("OUTPUT_FOLDER")) # if the service needs to confirm GPU is working enforce_gpu_support = get_from_environ("DOCKER_RESOURCE_VRAM") is not None @@ -120,22 +143,22 @@ def main() -> None: if enforce_mpi_support: sleep_payload_function = test_mpi_code - walk_to_bed( - amount_to_walk=walk_distance - ) + walk_to_bed(amount_to_walk=walk_distance) sleep_with_payload( amount_to_sleep=amount_to_sleep, target_payload=sleep_payload_function ) # writing program outputs - output_3_file = output_folder / "single_number.txt" - output_3_file.write_text(str(get_random_sleep())) + output_1_file = output_folder / "single_number.txt" + output_1_file.write_text(str(get_random_sleep())) output_json_content = {"output_2": get_random_sleep()} output_json = output_folder / "outputs.json" output_json.write_text(json.dumps(output_json_content)) + dream(output_folder, dream_size_bytes) + # Last step should be to fail if fail_after_sleep: raise Exception("Failing after sleep as requested") diff --git a/services/sleeper/tests/integration/test_docker_image.py b/services/sleeper/tests/integration/test_docker_image.py index d65e37d4..110dc6b4 100644 --- a/services/sleeper/tests/integration/test_docker_image.py +++ b/services/sleeper/tests/integration/test_docker_image.py @@ -38,14 +38,6 @@ def _convert_to_simcore_labels(image_labels: Dict) -> Dict: # FIXTURES -@pytest.fixture -def osparc_service_labels_jsonschema(tmp_path) -> Dict: - url = "https://raw.githubusercontent.com/ITISFoundation/osparc-simcore/master/api/specs/common/schemas/node-meta-v0.0.1.json" - file_name = tmp_path / "service_label.json" - _download_url(url, file_name) - with file_name.open() as fp: - json_schema = json.load(fp) - return json_schema @pytest.fixture(scope="session") @@ -64,23 +56,9 @@ def test_docker_io_simcore_labels_against_files( image_labels = docker_image.labels io_simcore_labels = _convert_to_simcore_labels(image_labels) # check files are identical + SKIPPED_KEYS = ["key", "name"] for key, value in io_simcore_labels.items(): + if key in SKIPPED_KEYS: + continue assert key in metadata_labels assert value == metadata_labels[key] - - -def test_validate_docker_io_simcore_labels( - docker_image: docker.models.images.Image, osparc_service_labels_jsonschema: Dict -): - image_labels = docker_image.labels - # get io labels - io_simcore_labels = _convert_to_simcore_labels(image_labels) - # validate schema - try: - jsonschema.validate(io_simcore_labels, osparc_service_labels_jsonschema) - except jsonschema.SchemaError: - pytest.fail( - "Schema {} contains errors".format(osparc_service_labels_jsonschema) - ) - except jsonschema.ValidationError: - pytest.fail("Failed to validate docker image io labels against schema") diff --git a/services/sleeper/tools/update_compose_labels.py b/services/sleeper/tools/update_compose_labels.py index b18b1fc0..5b340199 100644 --- a/services/sleeper/tools/update_compose_labels.py +++ b/services/sleeper/tools/update_compose_labels.py @@ -44,14 +44,16 @@ def stringify_metadata(metadata: Dict) -> Dict[str, str]: def update_compose_labels(compose_cfg: Dict, metadata: Dict[str, str]) -> bool: - compose_labels = compose_cfg["services"]["sleeper"]["build"]["labels"] - changed = False - for key, value in metadata.items(): - if key in compose_labels: - if compose_labels[key] == value: - continue - compose_labels[key] = value - changed = True + for service in compose_cfg["services"]: + + compose_labels = compose_cfg["services"][service]["build"]["labels"] + changed = False + for key, value in metadata.items(): + if key in compose_labels: + if compose_labels[key] == value: + continue + compose_labels[key] = value + changed = True return changed @@ -59,21 +61,34 @@ def main(args=None) -> int: try: parser = argparse.ArgumentParser(description=__doc__) parser.add_argument( - "--compose", help="The compose file where labels shall be updated", type=Path, required=True) - parser.add_argument("--metadata", help="The metadata yaml file", - type=Path, required=False, default="metadata/metadata.yml") + "--compose", + help="The compose file where labels shall be updated", + type=Path, + required=True, + ) + parser.add_argument( + "--metadata", + help="The metadata yaml file", + type=Path, + required=False, + default="metadata/metadata.yml", + ) options = parser.parse_args(args) - log.info("Testing if %s needs updates using labels in %s", - options.compose, options.metadata) + log.info( + "Testing if %s needs updates using labels in %s", + options.compose, + options.metadata, + ) # get available jsons compose_cfg = get_compose_file(options.compose) metadata = get_metadata_file(options.metadata) json_metadata = stringify_metadata(metadata) if update_compose_labels(compose_cfg, json_metadata): - log.info("Updating %s using labels in %s", - options.compose, options.metadata) + log.info( + "Updating %s using labels in %s", options.compose, options.metadata + ) # write the file back - with options.compose.open('w') as fp: + with options.compose.open("w") as fp: yaml.safe_dump(compose_cfg, fp, default_flow_style=False) log.info("Update completed") else: diff --git a/services/sleeper/validation/input/inputs.json b/services/sleeper/validation/input/inputs.json index 9bf5bd0e..017bea44 100644 --- a/services/sleeper/validation/input/inputs.json +++ b/services/sleeper/validation/input/inputs.json @@ -2,5 +2,6 @@ "input_1": "single_number.txt", "input_2": 2, "input_3": false, - "input_4": 4 -} + "input_4": 4, + "input_5": 1024 +} \ No newline at end of file diff --git a/services/sleeper/validation/output/dream.txt b/services/sleeper/validation/output/dream.txt new file mode 100644 index 00000000..8cdb5ee8 Binary files /dev/null and b/services/sleeper/validation/output/dream.txt differ diff --git a/services/sleeper/validation/output/outputs.json b/services/sleeper/validation/output/outputs.json index 8e337fae..3e4d7853 100644 --- a/services/sleeper/validation/output/outputs.json +++ b/services/sleeper/validation/output/outputs.json @@ -1,4 +1,5 @@ { "output_1": "single_number.txt", - "output_2": 2 -} + "output_2": 2, + "output_3": "dream.txt" +} \ No newline at end of file diff --git a/services/sleeper/versioning/service.cfg b/services/sleeper/versioning/service.cfg index 2f999d09..e8bd7a4f 100644 --- a/services/sleeper/versioning/service.cfg +++ b/services/sleeper/versioning/service.cfg @@ -1,5 +1,5 @@ [bumpversion] -current_version = 2.1.6 +current_version = 2.2.0 commit = False message = service/kernel version: {current_version} → {new_version} tag = False