diff --git a/README.md b/README.md index 9cc5143..2f00f28 100644 --- a/README.md +++ b/README.md @@ -1 +1,6 @@ -# seldonio-rocks \ No newline at end of file +# seldonio-rocks + +Rocks based on [Seldon](https://github.com/SeldonIO) images. + +> [!NOTE] +> The `main` branch of this repository has been cleaned up to contain Rocks we currently maintain and use in the Charmed Kubeflow bundle. To see the deprecated Rocks previously used for Seldon v1.17, switch to the `track/1.17` branch. \ No newline at end of file diff --git a/mlserver-huggingface/rockcraft.yaml b/mlserver-huggingface/rockcraft.yaml deleted file mode 100644 index 4339d54..0000000 --- a/mlserver-huggingface/rockcraft.yaml +++ /dev/null @@ -1,115 +0,0 @@ -# Based on https://github.com/SeldonIO/MLServer/blob/1.3.5/Dockerfile -name: mlserver-huggingface -summary: An image for Seldon MLServer Huggingface -description: | - This image is used as part of the Charmed Kubeflow product. -version: 1.3.5 -license: Apache-2.0 -base: ubuntu@20.04 -run-user: _daemon_ -services: - mlserver-huggingface: - override: replace - summary: "mlserver-huggingface service" - startup: enabled - # Do not split command in many lines using `\` because this results in - # export: command not found error during container startup - command: bash -c 'export PATH=/opt/conda/bin/:/opt/mlserver/.local/bin:${PATH}:/usr/bin && export PYTHONPATH=/opt/mlserver/.local/lib/python3.8/site-packages/:${PYTHONPATH} && eval $(/opt/conda/bin/conda shell.bash hook 2> /dev/null) && mlserver start ${MLSERVER_MODELS_DIR}' - working-dir: "/opt/mlserver" - environment: - MLSERVER_ENV_TARBALL: "/mnt/models/environment.tar.gz" - MLSERVER_MODELS_DIR: "/mnt/models/" - LD_LIBRARY_PATH: "/usr/local/nvidia/lib64:/opt/conda/lib/python3.8/site-packages/nvidia/cuda_runtime/lib:$LD_LIBRARY_PATH" - TRANSFORMERS_CACHE: "/opt/mlserver/.cache" - NUMBA_CACHE_DIR: "/opt/mlserver/.cache" -platforms: - amd64: - -parts: - mlserver-huggingface: - plugin: nil - source: https://github.com/SeldonIO/MLServer - source-type: git - source-tag: 1.3.5 - build-packages: - - python3-dev - - python3-setuptools - - python3-pip - - python-is-python3 - override-build: | - - mkdir -p ${CRAFT_PART_INSTALL}/opt/mlserver/dist - mkdir -p ${CRAFT_PART_INSTALL}/opt/openapi - ./hack/build-wheels.sh ${CRAFT_PART_INSTALL}/opt/mlserver/dist - - override-stage: | - export ROCK_RUNTIME="huggingface" - export PYTHON_VERSION="3.8.16" - export CONDA_VERSION="22.11.1" - export RUNTIMES="mlserver_${ROCK_RUNTIME}" - export MINIFORGE_VERSION="${CONDA_VERSION}-4" - export MLSERVER_PATH=opt/mlserver - export CONDA_PATH=opt/conda - export PATH=/opt/mlserver/.local/bin:/opt/conda/bin:$PATH - - # Install Conda, Python 3.8 and FFmpeg - curl -L -o ~/miniforge3.sh https://github.com/conda-forge/miniforge/releases/download/${MINIFORGE_VERSION}/Miniforge3-${MINIFORGE_VERSION}-Linux-x86_64.sh - bash ~/miniforge3.sh -b -u -p ${CONDA_PATH} - rm ~/miniforge3.sh - ${CONDA_PATH}/bin/conda install --yes conda=${CONDA_VERSION} python=${PYTHON_VERSION} ffmpeg - ${CONDA_PATH}/bin/conda clean -tipy - mkdir -p etc/profile.d - ln -sf ${CONDA_PATH}/etc/profile.d/conda.sh etc/profile.d/conda.sh - echo ". ${CONDA_PATH}/etc/profile.d/conda.sh" >> ~/.bashrc - echo "PATH=${PATH}" >> ~/.bashrc - ${CONDA_PATH}/bin/conda init bash - echo "conda activate base" >> ~/.bashrc - chgrp -R root opt/conda && chmod -R g+rw opt/conda - - # install required wheels - mkdir -p ${MLSERVER_PATH} - mkdir -p ./wheels - cp -p ${CRAFT_PART_INSTALL}/opt/mlserver/dist/mlserver-*.whl ./wheels - cp -p ${CRAFT_PART_INSTALL}/opt/mlserver/dist/mlserver_${ROCK_RUNTIME}-*.whl ./wheels - # setup pip to be from conda - . ${CONDA_PATH}/etc/profile.d/conda.sh - pip install --prefix ${MLSERVER_PATH}/.local --upgrade pip wheel setuptools - pip install --prefix ${MLSERVER_PATH}/.local $(ls "./wheels/mlserver-"*.whl) - pip install --prefix ${MLSERVER_PATH}/.local $(ls "./wheels/mlserver_${ROCK_RUNTIME}-"*.whl) - # Pin starlette due to https://github.com/canonical/seldonio-rocks/issues/80 - echo starlette==0.22.0 >> ${CRAFT_PART_SRC}/requirements/docker.txt - pip install --prefix ${MLSERVER_PATH}/.local -r ${CRAFT_PART_SRC}/requirements/docker.txt - chown -R root:root ${MLSERVER_PATH} && chmod -R 777 ${MLSERVER_PATH} - - # conda writes shebangs with its path everywhere, and in crafting, that will be, for example: - # #!/root/stage/opt/conda/... - # - # Snip off the /root/stage part - bash -c "grep -R -E '/root/stage' opt/ 2>/dev/null | grep -v Bin | awk '{split(\$0,out,\":\"); print out[1]}' | uniq | xargs -I{} sed -i -e 's/\/root\/stage//' {}" - - # replace first line of mlserver script with reference to installed Conda python - export CONDA_PYTHON="#\!\/opt\/conda\/bin\/python" - sed -i "1s/.*/${CONDA_PYTHON}/" ${MLSERVER_PATH}/.local/bin/mlserver - - # clean wheels - rm -rf ./wheels - - override-prime: | - # copy all artifacts - cp -rp ${CRAFT_STAGE}/opt . - - # copy required files - mkdir -p licenses - cp ${CRAFT_PART_SRC}/licenses/license.txt licenses/ - mkdir -p hack - cp ${CRAFT_PART_SRC}/hack/build-env.sh hack/ - cp ${CRAFT_PART_SRC}/hack/generate_dotenv.py hack/ - cp ${CRAFT_PART_SRC}/hack/activate-env.sh hack/ - - security-team-requirement: - plugin: nil - override-build: | - mkdir -p ${CRAFT_PART_INSTALL}/usr/share/rocks - (echo "# os-release" && cat /etc/os-release && echo "# dpkg-query" && \ - dpkg-query -f '${db:Status-Abbrev},${binary:Package},${Version},${source:Package},${Source:Version}\n' -W) \ - > ${CRAFT_PART_INSTALL}/usr/share/rocks/dpkg.query diff --git a/mlserver-huggingface/tests/test_rock.py b/mlserver-huggingface/tests/test_rock.py deleted file mode 100644 index 2dfebe6..0000000 --- a/mlserver-huggingface/tests/test_rock.py +++ /dev/null @@ -1,45 +0,0 @@ -# Copyright 2022 Canonical Ltd. -# See LICENSE file for licensing details. -# -# - -from pathlib import Path - -import os -import logging -import random -import pytest -import string -import subprocess -import yaml - -from charmed_kubeflow_chisme.rock import CheckRock - -@pytest.fixture() -def rock_test_env(tmpdir): - """Yields a temporary directory and random docker container name, then cleans them up after.""" - container_name = "".join([str(i) for i in random.choices(string.ascii_lowercase, k=8)]) - yield tmpdir, container_name - - try: - subprocess.run(["docker", "rm", container_name]) - except Exception: - pass - # tmpdir fixture we use here should clean up the other files for us - -@pytest.mark.abort_on_fail -def test_rock(rock_test_env): - """Test rock.""" - temp_dir, container_name = rock_test_env - check_rock = CheckRock("rockcraft.yaml") - rock_image = check_rock.get_name() - rock_version = check_rock.get_version() - LOCAL_ROCK_IMAGE = f"{rock_image}:{rock_version}" - - rock_services = check_rock.get_services() - assert rock_services["mlserver-huggingface"] - assert rock_services["mlserver-huggingface"]["startup"] == "enabled" - - # create rock filesystem - subprocess.run(["docker", "run", LOCAL_ROCK_IMAGE, "exec", "ls", "-la", "/opt/mlserver/.local/lib/python3.8/site-packages/mlserver"], check=True) - subprocess.run(["docker", "run", LOCAL_ROCK_IMAGE, "exec", "ls", "-la", "/opt/mlserver/.local/bin/mlserver"], check=True) diff --git a/mlserver-huggingface/tox.ini b/mlserver-huggingface/tox.ini deleted file mode 100644 index 200fcae..0000000 --- a/mlserver-huggingface/tox.ini +++ /dev/null @@ -1,80 +0,0 @@ -# Copyright 2022 Canonical Ltd. -# See LICENSE file for licensing details. -[tox] -skipsdist = True -skip_missing_interpreters = True -envlist = unit, sanity, integration - -[testenv] -setenv = - PYTHONPATH={toxinidir} - PYTHONBREAKPOINT=ipdb.set_trace - CHARM_REPO=https://github.com/canonical/seldon-core-operator.git - CHARM_BRANCH=main - LOCAL_CHARM_DIR=charm_repo - -[testenv:pack] -passenv = * -allowlist_externals = - rockcraft -commands = - rockcraft pack - -[testenv:export-to-docker] -passenv = * -allowlist_externals = - bash - skopeo - yq -commands = - # pack rock and export to docker - bash -c 'NAME=$(yq eval .name rockcraft.yaml) && \ - VERSION=$(yq eval .version rockcraft.yaml) && \ - ARCH=$(yq eval ".platforms | keys | .[0]" rockcraft.yaml) && \ - ROCK="$\{NAME\}_$\{VERSION\}_$\{ARCH\}.rock" && \ - DOCKER_IMAGE=$NAME:$VERSION && \\ - echo "Exporting $ROCK to docker as $DOCKER_IMAGE" && \ - skopeo --insecure-policy copy oci-archive:$ROCK docker-daemon:$DOCKER_IMAGE' - -[testenv:sanity] -passenv = * -deps = - pytest - charmed_kubeflow_chisme -commands = - # run rock tests - pytest -v --tb native --show-capture=all --log-cli-level=INFO {posargs} {toxinidir}/tests - -[testenv:integration] -passenv = * -allowlist_externals = - bash - git - rm - tox - rockcraft - sed -deps = - juju<4.0 - pytest - pytest-operator - ops -commands = - # clone related charm - rm -rf {env:LOCAL_CHARM_DIR} - git clone --branch {env:CHARM_BRANCH} {env:CHARM_REPO} {env:LOCAL_CHARM_DIR} - # replace jinja2 templated value with yq safe placeholder - sed -i "s/namespace: {{ namespace }}/namespace: YQ_SAFE/" {env:LOCAL_CHARM_DIR}/src/templates/configmap.yaml.j2 - # upload rock to docker and microk8s cache, replace charm's container with local rock reference - bash -c 'NAME=$(yq eval .name rockcraft.yaml) && \ - VERSION=$(yq eval .version rockcraft.yaml) && \ - DOCKER_IMAGE=$NAME:$VERSION && \ - docker save $DOCKER_IMAGE > $DOCKER_IMAGE.tar && \ - sudo microk8s ctr image import $DOCKER_IMAGE.tar --digests=true && \ - predictor_servers=$(yq e ".data.predictor_servers" {env:LOCAL_CHARM_DIR}/src/templates/configmap.yaml.j2) && \ - predictor_servers=$(jq --arg jq_name $NAME -r '\''.HUGGINGFACE_SERVER.protocols.v2.image=$jq_name'\'' <<< $predictor_servers) && \ - predictor_servers=$(jq --arg jq_version $VERSION -r '\''.HUGGINGFACE_SERVER.protocols.v2.defaultImageVersion=$jq_version'\'' <<< $predictor_servers) yq e -i ".data.predictor_servers=strenv(predictor_servers)" {env:LOCAL_CHARM_DIR}/src/templates/configmap.yaml.j2' - # replace yq safe placeholder with original value - sed -i "s/namespace: YQ_SAFE/namespace: {{ namespace }}/" {env:LOCAL_CHARM_DIR}/src/templates/configmap.yaml.j2 - # run charm integration test with rock - tox -c {env:LOCAL_CHARM_DIR} -e seldon-servers-integration -- -k huggingface diff --git a/mlserver-mlflow/rockcraft.yaml b/mlserver-mlflow/rockcraft.yaml deleted file mode 100644 index 7b18e93..0000000 --- a/mlserver-mlflow/rockcraft.yaml +++ /dev/null @@ -1,115 +0,0 @@ -# Based on https://github.com/SeldonIO/MLServer/blob/1.3.5/Dockerfile -name: mlserver-mlflow -summary: An image for Seldon MLServer MLflow -description: | - This image is used as part of the Charmed Kubeflow product. -version: 1.3.5 -license: Apache-2.0 -base: ubuntu@20.04 -run-user: _daemon_ -services: - mlserver-mlflow: - override: replace - summary: "mlserver-mlflow service" - startup: enabled - # Do not split command in many lines using `\` because this results in - # export: command not found error during container startup - command: bash -c 'export PATH=/opt/conda/bin/:/opt/mlserver/.local/bin:${PATH}:/usr/bin && export PYTHONPATH=/opt/mlserver/.local/lib/python3.8/site-packages/:${PYTHONPATH} && eval $(/opt/conda/bin/conda shell.bash hook 2> /dev/null) && mlserver start ${MLSERVER_MODELS_DIR}' - working-dir: "/opt/mlserver" - environment: - MLSERVER_ENV_TARBALL: "/mnt/models/environment.tar.gz" - MLSERVER_MODELS_DIR: "/mnt/models" - LD_LIBRARY_PATH: "/usr/local/nvidia/lib64:/opt/conda/lib/python3.8/site-packages/nvidia/cuda_runtime/lib:$LD_LIBRARY_PATH" - TRANSFORMERS_CACHE: "/opt/mlserver/.cache" - NUMBA_CACHE_DIR: "/opt/mlserver/.cache" -platforms: - amd64: - -parts: - mlserver-mlflow: - plugin: nil - source: https://github.com/SeldonIO/MLServer - source-type: git - source-tag: 1.3.5 - build-packages: - - python3-dev - - python3-setuptools - - python3-pip - - python-is-python3 - override-build: | - - mkdir -p ${CRAFT_PART_INSTALL}/opt/mlserver/dist - mkdir -p ${CRAFT_PART_INSTALL}/opt/openapi - ./hack/build-wheels.sh ${CRAFT_PART_INSTALL}/opt/mlserver/dist - - override-stage: | - export ROCK_RUNTIME="mlflow" - export PYTHON_VERSION="3.8.16" - export CONDA_VERSION="22.11.1" - export RUNTIMES="mlserver_${ROCK_RUNTIME}" - export MINIFORGE_VERSION="${CONDA_VERSION}-4" - export MLSERVER_PATH=opt/mlserver - export CONDA_PATH=opt/conda - export PATH=/opt/mlserver/.local/bin:/opt/conda/bin:$PATH - - # Install Conda, Python 3.8 and FFmpeg - curl -L -o ~/miniforge3.sh https://github.com/conda-forge/miniforge/releases/download/${MINIFORGE_VERSION}/Miniforge3-${MINIFORGE_VERSION}-Linux-x86_64.sh - bash ~/miniforge3.sh -b -u -p ${CONDA_PATH} - rm ~/miniforge3.sh - ${CONDA_PATH}/bin/conda install --yes conda=${CONDA_VERSION} python=${PYTHON_VERSION} ffmpeg - ${CONDA_PATH}/bin/conda clean -tipy - mkdir -p etc/profile.d - ln -sf ${CONDA_PATH}/etc/profile.d/conda.sh etc/profile.d/conda.sh - echo ". ${CONDA_PATH}/etc/profile.d/conda.sh" >> ~/.bashrc - echo "PATH=${PATH}" >> ~/.bashrc - ${CONDA_PATH}/bin/conda init bash - echo "conda activate base" >> ~/.bashrc - chgrp -R root opt/conda && chmod -R g+rw opt/conda - - # install required wheels - mkdir -p ${MLSERVER_PATH} - mkdir -p ./wheels - cp -p ${CRAFT_PART_INSTALL}/opt/mlserver/dist/mlserver-*.whl ./wheels - cp -p ${CRAFT_PART_INSTALL}/opt/mlserver/dist/mlserver_${ROCK_RUNTIME}-*.whl ./wheels - # setup pip to be from conda - . ${CONDA_PATH}/etc/profile.d/conda.sh - pip install --prefix ${MLSERVER_PATH}/.local --upgrade pip wheel setuptools - pip install --prefix ${MLSERVER_PATH}/.local $(ls "./wheels/mlserver-"*.whl) - pip install --prefix ${MLSERVER_PATH}/.local $(ls "./wheels/mlserver_${ROCK_RUNTIME}-"*.whl) - # Pin starlette due to https://github.com/canonical/seldonio-rocks/issues/80 - echo starlette==0.22.0 >> ${CRAFT_PART_SRC}/requirements/docker.txt - pip install --prefix ${MLSERVER_PATH}/.local -r ${CRAFT_PART_SRC}/requirements/docker.txt - chown -R root:root ${MLSERVER_PATH} && chmod -R 777 ${MLSERVER_PATH} - - # conda writes shebangs with its path everywhere, and in crafting, that will be, for example: - # #!/root/stage/opt/conda/... - # - # Snip off the /root/stage part - bash -c "grep -R -E '/root/stage' opt/ 2>/dev/null | grep -v Bin | awk '{split(\$0,out,\":\"); print out[1]}' | uniq | xargs -I{} sed -i -e 's/\/root\/stage//' {}" - - # replace first line of mlserver script with reference to installed Conda python - export CONDA_PYTHON="#\!\/opt\/conda\/bin\/python" - sed -i "1s/.*/${CONDA_PYTHON}/" ${MLSERVER_PATH}/.local/bin/mlserver - - # clean wheels - rm -rf ./wheels - - override-prime: | - # copy all artifacts - cp -rp ${CRAFT_STAGE}/opt . - - # copy required files - mkdir -p licenses - cp ${CRAFT_PART_SRC}/licenses/license.txt licenses/ - mkdir -p hack - cp ${CRAFT_PART_SRC}/hack/build-env.sh hack/ - cp ${CRAFT_PART_SRC}/hack/generate_dotenv.py hack/ - cp ${CRAFT_PART_SRC}/hack/activate-env.sh hack/ - - security-team-requirement: - plugin: nil - override-build: | - mkdir -p ${CRAFT_PART_INSTALL}/usr/share/rocks - (echo "# os-release" && cat /etc/os-release && echo "# dpkg-query" && \ - dpkg-query -f '${db:Status-Abbrev},${binary:Package},${Version},${source:Package},${Source:Version}\n' -W) \ - > ${CRAFT_PART_INSTALL}/usr/share/rocks/dpkg.query diff --git a/mlserver-mlflow/tests/test_rock.py b/mlserver-mlflow/tests/test_rock.py deleted file mode 100644 index 6c0a771..0000000 --- a/mlserver-mlflow/tests/test_rock.py +++ /dev/null @@ -1,45 +0,0 @@ -# Copyright 2022 Canonical Ltd. -# See LICENSE file for licensing details. -# -# - -from pathlib import Path - -import os -import logging -import random -import pytest -import string -import subprocess -import yaml - -from charmed_kubeflow_chisme.rock import CheckRock - -@pytest.fixture() -def rock_test_env(tmpdir): - """Yields a temporary directory and random docker container name, then cleans them up after.""" - container_name = "".join([str(i) for i in random.choices(string.ascii_lowercase, k=8)]) - yield tmpdir, container_name - - try: - subprocess.run(["docker", "rm", container_name]) - except Exception: - pass - # tmpdir fixture we use here should clean up the other files for us - -@pytest.mark.abort_on_fail -def test_rock(rock_test_env): - """Test rock.""" - temp_dir, container_name = rock_test_env - check_rock = CheckRock("rockcraft.yaml") - rock_image = check_rock.get_name() - rock_version = check_rock.get_version() - LOCAL_ROCK_IMAGE = f"{rock_image}:{rock_version}" - - rock_services = check_rock.get_services() - assert rock_services["mlserver-mlflow"] - assert rock_services["mlserver-mlflow"]["startup"] == "enabled" - - # create rock filesystem - subprocess.run(["docker", "run", LOCAL_ROCK_IMAGE, "exec", "ls", "-la", "/opt/mlserver/.local/lib/python3.8/site-packages/mlserver"], check=True) - subprocess.run(["docker", "run", LOCAL_ROCK_IMAGE, "exec", "ls", "-la", "/opt/mlserver/.local/bin/mlserver"], check=True) diff --git a/mlserver-mlflow/tox.ini b/mlserver-mlflow/tox.ini deleted file mode 100644 index 27bef46..0000000 --- a/mlserver-mlflow/tox.ini +++ /dev/null @@ -1,79 +0,0 @@ -# Copyright 2022 Canonical Ltd. -# See LICENSE file for licensing details. -[tox] -skipsdist = True -skip_missing_interpreters = True -envlist = unit, sanity, integration - -[testenv] -setenv = - PYTHONPATH={toxinidir} - PYTHONBREAKPOINT=ipdb.set_trace - CHARM_REPO=https://github.com/canonical/seldon-core-operator.git - CHARM_BRANCH=main - LOCAL_CHARM_DIR=charm_repo - -[testenv:pack] -passenv = * -allowlist_externals = - rockcraft -commands = - rockcraft pack - -[testenv:export-to-docker] -passenv = * -allowlist_externals = - bash - skopeo - yq -commands = - # pack rock and export to docker - bash -c 'NAME=$(yq eval .name rockcraft.yaml) && \ - VERSION=$(yq eval .version rockcraft.yaml) && \ - ARCH=$(yq eval ".platforms | keys | .[0]" rockcraft.yaml) && \ - ROCK="$\{NAME\}_$\{VERSION\}_$\{ARCH\}.rock" && \ - DOCKER_IMAGE=$NAME:$VERSION && \\ - echo "Exporting $ROCK to docker as $DOCKER_IMAGE" && \\ - skopeo --insecure-policy copy oci-archive:$ROCK docker-daemon:$DOCKER_IMAGE' - -[testenv:sanity] -passenv = * -deps = - pytest - charmed_kubeflow_chisme -commands = - # run rock tests - pytest -v --tb native --show-capture=all --log-cli-level=INFO {posargs} {toxinidir}/tests - -[testenv:integration] -passenv = * -allowlist_externals = - bash - git - rm - tox - sed -deps = - juju<4.0 - pytest - pytest-operator - ops -commands = - # clone related charm - rm -rf {env:LOCAL_CHARM_DIR} - git clone --branch {env:CHARM_BRANCH} {env:CHARM_REPO} {env:LOCAL_CHARM_DIR} - # replace jinja2 templated value with yq safe placeholder - sed -i "s/namespace: {{ namespace }}/namespace: YQ_SAFE/" {env:LOCAL_CHARM_DIR}/src/templates/configmap.yaml.j2 - # upload rock to docker and microk8s cache, replace charm's container with local rock reference - bash -c 'NAME=$(yq eval .name rockcraft.yaml) && \ - VERSION=$(yq eval .version rockcraft.yaml) && \ - DOCKER_IMAGE=$NAME:$VERSION && \ - docker save $DOCKER_IMAGE > $DOCKER_IMAGE.tar && \ - sudo microk8s ctr image import $DOCKER_IMAGE.tar --digests=true && \ - predictor_servers=$(yq e ".data.predictor_servers" {env:LOCAL_CHARM_DIR}/src/templates/configmap.yaml.j2) && \ - predictor_servers=$(jq --arg jq_name $NAME -r '\''.MLFLOW_SERVER.protocols.v2.image=$jq_name'\'' <<< $predictor_servers) && \ - predictor_servers=$(jq --arg jq_version $VERSION -r '\''.MLFLOW_SERVER.protocols.v2.defaultImageVersion=$jq_version'\'' <<< $predictor_servers) yq e -i ".data.predictor_servers=strenv(predictor_servers)" {env:LOCAL_CHARM_DIR}/src/templates/configmap.yaml.j2' - # replace yq safe placeholder with original value - sed -i "s/namespace: YQ_SAFE/namespace: {{ namespace }}/" {env:LOCAL_CHARM_DIR}/src/templates/configmap.yaml.j2 - # run charm integration test with rock - tox -c {env:LOCAL_CHARM_DIR} -e seldon-servers-integration -- -k mlflowserver-v2 diff --git a/mlserver-sklearn/rockcraft.yaml b/mlserver-sklearn/rockcraft.yaml deleted file mode 100644 index 6738887..0000000 --- a/mlserver-sklearn/rockcraft.yaml +++ /dev/null @@ -1,116 +0,0 @@ -# Based on https://github.com/SeldonIO/MLServer/blob/1.3.5/Dockerfile -name: mlserver-sklearn -summary: An image for Seldon MLServer SKLearn -description: | - This image is used as part of the Charmed Kubeflow product. -version: 1.3.5 -license: Apache-2.0 -base: ubuntu@20.04 -run-user: _daemon_ -services: - mlserver-sklearn: - override: replace - summary: "mlserver-sklearn service" - startup: enabled - # Do not split command in many lines using `\` because this results in - # export: command not found error during container startup - command: bash -c 'export PATH=/opt/conda/bin/:/opt/mlserver/.local/bin:${PATH}:/usr/bin && export PYTHONPATH=/opt/mlserver/.local/lib/python3.8/site-packages/:${PYTHONPATH} && eval $(/opt/conda/bin/conda shell.bash hook 2> /dev/null) && mlserver start ${MLSERVER_MODELS_DIR}' - working-dir: "/opt/mlserver" - environment: - MLSERVER_ENV_TARBALL: "/mnt/models/environment.tar.gz" - MLSERVER_MODELS_DIR: "/mnt/models" - LD_LIBRARY_PATH: "/usr/local/nvidia/lib64:/opt/conda/lib/python3.8/site-packages/nvidia/cuda_runtime/lib:$LD_LIBRARY_PATH" - TRANSFORMERS_CACHE: "/opt/mlserver/.cache" - NUMBA_CACHE_DIR: "/opt/mlserver/.cache" -platforms: - amd64: - -parts: - mlserver-sklearn: - plugin: nil - source: https://github.com/SeldonIO/MLServer - source-type: git - source-tag: 1.3.5 - build-packages: - - python3-dev - - python3-setuptools - - python3-pip - - python-is-python3 - override-build: | - - mkdir -p ${CRAFT_PART_INSTALL}/opt/mlserver/dist - mkdir -p ${CRAFT_PART_INSTALL}/opt/openapi - ./hack/build-wheels.sh ${CRAFT_PART_INSTALL}/opt/mlserver/dist - - override-stage: | - export ROCK_RUNTIME="sklearn" - export PYTHON_VERSION="3.8.16" - export CONDA_VERSION="22.11.1" - export RUNTIMES="mlserver_${ROCK_RUNTIME}" - export MINIFORGE_VERSION="${CONDA_VERSION}-4" - export MLSERVER_PATH=opt/mlserver - export CONDA_PATH=opt/conda - export PATH=/opt/mlserver/.local/bin:/opt/conda/bin:$PATH - - # Install Conda, Python 3.8 and FFmpeg - curl -L -o ~/miniforge3.sh https://github.com/conda-forge/miniforge/releases/download/${MINIFORGE_VERSION}/Miniforge3-${MINIFORGE_VERSION}-Linux-x86_64.sh - bash ~/miniforge3.sh -b -u -p ${CONDA_PATH} - rm ~/miniforge3.sh - ${CONDA_PATH}/bin/conda install --yes conda=${CONDA_VERSION} python=${PYTHON_VERSION} ffmpeg - ${CONDA_PATH}/bin/conda clean -tipy - mkdir -p etc/profile.d - ln -sf ${CONDA_PATH}/etc/profile.d/conda.sh etc/profile.d/conda.sh - echo ". ${CONDA_PATH}/etc/profile.d/conda.sh" >> ~/.bashrc - echo "PATH=${PATH}" >> ~/.bashrc - ${CONDA_PATH}/bin/conda init bash - echo "conda activate base" >> ~/.bashrc - chgrp -R root opt/conda && chmod -R g+rw opt/conda - - # install required wheels - - mkdir -p ${MLSERVER_PATH} - mkdir -p ./wheels - cp -p ${CRAFT_PART_INSTALL}/opt/mlserver/dist/mlserver-*.whl ./wheels - cp -p ${CRAFT_PART_INSTALL}/opt/mlserver/dist/mlserver_${ROCK_RUNTIME}-*.whl ./wheels - # setup pip to be from conda - . ${CONDA_PATH}/etc/profile.d/conda.sh - pip install --prefix ${MLSERVER_PATH}/.local --upgrade pip wheel setuptools - pip install --prefix ${MLSERVER_PATH}/.local $(ls "./wheels/mlserver-"*.whl) - pip install --prefix ${MLSERVER_PATH}/.local $(ls "./wheels/mlserver_${ROCK_RUNTIME}-"*.whl) - # Pin starlette due to https://github.com/canonical/seldonio-rocks/issues/80 - echo starlette==0.22.0 >> ${CRAFT_PART_SRC}/requirements/docker.txt - pip install --prefix ${MLSERVER_PATH}/.local -r ${CRAFT_PART_SRC}/requirements/docker.txt - chown -R root:root ${MLSERVER_PATH} && chmod -R 777 ${MLSERVER_PATH} - - # conda writes shebangs with its path everywhere, and in crafting, that will be, for example: - # #!/root/stage/opt/conda/... - # - # Snip off the /root/stage part - bash -c "grep -R -E '/root/stage' opt/ 2>/dev/null | grep -v Bin | awk '{split(\$0,out,\":\"); print out[1]}' | uniq | xargs -I{} sed -i -e 's/\/root\/stage//' {}" - - # replace first line of mlserver script with reference to installed Conda python - export CONDA_PYTHON="#\!\/opt\/conda\/bin\/python" - sed -i "1s/.*/${CONDA_PYTHON}/" ${MLSERVER_PATH}/.local/bin/mlserver - - # clean wheels - rm -rf ./wheels - - override-prime: | - # copy all artifacts - cp -rp ${CRAFT_STAGE}/opt . - - # copy required files - mkdir -p licenses - cp ${CRAFT_PART_SRC}/licenses/license.txt licenses/ - mkdir -p hack - cp ${CRAFT_PART_SRC}/hack/build-env.sh hack/ - cp ${CRAFT_PART_SRC}/hack/generate_dotenv.py hack/ - cp ${CRAFT_PART_SRC}/hack/activate-env.sh hack/ - - security-team-requirement: - plugin: nil - override-build: | - mkdir -p ${CRAFT_PART_INSTALL}/usr/share/rocks - (echo "# os-release" && cat /etc/os-release && echo "# dpkg-query" && \ - dpkg-query -f '${db:Status-Abbrev},${binary:Package},${Version},${source:Package},${Source:Version}\n' -W) \ - > ${CRAFT_PART_INSTALL}/usr/share/rocks/dpkg.query diff --git a/mlserver-sklearn/tests/test_rock.py b/mlserver-sklearn/tests/test_rock.py deleted file mode 100644 index 2e1f9cd..0000000 --- a/mlserver-sklearn/tests/test_rock.py +++ /dev/null @@ -1,45 +0,0 @@ -# Copyright 2022 Canonical Ltd. -# See LICENSE file for licensing details. -# -# - -from pathlib import Path - -import os -import logging -import random -import pytest -import string -import subprocess -import yaml - -from charmed_kubeflow_chisme.rock import CheckRock - -@pytest.fixture() -def rock_test_env(tmpdir): - """Yields a temporary directory and random docker container name, then cleans them up after.""" - container_name = "".join([str(i) for i in random.choices(string.ascii_lowercase, k=8)]) - yield tmpdir, container_name - - try: - subprocess.run(["docker", "rm", container_name]) - except Exception: - pass - # tmpdir fixture we use here should clean up the other files for us - -@pytest.mark.abort_on_fail -def test_rock(rock_test_env): - """Test rock.""" - temp_dir, container_name = rock_test_env - check_rock = CheckRock("rockcraft.yaml") - rock_image = check_rock.get_name() - rock_version = check_rock.get_version() - LOCAL_ROCK_IMAGE = f"{rock_image}:{rock_version}" - - rock_services = check_rock.get_services() - assert rock_services["mlserver-sklearn"] - assert rock_services["mlserver-sklearn"]["startup"] == "enabled" - - # create rock filesystem - subprocess.run(["docker", "run", LOCAL_ROCK_IMAGE, "exec", "ls", "-la", "/opt/mlserver/.local/lib/python3.8/site-packages/mlserver"], check=True) - subprocess.run(["docker", "run", LOCAL_ROCK_IMAGE, "exec", "ls", "-la", "/opt/mlserver/.local/bin/mlserver"], check=True) diff --git a/mlserver-sklearn/tox.ini b/mlserver-sklearn/tox.ini deleted file mode 100644 index 1db6561..0000000 --- a/mlserver-sklearn/tox.ini +++ /dev/null @@ -1,79 +0,0 @@ -# Copyright 2022 Canonical Ltd. -# See LICENSE file for licensing details. -[tox] -skipsdist = True -skip_missing_interpreters = True -envlist = unit, sanity, integration - -[testenv] -setenv = - PYTHONPATH={toxinidir} - PYTHONBREAKPOINT=ipdb.set_trace - CHARM_REPO=https://github.com/canonical/seldon-core-operator.git - CHARM_BRANCH=main - LOCAL_CHARM_DIR=charm_repo - -[testenv:pack] -passenv = * -allowlist_externals = - rockcraft -commands = - rockcraft pack - -[testenv:export-to-docker] -passenv = * -allowlist_externals = - bash - skopeo - yq -commands = - # pack rock and export to docker - bash -c 'NAME=$(yq eval .name rockcraft.yaml) && \ - VERSION=$(yq eval .version rockcraft.yaml) && \ - ARCH=$(yq eval ".platforms | keys | .[0]" rockcraft.yaml) && \ - ROCK="$\{NAME\}_$\{VERSION\}_$\{ARCH\}.rock" && \ - DOCKER_IMAGE=$NAME:$VERSION && \ - echo "Exporting $ROCK to docker as $DOCKER_IMAGE" && \\ - skopeo --insecure-policy copy oci-archive:$ROCK docker-daemon:$DOCKER_IMAGE' - -[testenv:sanity] -passenv = * -deps = - pytest - charmed_kubeflow_chisme -commands = - # run rock tests - pytest -v --tb native --show-capture=all --log-cli-level=INFO {posargs} {toxinidir}/tests - -[testenv:integration] -passenv = * -allowlist_externals = - bash - git - rm - tox - sed -deps = - juju<4.0 - pytest - pytest-operator - ops -commands = - # clone related charm - rm -rf {env:LOCAL_CHARM_DIR} - git clone --branch {env:CHARM_BRANCH} {env:CHARM_REPO} {env:LOCAL_CHARM_DIR} - # replace jinja2 templated value with yq safe placeholder - sed -i "s/namespace: {{ namespace }}/namespace: YQ_SAFE/" {env:LOCAL_CHARM_DIR}/src/templates/configmap.yaml.j2 - # upload rock to docker and microk8s cache, replace charm's container with local rock reference - bash -c 'NAME=$(yq eval .name rockcraft.yaml) && \ - VERSION=$(yq eval .version rockcraft.yaml) && \ - DOCKER_IMAGE=$NAME:$VERSION && \ - docker save $DOCKER_IMAGE > $DOCKER_IMAGE.tar && \ - sudo microk8s ctr image import $DOCKER_IMAGE.tar --digests=true && \ - predictor_servers=$(yq e ".data.predictor_servers" {env:LOCAL_CHARM_DIR}/src/templates/configmap.yaml.j2) && \ - predictor_servers=$(jq --arg jq_name $NAME -r '\''.SKLEARN_SERVER.protocols.v2.image=$jq_name'\'' <<< $predictor_servers) && \ - predictor_servers=$(jq --arg jq_version $VERSION -r '\''.SKLEARN_SERVER.protocols.v2.defaultImageVersion=$jq_version'\'' <<< $predictor_servers) yq e -i ".data.predictor_servers=strenv(predictor_servers)" {env:LOCAL_CHARM_DIR}/src/templates/configmap.yaml.j2' - # replace yq safe placeholder with original value - sed -i "s/namespace: YQ_SAFE/namespace: {{ namespace }}/" {env:LOCAL_CHARM_DIR}/src/templates/configmap.yaml.j2 - # run charm integration test with rock - tox -c {env:LOCAL_CHARM_DIR} -e seldon-servers-integration -- -k sklearn-v2 diff --git a/mlserver-xgboost/rockcraft.yaml b/mlserver-xgboost/rockcraft.yaml deleted file mode 100644 index 0a7004b..0000000 --- a/mlserver-xgboost/rockcraft.yaml +++ /dev/null @@ -1,115 +0,0 @@ -# Based on https://github.com/SeldonIO/MLServer/blob/1.3.5/Dockerfile -name: mlserver-xgboost -summary: An image for Seldon MLServer XGBoost -description: | - This image is used as part of the Charmed Kubeflow product. -version: 1.3.5 -license: Apache-2.0 -base: ubuntu@20.04 -run-user: _daemon_ -services: - mlserver-xgboost: - override: replace - summary: "mlserver-xgboost service" - startup: enabled - # Do not split command in many lines using `\` because this results in - # export: command not found error during container startup - command: bash -c 'export PATH=/opt/conda/bin/:/opt/mlserver/.local/bin:${PATH}:/usr/bin && export PYTHONPATH=/opt/mlserver/.local/lib/python3.8/site-packages/:${PYTHONPATH} && eval $(/opt/conda/bin/conda shell.bash hook 2> /dev/null) && mlserver start ${MLSERVER_MODELS_DIR}' - working-dir: "/opt/mlserver" - environment: - MLSERVER_ENV_TARBALL: "/mnt/models/environment.tar.gz" - MLSERVER_MODELS_DIR: "/mnt/models" - LD_LIBRARY_PATH: "/usr/local/nvidia/lib64:/opt/conda/lib/python3.8/site-packages/nvidia/cuda_runtime/lib:$LD_LIBRARY_PATH" - TRANSFORMERS_CACHE: "/opt/mlserver/.cache" - NUMBA_CACHE_DIR: "/opt/mlserver/.cache" -platforms: - amd64: - -parts: - mlserver-xgboost: - plugin: nil - source: https://github.com/SeldonIO/MLServer - source-type: git - source-tag: 1.3.5 - build-packages: - - python3-dev - - python3-setuptools - - python3-pip - - python-is-python3 - override-build: | - - mkdir -p ${CRAFT_PART_INSTALL}/opt/mlserver/dist - mkdir -p ${CRAFT_PART_INSTALL}/opt/openapi - ./hack/build-wheels.sh ${CRAFT_PART_INSTALL}/opt/mlserver/dist - - override-stage: | - export ROCK_RUNTIME="xgboost" - export PYTHON_VERSION="3.8.16" - export CONDA_VERSION="22.11.1" - export RUNTIMES="mlserver_${ROCK_RUNTIME}" - export MINIFORGE_VERSION="${CONDA_VERSION}-4" - export MLSERVER_PATH=opt/mlserver - export CONDA_PATH=opt/conda - export PATH=/opt/mlserver/.local/bin:/opt/conda/bin:$PATH - - # Install Conda, Python 3.8 and FFmpeg - curl -L -o ~/miniforge3.sh https://github.com/conda-forge/miniforge/releases/download/${MINIFORGE_VERSION}/Miniforge3-${MINIFORGE_VERSION}-Linux-x86_64.sh - bash ~/miniforge3.sh -b -u -p ${CONDA_PATH} - rm ~/miniforge3.sh - ${CONDA_PATH}/bin/conda install --yes conda=${CONDA_VERSION} python=${PYTHON_VERSION} ffmpeg - ${CONDA_PATH}/bin/conda clean -tipy - mkdir -p etc/profile.d - ln -sf ${CONDA_PATH}/etc/profile.d/conda.sh etc/profile.d/conda.sh - echo ". ${CONDA_PATH}/etc/profile.d/conda.sh" >> ~/.bashrc - echo "PATH=${PATH}" >> ~/.bashrc - ${CONDA_PATH}/bin/conda init bash - echo "conda activate base" >> ~/.bashrc - chgrp -R root opt/conda && chmod -R g+rw opt/conda - - # install required wheels - mkdir -p ${MLSERVER_PATH} - mkdir -p ./wheels - cp -p ${CRAFT_PART_INSTALL}/opt/mlserver/dist/mlserver-*.whl ./wheels - cp -p ${CRAFT_PART_INSTALL}/opt/mlserver/dist/mlserver_${ROCK_RUNTIME}-*.whl ./wheels - # setup pip to be from conda - . ${CONDA_PATH}/etc/profile.d/conda.sh - pip install --prefix ${MLSERVER_PATH}/.local --upgrade pip wheel setuptools - pip install --prefix ${MLSERVER_PATH}/.local $(ls "./wheels/mlserver-"*.whl) - pip install --prefix ${MLSERVER_PATH}/.local $(ls "./wheels/mlserver_${ROCK_RUNTIME}-"*.whl) - # Pin starlette due to https://github.com/canonical/seldonio-rocks/issues/80 - echo starlette==0.22.0 >> ${CRAFT_PART_SRC}/requirements/docker.txt - pip install --prefix ${MLSERVER_PATH}/.local -r ${CRAFT_PART_SRC}/requirements/docker.txt - chown -R root:root ${MLSERVER_PATH} && chmod -R 777 ${MLSERVER_PATH} - - # conda writes shebangs with its path everywhere, and in crafting, that will be, for example: - # #!/root/stage/opt/conda/... - # - # Snip off the /root/stage part - bash -c "grep -R -E '/root/stage' opt/ 2>/dev/null | grep -v Bin | awk '{split(\$0,out,\":\"); print out[1]}' | uniq | xargs -I{} sed -i -e 's/\/root\/stage//' {}" - - # replace first line of mlserver script with reference to installed Conda python - export CONDA_PYTHON="#\!\/opt\/conda\/bin\/python" - sed -i "1s/.*/${CONDA_PYTHON}/" ${MLSERVER_PATH}/.local/bin/mlserver - - # clean wheels - rm -rf ./wheels - - override-prime: | - # copy all artifacts - cp -rp ${CRAFT_STAGE}/opt . - - # copy required files - mkdir -p licenses - cp ${CRAFT_PART_SRC}/licenses/license.txt licenses/ - mkdir -p hack - cp ${CRAFT_PART_SRC}/hack/build-env.sh hack/ - cp ${CRAFT_PART_SRC}/hack/generate_dotenv.py hack/ - cp ${CRAFT_PART_SRC}/hack/activate-env.sh hack/ - - security-team-requirement: - plugin: nil - override-build: | - mkdir -p ${CRAFT_PART_INSTALL}/usr/share/rocks - (echo "# os-release" && cat /etc/os-release && echo "# dpkg-query" && \ - dpkg-query -f '${db:Status-Abbrev},${binary:Package},${Version},${source:Package},${Source:Version}\n' -W) \ - > ${CRAFT_PART_INSTALL}/usr/share/rocks/dpkg.query diff --git a/mlserver-xgboost/tests/test_rock.py b/mlserver-xgboost/tests/test_rock.py deleted file mode 100644 index 391770b..0000000 --- a/mlserver-xgboost/tests/test_rock.py +++ /dev/null @@ -1,45 +0,0 @@ -# Copyright 2022 Canonical Ltd. -# See LICENSE file for licensing details. -# -# - -from pathlib import Path - -import os -import logging -import random -import pytest -import string -import subprocess -import yaml - -from charmed_kubeflow_chisme.rock import CheckRock - -@pytest.fixture() -def rock_test_env(tmpdir): - """Yields a temporary directory and random docker container name, then cleans them up after.""" - container_name = "".join([str(i) for i in random.choices(string.ascii_lowercase, k=8)]) - yield tmpdir, container_name - - try: - subprocess.run(["docker", "rm", container_name]) - except Exception: - pass - # tmpdir fixture we use here should clean up the other files for us - -@pytest.mark.abort_on_fail -def test_rock(rock_test_env): - """Test rock.""" - temp_dir, container_name = rock_test_env - check_rock = CheckRock("rockcraft.yaml") - rock_image = check_rock.get_name() - rock_version = check_rock.get_version() - LOCAL_ROCK_IMAGE = f"{rock_image}:{rock_version}" - - rock_services = check_rock.get_services() - assert rock_services["mlserver-xgboost"] - assert rock_services["mlserver-xgboost"]["startup"] == "enabled" - - # create rock filesystem - subprocess.run(["docker", "run", LOCAL_ROCK_IMAGE, "exec", "ls", "-la", "/opt/mlserver/.local/lib/python3.8/site-packages/mlserver"], check=True) - subprocess.run(["docker", "run", LOCAL_ROCK_IMAGE, "exec", "ls", "-la", "/opt/mlserver/.local/bin/mlserver"], check=True) diff --git a/mlserver-xgboost/tox.ini b/mlserver-xgboost/tox.ini deleted file mode 100644 index 576cd6f..0000000 --- a/mlserver-xgboost/tox.ini +++ /dev/null @@ -1,80 +0,0 @@ -# Copyright 2022 Canonical Ltd. -# See LICENSE file for licensing details. -[tox] -skipsdist = True -skip_missing_interpreters = True -envlist = unit, sanity, integration - -[testenv] -setenv = - PYTHONPATH={toxinidir} - PYTHONBREAKPOINT=ipdb.set_trace - CHARM_REPO=https://github.com/canonical/seldon-core-operator.git - CHARM_BRANCH=main - LOCAL_CHARM_DIR=charm_repo - -[testenv:pack] -passenv = * -allowlist_externals = - rockcraft -commands = - rockcraft pack - -[testenv:export-to-docker] -passenv = * -allowlist_externals = - bash - skopeo - yq -commands = - # pack rock and export to docker - bash -c 'NAME=$(yq eval .name rockcraft.yaml) && \ - VERSION=$(yq eval .version rockcraft.yaml) && \ - ARCH=$(yq eval ".platforms | keys | .[0]" rockcraft.yaml) && \ - ROCK="$\{NAME\}_$\{VERSION\}_$\{ARCH\}.rock" && \ - DOCKER_IMAGE=$NAME:$VERSION && \ - echo "Exporting $ROCK to docker as $DOCKER_IMAGE" && \\ - skopeo --insecure-policy copy oci-archive:$ROCK docker-daemon:$DOCKER_IMAGE' - -[testenv:sanity] -passenv = * -deps = - pytest - charmed_kubeflow_chisme -commands = - # run rock tests - pytest -v --tb native --show-capture=all --log-cli-level=INFO {posargs} {toxinidir}/tests - -[testenv:integration] -passenv = * -allowlist_externals = - bash - git - rm - tox - sed -deps = - juju<4.0 - pytest - pytest-operator - ops -commands = - # clone related charm - rm -rf {env:LOCAL_CHARM_DIR} - git clone --branch {env:CHARM_BRANCH} {env:CHARM_REPO} {env:LOCAL_CHARM_DIR} - # replace jinja2 templated value with yq safe placeholder - sed -i "s/namespace: {{ namespace }}/namespace: YQ_SAFE/" {env:LOCAL_CHARM_DIR}/src/templates/configmap.yaml.j2 - # upload rock to docker and microk8s cache, replace charm's container with local rock reference - bash -c 'NAME=$(yq eval .name rockcraft.yaml) && \ - VERSION=$(yq eval .version rockcraft.yaml) && \ - DOCKER_IMAGE=$NAME:$VERSION && \ - docker save $DOCKER_IMAGE > $DOCKER_IMAGE.tar && \ - sudo microk8s ctr image import $DOCKER_IMAGE.tar --digests=true && \ - predictor_servers=$(yq e ".data.predictor_servers" {env:LOCAL_CHARM_DIR}/src/templates/configmap.yaml.j2) && \ - predictor_servers=$(jq --arg jq_name $NAME -r '\''.XGBOOST_SERVER.protocols.v2.image=$jq_name'\'' <<< $predictor_servers) && \ - predictor_servers=$(jq --arg jq_version $VERSION -r '\''.XGBOOST_SERVER.protocols.v2.defaultImageVersion=$jq_version'\'' <<< $predictor_servers) yq e -i ".data.predictor_servers=strenv(predictor_servers)" {env:LOCAL_CHARM_DIR}/src/templates/configmap.yaml.j2' - # replace yq safe placeholder with original value - sed -i "s/namespace: YQ_SAFE/namespace: {{ namespace }}/" {env:LOCAL_CHARM_DIR}/src/templates/configmap.yaml.j2 - # run charm integration test with rock - tox -c {env:LOCAL_CHARM_DIR} -e seldon-servers-integration -- -k xgboost-v2 - diff --git a/seldon-core-operator/rockcraft.yaml b/seldon-core-operator/rockcraft.yaml deleted file mode 100644 index 07d5a6a..0000000 --- a/seldon-core-operator/rockcraft.yaml +++ /dev/null @@ -1,110 +0,0 @@ -# Based on https://github.com/SeldonIO/seldon-core/blob/v1.17.1/operator/Dockerfile -name: seldon-core-operator -summary: Convert your ML models or language wrappers into microservices -description: | - Seldon core converts your ML models (Tensorflow, Pytorch, H2o, etc.) or - language wrappers (Python, Java, etc.) into production REST/GRPC - microservices. - - Seldon handles scaling to thousands of production machine learning models and - provides advanced machine learning capabilities out of the box including - Advanced Metrics, Request Logging, Explainers, Outlier Detectors, A/B Tests, - Canaries and more. -version: 1.17.1 -license: Apache-2.0 -build-base: ubuntu@22.04 -base: bare -run-user: _daemon_ -services: - seldon-core: - override: replace - summary: "seldon-core service" - startup: enabled - command: "/manager --enable-leader-election --webhook-port 4443" -platforms: - amd64: - -parts: - seldon-core-operator: - plugin: go - source: https://github.com/SeldonIO/seldon-core - source-type: git - source-tag: v1.17.1 - build-snaps: - - go - - kustomize/latest/stable - stage-packages: - - libc6_libs - override-build: | - set -xe - cd $CRAFT_PART_SRC/operator - - # Download go dependencies and build the manager binary - rm -f go.sum - go mod tidy -compat=1.17 - go mod download all - go build -a -o manager main.go - - # Install the manager binary and the licenses file - install -D manager $CRAFT_PART_INSTALL/manager - install -D licenses/license.txt $CRAFT_PART_INSTALL/licenses/license.txt - - # TODO: Validate if we indeed need to do this given that the charm overrides the /tmp dir - # Generate the resources per the upstream OCI image - make generate-resources - - # Install the generated resources into /tmp/operator-resources - res="$CRAFT_PART_INSTALL/tmp/operator-resources/" - install -D generated/v1_service_seldon-webhook-service.yaml "${res}/service.yaml" - install -D generated/v1_configmap_seldon-config.yaml "${res}/configmap.yaml" - install -D \ - generated/admissionregistration.k8s.io_v1_validatingwebhookconfiguration_seldon-validating-webhook-configuration.yaml \ - "${res}/validate.yaml" - install -D \ - generated/apiextensions.k8s.io_v1_customresourcedefinition_seldondeployments.machinelearning.seldon.io.yaml \ - "${res}/crd-v1.yaml" - - mpl-deps: - plugin: nil - after: [seldon-core-operator] - build-packages: - - wget - override-build: | - set -xe - mkdir -p $CRAFT_PART_INSTALL/licenses/mpl_source - cd $CRAFT_PART_INSTALL/licenses/mpl_source - - # Per https://github.com/SeldonIO/seldon-core/blob/5591c42b6a40a44641b848d86f9228f623c64598/operator/Dockerfile - wget -qO armon-consul-api.tar.gz https://github.com/armon/consul-api/archive/master.tar.gz - wget -qO go-sql-driver-mysql.tar.gz https://github.com/go-sql-driver/mysql/archive/master.tar.gz - wget -qO hashicorp-consul.tar.gz https://github.com/hashicorp/consul/archive/main.tar.gz - wget -qO hashicorp-errwrap.tar.gz https://github.com/hashicorp/errwrap/archive/master.tar.gz - wget -qO hashicorp-go-cleanhttp.tar.gz https://github.com/hashicorp/go-cleanhttp/archive/master.tar.gz - wget -qO hashicorp-go-immutable-radix.tar.gz https://github.com/hashicorp/go-immutable-radix/archive/master.tar.gz - wget -qO hashicorp-go-multierror.tar.gz https://github.com/hashicorp/go-multierror/archive/master.tar.gz - wget -qO hashicorp-go-plugin.tar.gz https://github.com/hashicorp/go-plugin/archive/master.tar.gz - wget -qO hashicorp-go-retryablehttp.tar.gz https://github.com/hashicorp/go-retryablehttp/archive/master.tar.gz - wget -qO hashicorp-go-rootcerts.tar.gz https://github.com/hashicorp/go-rootcerts/archive/master.tar.gz - wget -qO hashicorp-go-sockaddr.tar.gz https://github.com/hashicorp/go-sockaddr/archive/master.tar.gz - wget -qO hashicorp-go-uuid.tar.gz https://github.com/hashicorp/go-uuid/archive/master.tar.gz - wget -qO hashicorp-go-version.tar.gz https://github.com/hashicorp/go-version/archive/main.tar.gz - wget -qO hashicorp-golang-lru.tar.gz https://github.com/hashicorp/golang-lru/archive/master.tar.gz - wget -qO hashicorp-hcl.tar.gz https://github.com/hashicorp/hcl/archive/main.tar.gz - wget -qO hashicorp-logutils.tar.gz https://github.com/hashicorp/logutils/archive/master.tar.gz - wget -qO hashicorp-memberlist.tar.gz https://github.com/hashicorp/memberlist/archive/master.tar.gz - wget -qO hashicorp-serf.tar.gz https://github.com/hashicorp/serf/archive/master.tar.gz - wget -qO hashicorp-vault.tar.gz https://github.com/hashicorp/vault/archive/master.tar.gz - wget -qO hashicorp-yamux.tar.gz https://github.com/hashicorp/yamux/archive/master.tar.gz - wget -qO mitchellh-cli.tar.gz https://github.com/mitchellh/cli/archive/master.tar.gz - wget -qO mitchellh-gox.tar.gz https://github.com/mitchellh/gox/archive/master.tar.gz - wget -qO mozilla-tls-observatory.tar.gz https://github.com/mozilla/tls-observatory/archive/master.tar.gz - - security-team-requirement: - plugin: nil - after: [seldon-core-operator, mpl-deps] - override-build: | - # security requirement - # there are no packages installed in `bare` base which is used in this rock - mkdir -p ${CRAFT_PART_INSTALL}/usr/share/rocks - (echo "# os-release" && cat /etc/os-release && echo "# dpkg-query") \ - > ${CRAFT_PART_INSTALL}/usr/share/rocks/dpkg.query diff --git a/seldon-core-operator/tests/test_rock.py b/seldon-core-operator/tests/test_rock.py deleted file mode 100644 index 85c8327..0000000 --- a/seldon-core-operator/tests/test_rock.py +++ /dev/null @@ -1,64 +0,0 @@ -# Copyright 2022 Canonical Ltd. -# See LICENSE file for licensing details. -# -# Checks out charm repository into `charm_repo`. Updated metadata.yaml with reference to locally -# built rock. Executes integration tests. -# - -from pathlib import Path - -import os -import logging -import random -import pytest -import string -import subprocess -import yaml -from charmed_kubeflow_chisme.rock import CheckRock - -@pytest.fixture() -def rock_test_env(tmpdir): - """Yields a temporary directory and random docker container name, then cleans them up after.""" - container_name = "".join([str(i) for i in random.choices(string.ascii_lowercase, k=8)]) - yield tmpdir, container_name - - try: - subprocess.run(["docker", "rm", container_name]) - except Exception: - pass - # tmpdir fixture we use here should clean up the other files for us - -@pytest.mark.abort_on_fail -def test_rock(rock_test_env): - """Test rock.""" - temp_dir, container_name = rock_test_env - check_rock = CheckRock("rockcraft.yaml") - rock_image = check_rock.get_name() - rock_version = check_rock.get_version() - LOCAL_ROCK_IMAGE = f"{rock_image}:{rock_version}" - - # rockfs_tar = temp_dir.join("rockfs.tar") - rockfs_tar = "rockfs.tar" - rockfs_dir = temp_dir.mkdir("rockfs") - - # verify that rock service matches charm service - rock_services = check_rock.get_services() - assert rock_services["seldon-core"] - assert rock_services["seldon-core"]["startup"] == "enabled" - - # create rock filesystem - subprocess.run(["docker", "create", f"--name={container_name}", LOCAL_ROCK_IMAGE]) - subprocess.run(["docker", "export", f"{container_name}", "--output", rockfs_tar], check=True) - subprocess.run(["tar", "xvf", rockfs_tar, "-C", rockfs_dir], check=True) - - # verify that all artifacts are in correct locations - files = os.listdir(f"{rockfs_dir}/") - assert "manager" in files - - files = os.listdir(f"{rockfs_dir}/tmp/operator-resources/") - assert "service.yaml" in files - assert "configmap.yaml" in files - assert "validate.yaml" in files - assert "crd-v1.yaml" in files - - subprocess.run(["rm",rockfs_tar], check=True) diff --git a/seldon-core-operator/tox.ini b/seldon-core-operator/tox.ini deleted file mode 100644 index aea96ca..0000000 --- a/seldon-core-operator/tox.ini +++ /dev/null @@ -1,75 +0,0 @@ -# Copyright 2022 Canonical Ltd. -# See LICENSE file for licensing details. -[tox] -skipsdist = True -skip_missing_interpreters = True -envlist = unit, sanity, integration - -[testenv] -setenv = - PYTHONPATH={toxinidir} - PYTHONBREAKPOINT=ipdb.set_trace - CHARM_REPO=https://github.com/canonical/seldon-core-operator.git - CHARM_BRANCH=main - LOCAL_CHARM_DIR=charm_repo - -[testenv:pack] -passenv = * -allowlist_externals = - rockcraft -commands = - rockcraft pack - -[testenv:export-to-docker] -passenv = * -allowlist_externals = - bash - skopeo - yq -commands = - # pack rock and export to docker - bash -c 'NAME=$(yq eval .name rockcraft.yaml) && \ - VERSION=$(yq eval .version rockcraft.yaml) && \ - ARCH=$(yq eval ".platforms | keys | .[0]" rockcraft.yaml) && \ - ROCK="$\{NAME\}_$\{VERSION\}_$\{ARCH\}.rock" && \ - DOCKER_IMAGE=$NAME:$VERSION && \ - echo "Exporting $ROCK to docker as $DOCKER_IMAGE" && \\ - skopeo --insecure-policy copy oci-archive:$ROCK docker-daemon:$DOCKER_IMAGE' - -[testenv:sanity] -passenv = * -deps = - pytest - git+https://github.com/canonical/charmed-kubeflow-chisme.git@main - # Remove above line and uncomment below once we publish - # https://github.com/canonical/charmed-kubeflow-chisme/pull/81 - # charmed_kubeflow_chisme -commands = - # run rock tests - pytest -v --tb native --show-capture=all --log-cli-level=INFO {posargs} {toxinidir}/tests - -[testenv:integration] -passenv = * -allowlist_externals = - bash - git - rm - tox -deps = - juju<4.0 - pytest - pytest-operator - ops -commands = - # clone related charm - rm -rf {env:LOCAL_CHARM_DIR} - git clone --branch {env:CHARM_BRANCH} {env:CHARM_REPO} {env:LOCAL_CHARM_DIR} - # upload rock to docker and microk8s cache, replace charm's container with local rock reference - bash -c 'NAME=$(yq eval .name rockcraft.yaml) && \ - VERSION=$(yq eval .version rockcraft.yaml) && \ - DOCKER_IMAGE=$NAME:$VERSION && \ - docker save $DOCKER_IMAGE > $DOCKER_IMAGE.tar && \ - sudo microk8s ctr image import $DOCKER_IMAGE.tar && \ - yq e -i ".resources.oci-image.upstream-source=\"$DOCKER_IMAGE\"" {env:LOCAL_CHARM_DIR}/metadata.yaml' - # run charm integration test with rock - tox -c {env:LOCAL_CHARM_DIR} -e charm-integration diff --git a/sklearnserver/rockcraft.yaml b/sklearnserver/rockcraft.yaml deleted file mode 100644 index 31ef779..0000000 --- a/sklearnserver/rockcraft.yaml +++ /dev/null @@ -1,109 +0,0 @@ -# Based on https://github.com/SeldonIO/seldon-core/tree/master/servers/sklearnserver -# Based on https://github.com/SeldonIO/seldon-core/blob/v1.17.1/wrappers/s2i/python/Makefile -# Based on https://github.com/SeldonIO/seldon-core/blob/v1.17.1/wrappers/s2i/python/Dockerfile -# Based on https://github.com/SeldonIO/seldon-core/blob/v1.17.1/wrappers/s2i/python/Dockerfile.conda -name: sklearnserver -summary: An image for Seldon SKLearn Server -description: | - This image is used as part of the Charmed Kubeflow product. The SKLearn Server serves - models which have been stored as pickles. -version: 1.17.1 -license: Apache-2.0 -base: ubuntu@20.04 -run-user: _daemon_ -services: - sklearnserver: - override: replace - summary: "sklearnserver service" - startup: enabled - # Yet again, use a subshell to jam conda into a working state. Can't use bashrc, because it immediately - # exits if PS1 isn't set, so no-go from scripts. - command: bash -c 'export PATH=/opt/conda/bin/:${PATH} && eval $(/opt/conda/bin/conda shell.bash hook 2> /dev/null) && source /opt/conda/etc/profile.d/conda.sh && conda activate && seldon-core-microservice ${MODEL_NAME} --service-type ${SERVICE_TYPE} &> /tmp/log.txt' - working-dir: "/microservice" - environment: - # the following environment variables are taken from: - # https://github.com/SeldonIO/seldon-core/blob/master/servers/sklearnserver/environment - # NOTE: PERSISTENCE is omitted because it is depricated - MODEL_NAME: "SKLearnServer" - SERVICE_TYPE: "MODEL" -platforms: - amd64: - -parts: - sklearnserver: - plugin: nil - source: https://github.com/SeldonIO/seldon-core - source-type: git - source-tag: v1.17.1 - override-stage: | - export CONDA_DOWNLOAD_VERSION="py38_23.3.1-0" - export CONDA_VERSION="23.5.0" - curl -L -o certifi-python-certifi.tar.gz https://github.com/certifi/python-certifi/archive/master.tar.gz - curl -L -o ~/miniconda.sh https://repo.anaconda.com/miniconda/Miniconda3-${CONDA_DOWNLOAD_VERSION}-Linux-x86_64.sh - bash ~/miniconda.sh -b -u -p opt/conda - rm ~/miniconda.sh - # Omit usage of conda-forge channel due to security reasons - # since it is a community-maintained collection of packages. - opt/conda/bin/conda install --yes conda=${CONDA_VERSION} - opt/conda/bin/conda clean -tipy - - mkdir -p etc/profile.d - ln -sf opt/conda/etc/profile.d/conda.sh etc/profile.d/conda.sh - echo ". /opt/conda/etc/profile.d/conda.sh" >> ~/.bashrc - echo "conda activate base" >> ~/.bashrc - chgrp -R root opt/conda && chmod -R g+rw opt/conda - # Skip the TINI part since this is the Entrypoint for the intermediate base image - - # Configure shell to use `conda activate`. `conda init` also requires a restart - # of the shell afterwards. That's why we use a script to run the commands below - bash -c "opt/conda/bin/conda init bash" - - # Use a heredoc to build a temporary script. This will start a new shell session. - # Install requirements in conda environment (also installs seldon-core-microservice) - cat >> ./build.sh < /dev/null) - - conda activate - conda activate base - cd /root/parts/sklearnserver/src/servers/sklearnserver/sklearnserver - # Below version should match the source-tag - sed -i 's/seldon_core/seldon_core == 1.16.0/g' requirements.txt - pip install -r requirements.txt - - mkdir -p ${PWD}/microservice - cp SKLearnServer.py ${PWD}/microservice/ - EOF - - bash ./build.sh - rm build.sh - - # conda writes shebangs with its path everywhere, and in crafting, that will be, for example: - # #!/root/stage/opt/conda/... - # - # Snip off the /root/stage part - bash -c "grep -R -E '/root/stage' opt/ 2>/dev/null | grep -v Bin | awk '{split(\$0,out,\":\"); print out[1]}' | uniq | xargs -I{} sed -i -e 's/\/root\/stage//' {}" - override-prime: | - cp -rp ${CRAFT_STAGE}/opt opt/ - - # seldon-core-microservice is a trivial wrapper which looks for .py|.exe files in pwd - # and blindly executes them, as they should inherit. It doesn't need to be in /microservice, - # but it does need to match pebble's workdir - install -D -m 755 ${CRAFT_STAGE}/microservice/SKLearnServer.py microservice/SKLearnServer.py - # We do not install seldon-core-microservice using `pip install .` like upstream - # since we use the one installed in Conda environment during pip install -r requirements.txt - - security-team-requirement: - plugin: nil - after: [sklearnserver] - override-build: | - # security requirement - # there are no packages installed in `bare` base which is used in this rock - # `--root` option is not available in dpkg-query version which is packaged with 20.04 - mkdir -p ${CRAFT_PART_INSTALL}/usr/share/rocks - (echo "# os-release" && cat /etc/os-release && echo "# dpkg-query") \ - > ${CRAFT_PART_INSTALL}/usr/share/rocks/dpkg.query diff --git a/sklearnserver/tests/test_rock.py b/sklearnserver/tests/test_rock.py deleted file mode 100644 index b1a5a88..0000000 --- a/sklearnserver/tests/test_rock.py +++ /dev/null @@ -1,42 +0,0 @@ -# Copyright 2022 Canonical Ltd. -# See LICENSE file for licensing details. -# -# Tests for required artifacts to be present in the rock image. -# - -from charmed_kubeflow_chisme.rock import CheckRock -from pathlib import Path - -import os -import logging -import random -import pytest -import string -import subprocess -import yaml - -@pytest.fixture() -def rock_test_env(tmpdir): - """Yields a temporary directory and random docker container name, then cleans them up after.""" - container_name = "".join([str(i) for i in random.choices(string.ascii_lowercase, k=8)]) - yield tmpdir, container_name - - try: - subprocess.run(["docker", "rm", container_name]) - except Exception: - pass - -@pytest.mark.abort_on_fail -def test_rock(rock_test_env): - """Test rock.""" - temp_dir, container_name = rock_test_env - check_rock = CheckRock("rockcraft.yaml") - rock_image = check_rock.get_name() - rock_version = check_rock.get_version() - LOCAL_ROCK_IMAGE = f"{rock_image}:{rock_version}" - - # verify that all artifacts are in correct locations - subprocess.run(["docker", "run", LOCAL_ROCK_IMAGE, "exec", "ls", "-la", "/microservice/SKLearnServer.py"], check=True) - - # verify that rockcraft.yaml contains correct image name for PREDICTIVE_UNIT_IMAGE environment variable - #assert CheckRock.get_environment()["PREDICTIVE_UNIT_IMAGE"].contains(LOCAL_ROCK_IMAGE) diff --git a/sklearnserver/tox.ini b/sklearnserver/tox.ini deleted file mode 100644 index d25d3dd..0000000 --- a/sklearnserver/tox.ini +++ /dev/null @@ -1,83 +0,0 @@ -# Copyright 2022 Canonical Ltd. -# See LICENSE file for licensing details. -[tox] -skipsdist = True -skip_missing_interpreters = True -envlist = unit, sanity, integration - -[testenv] -setenv = - PYTHONPATH={toxinidir} - PYTHONBREAKPOINT=ipdb.set_trace - CHARM_REPO=https://github.com/canonical/seldon-core-operator.git - CHARM_BRANCH=main - LOCAL_CHARM_DIR=charm_repo - -[testenv:pack] -passenv = * -allowlist_externals = - rockcraft -commands = - rockcraft pack - -[testenv:export-to-docker] -passenv = * -allowlist_externals = - bash - skopeo - yq -commands = - # pack rock and export to docker - bash -c 'NAME=$(yq eval .name rockcraft.yaml) && \ - VERSION=$(yq eval .version rockcraft.yaml) && \ - ARCH=$(yq eval ".platforms | keys | .[0]" rockcraft.yaml) && \ - ROCK="$\{NAME\}_$\{VERSION\}_$\{ARCH\}.rock" && \ - DOCKER_IMAGE=$NAME:$VERSION && \ - echo "Exporting $ROCK to docker as $DOCKER_IMAGE" && \\ - skopeo --insecure-policy copy oci-archive:$ROCK docker-daemon:$DOCKER_IMAGE' - -[testenv:sanity] -passenv = * -deps = - pytest - git+https://github.com/canonical/charmed-kubeflow-chisme.git@main - # Remove above line and uncomment below once we publish - # https://github.com/canonical/charmed-kubeflow-chisme/pull/81 - # charmed_kubeflow_chisme -commands = - # run rock tests - pytest -v --tb native --show-capture=all --log-cli-level=INFO {posargs} {toxinidir}/tests - -[testenv:integration] -passenv = * -allowlist_externals = - bash - git - rm - tox - sed -deps = - juju<4.0 - pytest - pytest-operator - ops -commands = - # clone related charm - rm -rf {env:LOCAL_CHARM_DIR} - git clone --branch {env:CHARM_BRANCH} {env:CHARM_REPO} {env:LOCAL_CHARM_DIR} - # replace jinja2 templated value with yq safe placeholder - sed -i "s/namespace: {{ namespace }}/namespace: YQ_SAFE/" {env:LOCAL_CHARM_DIR}/src/templates/configmap.yaml.j2 - # upload rock to docker and microk8s cache, replace charm's container with local rock reference - bash -c 'NAME=$(yq eval .name rockcraft.yaml) && \ - VERSION=$(yq eval .version rockcraft.yaml) && \ - DOCKER_IMAGE=$NAME:$VERSION && \ - docker save $DOCKER_IMAGE > $DOCKER_IMAGE.tar && \ - sudo microk8s ctr image import $DOCKER_IMAGE.tar && \ - - predictor_servers=$(yq e ".data.predictor_servers" {env:LOCAL_CHARM_DIR}/src/templates/configmap.yaml.j2) && \ - predictor_servers=$(jq --arg jq_name $NAME -r '\''.SKLEARN_SERVER.protocols.seldon.image=$jq_name'\'' <<< $predictor_servers) && \ - predictor_servers=$(jq --arg jq_version $VERSION -r '\''.SKLEARN_SERVER.protocols.seldon.defaultImageVersion=$jq_version'\'' <<< $predictor_servers) yq e -i ".data.predictor_servers=strenv(predictor_servers)" {env:LOCAL_CHARM_DIR}/src/templates/configmap.yaml.j2' - # replace yq safe placeholder with original value - sed -i "s/namespace: YQ_SAFE/namespace: {{ namespace }}/" {env:LOCAL_CHARM_DIR}/src/templates/configmap.yaml.j2 - # run charm integration test with rock - tox -c {env:LOCAL_CHARM_DIR} -e seldon-servers-integration -- -k sklearn-v1 diff --git a/tensorflow-serving/rockcraft.yaml b/tensorflow-serving/rockcraft.yaml deleted file mode 100644 index d0f83b7..0000000 --- a/tensorflow-serving/rockcraft.yaml +++ /dev/null @@ -1,120 +0,0 @@ -# https://github.com/tensorflow/serving/blob/2.1.0/tensorflow_serving/tools/docker/Dockerfile -# Upstream uses 2.1.0 but we bumped the version until the rock could be built -# https://github.com/SeldonIO/seldon-core/blob/v1.17.1/operator/config/manager/configmap.yaml#L23-L24 -# See https://github.com/canonical/seldonio-rocks/issues/37#issuecomment-1716074625 -name: tensorflow-serving -summary: An image for Seldon Tensorflow Serving -description: | - This image is used as part of the Charmed Kubeflow product. -version: 2.13.0 -license: Apache-2.0 -base: ubuntu@20.04 -run-user: _daemon_ -services: - tensorflow-serving: - override: replace - summary: "tensorflow-serving service" - startup: enabled - command: bash -c 'tensorflow_model_server --port=8500 --rest_api_port=8501 --model_name=${MODEL_NAME} --model_base_path=${MODEL_BASE_PATH}/${MODEL_NAME} "$@"' [ args ] - environment: - MODEL_NAME: "model" - MODEL_BASE_PATH: "/models" -entrypoint-service: tensorflow-serving -platforms: - amd64: - -parts: - tensorflow-serving: - plugin: nil - source: https://github.com/tensorflow/serving/ - source-type: git - source-tag: 2.13.0 - build-packages: - - automake - - build-essential - - ca-certificates - - curl - - git - - libcurl3-dev - - libfreetype6-dev - - libpng-dev - - libtool - - libzmq3-dev - - mlocate - - openjdk-8-jdk - - openjdk-8-jre-headless - - pkg-config - - pip - - python-dev - - python3.8 - - python3.8-dev - - python3-pip - - python3.8-venv - - software-properties-common - - swig - - tar - - unzip - - wget - - zip - - zlib1g-dev - - python3-distutils - build-environment: - - BAZEL_VERSION: "5.3.0" - override-build: | - set -e - - # Make python3.8 the default python version - python3.8 -m pip install pip --upgrade - update-alternatives --install /usr/bin/python python /usr/bin/python3.8 0 - - pip3 --no-cache-dir install future>=0.17.1 grpcio h5py keras_applications>=1.0.8 keras_preprocessing>=1.1.0 mock numpy portpicker requests --ignore-installed setuptools --ignore-installed six>=1.12.0 - - mkdir -p ${CRAFT_PART_INSTALL}/bazel - cd ${CRAFT_PART_INSTALL}/bazel - curl -H "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36" -fSsL -O https://github.com/bazelbuild/bazel/releases/download/${BAZEL_VERSION}/bazel-${BAZEL_VERSION}-installer-linux-x86_64.sh - curl -H "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36" -fSsL -o ${CRAFT_PART_INSTALL}/bazel/LICENSE.txt https://raw.githubusercontent.com/bazelbuild/bazel/master/LICENSE && \ - chmod +x bazel-*.sh - bash ./bazel-${BAZEL_VERSION}-installer-linux-x86_64.sh - rm -f bazel/bazel-$BAZEL_VERSION-installer-linux-x86_64.sh - - # Build, and install TensorFlow Serving - export TF_SERVING_VERSION_GIT_COMMIT=HEAD - export TF_SERVING_BUILD_OPTIONS="--config=release" - echo "Building with build options: ${TF_SERVING_BUILD_OPTIONS}" - export TF_SERVING_BAZEL_OPTIONS="" - echo "Building with Bazel options: ${TF_SERVING_BAZEL_OPTIONS}" - export PATH=${PATH}:${CRAFT_PART_INSTALL}/bazel:/usr/local/bin:/usr/bin - - mkdir -p /root/.cache - chmod -R 766 /root/.cache - mkdir -p ${CRAFT_PART_INSTALL}/usr/local/bin/ - cd ${CRAFT_PART_SRC} - touch WORKSPACE - bazel build --color=yes --curses=yes ${TF_SERVING_BAZEL_OPTIONS} --verbose_failures --output_filter=DONT_MATCH_ANYTHING ${TF_SERVING_BUILD_OPTIONS} tensorflow_serving/model_servers:tensorflow_model_server - cp ${CRAFT_PART_SRC}/bazel-bin/tensorflow_serving/model_servers/tensorflow_model_server ${CRAFT_PART_INSTALL}/usr/local/bin/ - - # Build and install TensorFlow Serving API - mkdir -p ${CRAFT_PART_INSTALL}/tmp/pip - bazel build --color=yes --curses=yes ${TF_SERVING_BAZEL_OPTIONS} --verbose_failures --output_filter=DONT_MATCH_ANYTHING ${TF_SERVING_BUILD_OPTIONS} tensorflow_serving/tools/pip_package:build_pip_package - ${CRAFT_PART_SRC}/bazel-bin/tensorflow_serving/tools/pip_package/build_pip_package ${CRAFT_PART_INSTALL}/tmp/pip - pip --no-cache-dir install --upgrade ${CRAFT_PART_INSTALL}/tmp/pip/tensorflow_serving_api-*.whl - rm -rf /tmp/pip - - # Clean up Bazel cache when done. - bazel clean --expunge --color=yes - rm -rf /root/.cache/bazel - - organize: - usr/local/bin/tensorflow_model_server: usr/bin/tensorflow_model_server - - security-requirements: - plugin: nil - after: [tensorflow-serving] - override-build: | - # security requirement using `ubuntu-22.04` base - # > ${CRAFT_PART_INSTALL}/usr/share/rocks/dpkg.query - # `--root` option is not available in dpkg-query version which is packaged with 20.04 - mkdir -p ${CRAFT_PART_INSTALL}/usr/share/rocks - (echo "# os-release" && cat /etc/os-release && echo "# dpkg-query") \ - > ${CRAFT_PART_INSTALL}/usr/share/rocks/dpkg.query - diff --git a/tensorflow-serving/tox.ini b/tensorflow-serving/tox.ini deleted file mode 100644 index b49722f..0000000 --- a/tensorflow-serving/tox.ini +++ /dev/null @@ -1,78 +0,0 @@ -# Copyright 2022 Canonical Ltd. -# See LICENSE file for licensing details. -[tox] -skipsdist = True -skip_missing_interpreters = True -envlist = unit, sanity, integration - -[testenv] -setenv = - PYTHONPATH={toxinidir} - PYTHONBREAKPOINT=ipdb.set_trace - CHARM_REPO=https://github.com/canonical/seldon-core-operator.git - CHARM_BRANCH=main - LOCAL_CHARM_DIR=charm_repo - -[testenv:pack] -passenv = * -allowlist_externals = - rockcraft -commands = - rockcraft pack - -[testenv:export-to-docker] -passenv = * -allowlist_externals = - bash - skopeo - yq -commands = - # pack rock and export to docker - bash -c 'NAME=$(yq eval .name rockcraft.yaml) && \ - VERSION=$(yq eval .version rockcraft.yaml) && \ - ARCH=$(yq eval ".platforms | keys | .[0]" rockcraft.yaml) && \ - ROCK="$\{NAME\}_$\{VERSION\}_$\{ARCH\}.rock" && \ - DOCKER_IMAGE=$NAME:$VERSION && \ - echo "Exporting $ROCK to docker as $DOCKER_IMAGE" && \\ - skopeo --insecure-policy copy oci-archive:$ROCK docker-daemon:$DOCKER_IMAGE' - -[testenv:sanity] -passenv = * -allowlist_externals = - echo -commands = - echo "WARNING: This is a placeholder test - no test is implemented here." - -[testenv:integration] -passenv = * -allowlist_externals = - bash - git - rm - tox - sed -deps = - juju<4.0 - pytest - pytest-operator - ops -commands = - # clone related charm - rm -rf {env:LOCAL_CHARM_DIR} - git clone --branch {env:CHARM_BRANCH} {env:CHARM_REPO} {env:LOCAL_CHARM_DIR} - # replace jinja2 templated value with yq safe placeholder - sed -i "s/namespace: {{ namespace }}/namespace: YQ_SAFE/" {env:LOCAL_CHARM_DIR}/src/templates/configmap.yaml.j2 - # upload rock to docker and microk8s cache, replace charm's container with local rock reference - bash -c 'NAME=$(yq eval .name rockcraft.yaml) && \ - VERSION=$(yq eval .version rockcraft.yaml) && \ - DOCKER_IMAGE=$NAME:$VERSION && \ - docker save $DOCKER_IMAGE > $DOCKER_IMAGE.tar && \ - sudo microk8s ctr image import $DOCKER_IMAGE.tar --digests=true && \ - predictor_servers=$(yq e ".data.predictor_servers" {env:LOCAL_CHARM_DIR}/src/templates/configmap.yaml.j2) && \ - predictor_servers=$(jq --arg jq_name $NAME -r '\''.TENSORFLOW_SERVER.protocols.tensorflow.image=$jq_name'\'' <<< $predictor_servers) && \ - predictor_servers=$(jq --arg jq_version $VERSION -r '\''.TENSORFLOW_SERVER.protocols.tensorflow.defaultImageVersion=$jq_version'\'' <<< $predictor_servers) yq e -i ".data.predictor_servers=strenv(predictor_servers)" {env:LOCAL_CHARM_DIR}/src/templates/configmap.yaml.j2' - # replace yq safe placeholder with original value - sed -i "s/namespace: YQ_SAFE/namespace: {{ namespace }}/" {env:LOCAL_CHARM_DIR}/src/templates/configmap.yaml.j2 - # run charm integration test with rock - tox -c {env:LOCAL_CHARM_DIR} -e seldon-servers-integration -- -k tf-serving -