Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Use new python3.10-venv slices when bare in flask-framework extension #606

Merged
merged 21 commits into from
Jun 25, 2024
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/tutorials/getting-started-with-flask.rst
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,7 @@ As before, verify that the new rock was created:
:end-before: [docs:ls-bare-rock-end]
:dedent: 2

You'll verify that the new Flask rock is now approximately **15% smaller**
You'll verify that the new Flask rock is now approximately **30% smaller**
in size! And that's just because of the simple change of ``base``.

And the functionality is still the same. As before, you can confirm this by
Expand Down
9 changes: 8 additions & 1 deletion rockcraft/extensions/gunicorn.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,13 +66,20 @@ def gen_install_app_part(self) -> Dict[str, Any]:
def _gen_parts(self) -> dict:
"""Generate the parts associated with this extension."""
data_dir = get_extensions_data_dir()
stage_packages = ["python3-venv"]
gregory-schiano marked this conversation as resolved.
Show resolved Hide resolved
build_environment = []
if self.yaml_data["base"] == "bare":
stage_packages = ["python3.11-venv_ensurepip"]
build_environment = [{"PARTS_PYTHON_INTERPRETER": "python3.11"}]

parts: Dict[str, Any] = {
f"{self.framework}-framework/dependencies": {
"plugin": "python",
"stage-packages": ["python3-venv"],
"stage-packages": stage_packages,
"source": ".",
"python-packages": ["gunicorn"],
"python-requirements": ["requirements.txt"],
"build-environment": build_environment,
},
f"{self.framework}-framework/install-app": self.gen_install_app_part(),
f"{self.framework}-framework/config-files": {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
test
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
from flask import Flask # pyright: ignore[reportMissingImports]

app = Flask(__name__)


@app.route("/")
def ok():
return "ok"
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
flask
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
console.log("hello")
79 changes: 79 additions & 0 deletions tests/spread/rockcraft/extension-flask-uncomment-blocks/task.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
summary: flask extension test
environment:
SCENARIO/bare: bare
SCENARIO/base_2204: ubuntu-22.04
BLOCK/bare: runtime-slices
BLOCK/base_2204: runtime-debs
execute: |
NAME="flask-${SCENARIO//./-}"
ROCK_FILE="${NAME}_0.1_amd64.rock"
IMAGE="${NAME}:0.1"

run_rockcraft init --name flask-extension --profile flask-framework
sed -i "s/name: .*/name: ${NAME}/g" rockcraft.yaml
if [ "${SCENARIO}" = "bare" ]; then
tigarmo marked this conversation as resolved.
Show resolved Hide resolved
sed -i "s/base: .*/base: ${SCENARIO}\nbuild-base: [email protected]/g" rockcraft.yaml
else
sed -i "s/base: .*/base: ${SCENARIO//-/@}/g" rockcraft.yaml
fi

# uncomment the parts main section
sed -i "s/# parts:/parts:/g" rockcraft.yaml
# uncomment the part depending on the base
awk -i inplace -v block_key="${BLOCK}" '
BEGIN {
in_block = 0;
comment_pattern = "^#[[:space:]]";
uncommented_line = "";
}

/^#[[:space:]]/ {
# Check if the line contains the block key
if (in_block == 0 && $0 ~ block_key) {
in_block = 1;
}
}

{
# If in_block is active, uncomment lines
if (in_block == 1) {
uncommented_line = gensub(comment_pattern, "", 1, $0);
if (uncommented_line == $0) {
in_block = 0;
}
print uncommented_line;
} else {
print $0;
}
}' rockcraft.yaml
run_rockcraft pack

test -f "${ROCK_FILE}"
test ! -d work

# Ensure docker does not have this container image
docker rmi --force "${IMAGE}"
# Install container
sudo rockcraft.skopeo --insecure-policy copy "oci-archive:${ROCK_FILE}" "docker-daemon:${IMAGE}"
# Ensure container exists
docker images "${IMAGE}" | MATCH "${NAME}"

# ensure container doesn't exist
docker rm -f "${NAME}-container"

# test the flask project is ready to run inside the container
docker run --rm --entrypoint /bin/python3 "${IMAGE}" -m gunicorn --chdir /flask/app --check-config app:app
docker run --rm --entrypoint /bin/python3 "${IMAGE}" -c "import pathlib;assert pathlib.Path('/flask/app/static/js/test.js').is_file()"
docker run --rm --entrypoint /bin/python3 "${IMAGE}" -c "import pathlib;assert not pathlib.Path('/flask/app/node_modules').exists()"

# test the uncommented extra parts effectively added libpq library
docker run --rm --entrypoint /bin/bash "${IMAGE}" -c '/bin/ls -1 /usr/lib/**/libpq.so.5*'

# test the default flask service
docker run --name "${NAME}-container" -d -p 8137:8000 "${IMAGE}"
retry -n 5 --wait 2 curl localhost:8137
[ "$(curl -sSf localhost:8137)" == "ok" ]

restore: |
rm -f "*.rock"
docker system prune -a -f
37 changes: 24 additions & 13 deletions tests/spread/rockcraft/extension-flask/task.yaml
Original file line number Diff line number Diff line change
@@ -1,33 +1,44 @@
summary: flask extension test

environment:
SCENARIO/bare: bare
SCENARIO/base_2204: ubuntu-22.04
execute: |
NAME="flask-${SCENARIO//./-}"
ROCK_FILE="${NAME}_0.1_amd64.rock"
IMAGE="${NAME}:0.1"

run_rockcraft init --name flask-extension --profile flask-framework
sed -i "s/name: .*/name: ${NAME}/g" rockcraft.yaml
if [ "${SCENARIO}" = "bare" ]; then
tigarmo marked this conversation as resolved.
Show resolved Hide resolved
sed -i "s/base: .*/base: ${SCENARIO}\nbuild-base: [email protected]/g" rockcraft.yaml
else
sed -i "s/base: .*/base: ${SCENARIO//-/@}/g" rockcraft.yaml
fi
run_rockcraft pack

test -f flask-extension_0.1_amd64.rock
test -f "${ROCK_FILE}"
test ! -d work

# Ensure docker does not have this container image
docker rmi --force flask-extension
docker rmi --force "${IMAGE}"
# Install container
sudo rockcraft.skopeo --insecure-policy copy oci-archive:flask-extension_0.1_amd64.rock docker-daemon:flask-extension:latest
sudo rockcraft.skopeo --insecure-policy copy "oci-archive:${ROCK_FILE}" "docker-daemon:${IMAGE}"
# Ensure container exists
docker images flask-extension | MATCH "flask-extension"
docker images "${IMAGE}" | MATCH "${NAME}"

# ensure container doesn't exist
docker rm -f flask-extension-container
docker rm -f "${NAME}-container"

# test the flask project is ready to run inside the container
docker run --rm --entrypoint /bin/python3 flask-extension -m gunicorn --chdir /flask/app --check-config app:app
docker run --rm --entrypoint /bin/python3 flask-extension -c "import pathlib;assert pathlib.Path('/flask/app/static/js/test.js').is_file()"
docker run --rm --entrypoint /bin/python3 flask-extension -c "import pathlib;assert not pathlib.Path('/flask/app/node_modules').exists()"
docker run --rm --entrypoint /bin/python3 "${IMAGE}" -m gunicorn --chdir /flask/app --check-config app:app
docker run --rm --entrypoint /bin/python3 "${IMAGE}" -c "import pathlib;assert pathlib.Path('/flask/app/static/js/test.js').is_file()"
docker run --rm --entrypoint /bin/python3 "${IMAGE}" -c "import pathlib;assert not pathlib.Path('/flask/app/node_modules').exists()"

# test the default flask service
docker run --name flask-extension-container -d -p 8137:8000 flask-extension
docker run --name "${NAME}-container" -d -p 8137:8000 "${IMAGE}"
retry -n 5 --wait 2 curl localhost:8137
[ "$(curl -sSf localhost:8137)" == "ok" ]

restore: |
rm -f flask-extension_0.1_amd64.rock
docker rmi -f flask-extension
docker rm -f flask-extension-container
rm -f "*.rock"
docker system prune -a -f
11 changes: 11 additions & 0 deletions tests/unit/extensions/test_gunicorn.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ def test_flask_extension_default(tmp_path, flask_input_yaml, packages):
"python-requirements": ["requirements.txt"],
"source": ".",
"stage-packages": ["python3-venv"],
"build-environment": [],
},
"flask-framework/install-app": {
"organize": {
Expand Down Expand Up @@ -276,6 +277,7 @@ def test_flask_extension_override_parts(tmp_path, flask_input_yaml):
"python-requirements": ["requirements.txt", "requirements-jammy.txt"],
"source": ".",
"stage-packages": ["python3-venv"],
"build-environment": [],
}


Expand All @@ -296,6 +298,14 @@ def test_flask_extension_bare(tmp_path):
"override-build": "mkdir -m 777 ${CRAFT_PART_INSTALL}/tmp",
"stage-packages": ["bash_bins", "coreutils_bins", "ca-certificates_data"],
}
assert applied["parts"]["flask-framework/dependencies"] == {
"plugin": "python",
"python-packages": ["gunicorn"],
"python-requirements": ["requirements.txt"],
"source": ".",
"stage-packages": ["python3.11-venv_ensurepip"],
"build-environment": [{"PARTS_PYTHON_INTERPRETER": "python3.11"}],
}


@pytest.mark.usefixtures("flask_extension")
Expand Down Expand Up @@ -436,6 +446,7 @@ def test_django_extension_default(tmp_path, django_input_yaml):
"python-requirements": ["requirements.txt"],
"source": ".",
"stage-packages": ["python3-venv"],
"build-environment": [],
},
"django-framework/install-app": {
"organize": {"*": "django/app/", ".*": "django/app/"},
Expand Down
Loading