datasette publish cloudrun --apt-get-install, closes #1110

pull/1112/head
Simon Willison 2020-11-24 19:05:35 -08:00
rodzic f2e2bfcdd9
commit 37d18a5bce
4 zmienionych plików z 97 dodań i 17 usunięć

Wyświetl plik

@ -36,6 +36,12 @@ def publish_subcommand(publish):
callback=_validate_memory,
help="Memory to allocate in Cloud Run, e.g. 1Gi",
)
@click.option(
"--apt-get-install",
"apt_get_extras",
multiple=True,
help="Additional packages to apt-get install",
)
def cloudrun(
files,
metadata,
@ -60,6 +66,7 @@ def publish_subcommand(publish):
spatialite,
show_files,
memory,
apt_get_extras,
):
fail_if_publish_binary_not_installed(
"gcloud", "Google Cloud", "https://cloud.google.com/sdk/"
@ -122,6 +129,7 @@ def publish_subcommand(publish):
secret,
extra_metadata,
environment_variables,
apt_get_extras=apt_get_extras,
):
if show_files:
if os.path.exists("metadata.json"):

Wyświetl plik

@ -47,11 +47,10 @@ reserved_words = set(
).split()
)
SPATIALITE_DOCKERFILE_EXTRAS = r"""
APT_GET_DOCKERFILE_EXTRAS = r"""
RUN apt-get update && \
apt-get install -y python3-dev gcc libsqlite3-mod-spatialite && \
apt-get install -y {} && \
rm -rf /var/lib/apt/lists/*
ENV SQLITE_EXTENSIONS /usr/lib/x86_64-linux-gnu/mod_spatialite.so
"""
# Can replace with sqlite-utils when I add that dependency
@ -308,10 +307,12 @@ def make_dockerfile(
secret,
environment_variables=None,
port=8001,
apt_get_extras=None,
):
cmd = ["datasette", "serve", "--host", "0.0.0.0"]
environment_variables = environment_variables or {}
environment_variables["DATASETTE_SECRET"] = secret
apt_get_extras = apt_get_extras or []
for filename in files:
cmd.extend(["-i", filename])
cmd.extend(["--cors", "--inspect-file", "inspect-data.json"])
@ -340,28 +341,38 @@ def make_dockerfile(
else:
install = ["datasette"] + list(install)
apt_get_extras_ = []
apt_get_extras_.extend(apt_get_extras)
apt_get_extras = apt_get_extras_
if spatialite:
apt_get_extras.extend(["python3-dev", "gcc", "libsqlite3-mod-spatialite"])
environment_variables[
"SQLITE_EXTENSIONS"
] = "/usr/lib/x86_64-linux-gnu/mod_spatialite.so"
return """
FROM python:3.8
COPY . /app
WORKDIR /app
{spatialite_extras}
{apt_get_extras}
{environment_variables}
RUN pip install -U {install_from}
RUN datasette inspect {files} --inspect-file inspect-data.json
ENV PORT {port}
EXPOSE {port}
CMD {cmd}""".format(
apt_get_extras=APT_GET_DOCKERFILE_EXTRAS.format(" ".join(apt_get_extras))
if apt_get_extras
else "",
environment_variables="\n".join(
[
"ENV {} '{}'".format(key, value)
for key, value in environment_variables.items()
]
),
files=" ".join(files),
cmd=cmd,
install_from=" ".join(install),
spatialite_extras=SPATIALITE_DOCKERFILE_EXTRAS if spatialite else "",
files=" ".join(files),
port=port,
cmd=cmd,
).strip()
@ -382,6 +393,7 @@ def temporary_docker_directory(
extra_metadata=None,
environment_variables=None,
port=8001,
apt_get_extras=None,
):
extra_metadata = extra_metadata or {}
tmp = tempfile.TemporaryDirectory()
@ -415,6 +427,7 @@ def temporary_docker_directory(
secret,
environment_variables,
port=port,
apt_get_extras=apt_get_extras,
)
os.chdir(datasette_dir)
if metadata_content:

Wyświetl plik

@ -30,4 +30,5 @@ Options:
--spatialite Enable SpatialLite extension
--show-files Output the generated Dockerfile and metadata.json
--memory TEXT Memory to allocate in Cloud Run, e.g. 1Gi
--apt-get-install TEXT Additional packages to apt-get install
--help Show this message and exit.

Wyświetl plik

@ -182,22 +182,26 @@ def test_publish_cloudrun_plugin_secrets(mock_call, mock_output, mock_which):
"x-secret",
],
)
assert result.exit_code == 0
dockerfile = (
result.output.split("==== Dockerfile ====\n")[1]
.split("\n====================\n")[0]
.strip()
)
expected = """FROM python:3.8
COPY . /app
WORKDIR /app
expected = textwrap.dedent(
r"""
FROM python:3.8
COPY . /app
WORKDIR /app
ENV DATASETTE_AUTH_GITHUB_CLIENT_ID 'x-client-id'
ENV DATASETTE_SECRET 'x-secret'
RUN pip install -U datasette
RUN datasette inspect test.db --inspect-file inspect-data.json
ENV PORT 8001
EXPOSE 8001
CMD datasette serve --host 0.0.0.0 -i test.db --cors --inspect-file inspect-data.json --metadata metadata.json --port $PORT""".strip()
ENV DATASETTE_AUTH_GITHUB_CLIENT_ID 'x-client-id'
ENV DATASETTE_SECRET 'x-secret'
RUN pip install -U datasette
RUN datasette inspect test.db --inspect-file inspect-data.json
ENV PORT 8001
EXPOSE 8001
CMD datasette serve --host 0.0.0.0 -i test.db --cors --inspect-file inspect-data.json --metadata metadata.json --port $PORT"""
).strip()
assert expected == dockerfile
metadata = (
result.output.split("=== metadata.json ===\n")[1]
@ -213,3 +217,57 @@ CMD datasette serve --host 0.0.0.0 -i test.db --cors --inspect-file inspect-data
}
},
} == json.loads(metadata)
@mock.patch("shutil.which")
@mock.patch("datasette.publish.cloudrun.check_output")
@mock.patch("datasette.publish.cloudrun.check_call")
def test_publish_cloudrun_apt_get_install(mock_call, mock_output, mock_which):
mock_which.return_value = True
mock_output.return_value = "myproject"
runner = CliRunner()
with runner.isolated_filesystem():
open("test.db", "w").write("data")
result = runner.invoke(
cli.cli,
[
"publish",
"cloudrun",
"test.db",
"--service",
"datasette",
"--show-files",
"--secret",
"x-secret",
"--apt-get-install",
"ripgrep",
"--spatialite",
],
)
assert result.exit_code == 0
dockerfile = (
result.output.split("==== Dockerfile ====\n")[1]
.split("\n====================\n")[0]
.strip()
)
expected = textwrap.dedent(
r"""
FROM python:3.8
COPY . /app
WORKDIR /app
RUN apt-get update && \
apt-get install -y ripgrep python3-dev gcc libsqlite3-mod-spatialite && \
rm -rf /var/lib/apt/lists/*
ENV DATASETTE_SECRET 'x-secret'
ENV SQLITE_EXTENSIONS '/usr/lib/x86_64-linux-gnu/mod_spatialite.so'
RUN pip install -U datasette
RUN datasette inspect test.db --inspect-file inspect-data.json
ENV PORT 8001
EXPOSE 8001
CMD datasette serve --host 0.0.0.0 -i test.db --cors --inspect-file inspect-data.json --port $PORT
"""
).strip()
assert expected == dockerfile