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 the new edx-platform assets build + other improvements #34

Closed
wants to merge 59 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
59 commits
Select commit Hold shift + click to select a range
1a3abf8
feat!: assume BuildKit is available
kdmccormick Aug 18, 2023
61862b3
build: take advantage of upstream static asset build improvements
kdmccormick Aug 18, 2023
1ec378f
feat: `tutor dev/local copyartifacts`
kdmccormick Aug 31, 2023
eba2c77
Merge remote-tracking branch 'upstream/nightly' into kdmccormick/assets
kdmccormick Sep 6, 2023
b77ea64
Merge remote-tracking branch 'upstream/nightly' into kdmccormick/assets
kdmccormick Oct 5, 2023
f5c463b
Merge remote-tracking branch 'upstream/nightly' into kdmccormick/assets
kdmccormick Oct 16, 2023
c28cc93
Merge remote-tracking branch 'upstream/nightly' into kdmccormick/assets
kdmccormick Oct 17, 2023
510b023
build: switch watchthemes over to `npm run watch-sass`
kdmccormick Oct 18, 2023
82cdc5d
Merge remote-tracking branch 'upstream/nightly' into kdmccormick/assets
kdmccormick Oct 18, 2023
7123b8c
build: ensure EDX_PLATFORM_THEMES_ROOT is set in dev image to allow t…
kdmccormick Oct 19, 2023
8c72f69
Merge branch 'nightly' into kdmccormick/assets
kdmccormick Oct 25, 2023
0378a77
fix: build: re-install edx-platform in dev image
kdmccormick Oct 25, 2023
1d57cd8
Merge remote-tracking branch 'upstream/nightly' into kdmccormick/assets
kdmccormick Nov 9, 2023
e9e590d
Merge remote-tracking branch 'upstream/nightly' into kdmccormick/assets
kdmccormick Dec 6, 2023
ed519cb
Merge remote-tracking branch 'upstream/nightly' into kdmccormick/assets
kdmccormick Dec 18, 2023
72a832a
fix: build: separately install auto-mounts for prod, dev
kdmccormick Dec 18, 2023
2e5b530
Merge remote-tracking branch 'upstream/nightly' into kdmccormick/assets
kdmccormick Dec 18, 2023
a4e3155
fix: RsaKey.dq attribute error
regisb Dec 14, 2023
96a04db
temp: fix: temporary fix for 'tutor dev copyartifacts'; needs to be g…
kdmccormick Dec 20, 2023
bc9b2d6
docs: demo.openedx.edly.io -> sandbox.openedx.edly.io
regisb Dec 21, 2023
6948586
docs: more precise contribution instructions
Abdul-Muqadim-Arbisoft Jan 8, 2024
7879eff
docs: fix minor issues
regisb Jan 12, 2024
f2a5196
build: Github action to auto-add new issues and PRs to project
DawoudSheraz Jan 12, 2024
57e5712
ci: fix github token in auto-add to project
regisb Jan 12, 2024
02ee7ff
ci: fix reference to personal access token
regisb Jan 12, 2024
44f52f8
security: fix JWT scopes in XBlock callbacks
regisb Jan 22, 2024
c490c37
docs: remove useless openedx hooks section
regisb Jan 22, 2024
fdeb4b6
fix: security issues with jinja2 and pycryptodome
regisb Jan 22, 2024
7ea76e2
fix: correctly render .webp and .otf files in env
ravikhetani Jan 22, 2024
f0d4bd9
docs: fix google analytics example
Silidrone Jan 22, 2024
7f95062
docs: extra hooks functions and utilities
regisb Jan 22, 2024
aece9b6
doc: update steps to release a new version
Faraz32123 Jan 23, 2024
4e6df39
v17.0.1
regisb Jan 25, 2024
2789740
fix: Fix tutor when using docker compose versions > 2.24.1
xitij2000 Jan 25, 2024
62973dc
fixup!: Apply review feedback
xitij2000 Jan 29, 2024
70224a7
chore: remove useless test file
regisb Jan 30, 2024
d879573
fix: save env on `plugins enable`
regisb Jan 30, 2024
020787e
chore: add missing test fixture and changelog entry
regisb Feb 8, 2024
bf9fe93
Merge remote-tracking branch 'upstream/nightly' into kdmccormick/assets
kdmccormick Feb 8, 2024
dcab52d
fix: remove old temporary edx-platform patch
kdmccormick Feb 8, 2024
dfb6d53
Merge remote-tracking branch 'upstream/nightly' into kdmccormick/assets
kdmccormick Feb 16, 2024
d857612
Merge remote-tracking branch 'upstream/nightly' into kdmccormick/assets
kdmccormick Feb 21, 2024
cc65425
Merge remote-tracking branch 'upstream/nightly' into kdmccormick/assets
kdmccormick Mar 11, 2024
f00c311
feat!: remove dependency on Paver scripts
kdmccormick Oct 17, 2023
dc2ca3d
Merge remote-tracking branch 'origin/kdmccormick/assets-build' into k…
kdmccormick May 15, 2024
b38354f
fix: we cant use --link and --chown together?
kdmccormick May 15, 2024
5f79206
fix: rm 3.8/sass -> 3.11/sass
kdmccormick May 20, 2024
aba2af3
Merge remote-tracking branch 'upstream/nightly' into kdmccormick/assets
kdmccormick May 20, 2024
e46a58d
build: get rid of 'rm sass' line; optimization is not worth complexity
kdmccormick May 20, 2024
281c7b5
style: tabs -> spaces
kdmccormick May 20, 2024
eef1730
fix: chown /openedx app
kdmccormick May 20, 2024
a86e932
build: put link back on everything
kdmccormick May 20, 2024
f13715f
build: remove some --link
kdmccormick May 20, 2024
8e6f523
build: remove all --link again
kdmccormick May 20, 2024
072799b
fix: remove superfluous assets rebuild (from merge)
kdmccormick May 20, 2024
4f562d7
fix: make --link work via APP_USER_ID
kdmccormick May 25, 2024
6f664cc
Merge remote-tracking branch 'upstream/nightly' into kdmccormick/assets
kdmccormick May 28, 2024
1bd7aa5
fix: base app on minimal not python ; extract locales
kdmccormick May 28, 2024
7d5b970
feat!: simplify layers and remove comments for brevity
kdmccormick May 28, 2024
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
74 changes: 74 additions & 0 deletions tutor/commands/compose.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
from tutor.exceptions import TutorError
from tutor.tasks import BaseComposeTaskRunner
from tutor.types import Config
from tutor.utils import execute as execute_shell


class ComposeTaskRunner(BaseComposeTaskRunner):
Expand Down Expand Up @@ -114,6 +115,10 @@ def launch(
click.echo(fmt.title("Docker image updates"))
context.invoke(dc_command, command="pull")

if bindmount.get_mounts(config):
click.echo(fmt.title("Copying build artifacts into bind-mounted directories"))
context.invoke(copyartifacts)

click.echo(fmt.title("Starting the platform in detached mode"))
context.invoke(start, detach=True)

Expand Down Expand Up @@ -365,6 +370,63 @@ def copyfrom(
)


@click.command(
help="TODO describe"
)
@click.argument(
"mount_paths",
metavar="mount_path",
nargs=-1,
type=click.Path(dir_okay=True, file_okay=False, resolve_path=True),
)
@click.pass_obj
def copyartifacts(context: BaseComposeContext, mount_paths: list[Path]) -> None:
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm wondering if it makes sense to provide a dedicated command. In which cases will users have to run it? If I understand correctly, they will only run it when they don't want to run launch. But then this opens up the possibility that they will forget to build the Docker image before running copyartifacts. In such a scenario, the artifacts will be outdated, right?

I might not 100% understand the pros and cons, but it seems to me that it would be more intuitive if artifacts are copied as part of do init.

"""
TODO write docstring
TODO move this to `tutor images build <IMAGE> --populate` ??
"""
config = tutor_config.load(context.root)
host_mount_paths: list[str] = [
os.path.abspath(os.path.expanduser(mount_path))
for mount_path
in mount_paths or bindmount.get_mounts(config)
]

# Sort out the (source, target) pairs by image name so that we can work one-at-a-time later.
copies_by_image: dict[str, tuple[str, str]] = {}
for host_mount_path in host_mount_paths:
mount_name = os.path.basename(host_mount_path)
for image, container_mount_path in hooks.Filters.COMPOSE_MOUNTS.iterate(mount_name):
if image != "openedx-dev":
# TODO just do openedx-dev for now -- will generalize this soon.
continue
for path_in_mount in hooks.Filters.IMAGES_BUILD_MOUNT_ARTIFACTS.iterate(mount_name, image):
source = f"{container_mount_path}/{path_in_mount}"
target = f"{host_mount_path}/{path_in_mount}"
copies_by_image.setdefault(image, []).append((source, target))

container_name = "tutor_mounts_populate_temp" # TODO: improve name?
runner = context.job_runner(config)

# For each image: create a temporary container, do the copy operations, and then rm the container.
if not copies_by_image:
fmt.echo_alert("Nothing to copy.")
return
for image, copies in copies_by_image.items():
execute_shell("docker", "rm", "-f", container_name)
for name, _, tag, __ in hooks.Filters.IMAGES_BUILD.iterate(config):
if name == image:
execute_shell("docker", "create", "--name", container_name, tag)
break
else:
raise ValueError(f"unknown image name: {name}")
for source, target in copies:
execute_shell("rm", "-rf", target) # Wipe any existing artifact.
execute_shell("sh", "-c", f'mkdir -p "$(dirname "{target}")"') # Ensure parent dirs exist.
execute_shell("docker", "cp", f"{container_name}:{source}", target) # Actually do the copy.
execute_shell("docker", "rm", "-f", container_name)


@click.command(
short_help="Run a command in a running container",
help=(
Expand Down Expand Up @@ -426,6 +488,17 @@ def dc_command(
context.job_runner(config).docker_compose(command, *args)


@hooks.Filters.APP_PUBLIC_HOSTS.add()
def _edx_platform_public_hosts(
hosts: list[str], context_name: t.Literal["local", "dev"]
) -> list[str]:
if context_name == "dev":
hosts += ["{{ LMS_HOST }}:8000", "{{ CMS_HOST }}:8001"]
else:
hosts += ["{{ LMS_HOST }}", "{{ CMS_HOST }}"]
return hosts


hooks.Filters.ENV_TEMPLATE_VARIABLES.add_item(("iter_mounts", bindmount.iter_mounts))


Expand All @@ -439,6 +512,7 @@ def add_commands(command_group: click.Group) -> None:
command_group.add_command(dc_command)
command_group.add_command(run)
command_group.add_command(copyfrom)
command_group.add_command(copyartifacts)
command_group.add_command(execute)
command_group.add_command(logs)
command_group.add_command(status)
Expand Down
2 changes: 1 addition & 1 deletion tutor/commands/images.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ def _add_core_images_to_build(
image,
os.path.join("build", image),
tutor_config.get_typed(config, tag, str),
(),
("--target=production",),
)
)

Expand Down
28 changes: 28 additions & 0 deletions tutor/hooks/catalog.py
Original file line number Diff line number Diff line change
Expand Up @@ -401,6 +401,34 @@ def your_filter_callback(some_data):
#: ``os.path.basename(path)``) to conditionally add mounts.
IMAGES_BUILD_MOUNTS: Filter[list[tuple[str, str]], [str]] = Filter()

#: Relative paths of build artifacts, to be copied into a host-mounted folder from a service image.
#: (TODO update this description since Quince changes)
#:
#: Docker images contain many build artifacts, such as generated assets and packaging metadata, which
#: must exist at runtime in order for services to run properly. When a user bind-mounts a directory
#: from their host machine, there is no guarantee that the host directory will contain those essential
#: artifacts, and regenerating them from source may be time consuming. To remedy this, Tutor provides
#: the ``copyartifacts`` command, which efficiently copies the necessary artifacts from the original image
#: into the host directory. This command is also automatically run as part of ``launch``.
#:
#: The ``COMPOSE_MOUNT_ARTIFACTS`` filter tells Tutor which artifacts must be copied from which
#: service for any given host-mounted directory. By default, for edx-platform, this includes
#: several directories such as ``node_modules`` and ``lms/static/css``, to be copied from the lms
#: service's image.
#:
#: Note that any given artifact should only be specified once in this filter. If an artifact
#: exists on an image used by multiple services, choose one of those service for it to be
#: copied from.
#:
#: :parameter artifacts list[str]: files or directories considered build artifacts for the given
#: host-mounted folder in the given service. Paths must be relative to the mount directory.
#: :parameter str mount_name: basename of a host-mounted folder.
#: :parameter image: internal name of a Docker image from which artifacts will be copied. The ``IMAGES_BUILD_MOUNTS``
#: filter should map ``mount_name`` somewhere in this image; that mount location will be used
#: as the source for ``artifacts``.
IMAGES_BUILD_MOUNT_ARTIFACTS: Filter[list[str], [str, str]] = Filter()


#: List of images to be pulled when we run ``tutor images pull ...``.
#:
#: :parameter list[tuple[str, str]] tasks: list of ``(name, tag)`` tuples.
Expand Down
43 changes: 33 additions & 10 deletions tutor/plugins/openedx.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,27 @@ def _mount_edx_platform_build(
return volumes


@hooks.Filters.IMAGES_BUILD_MOUNT_ARTIFACTS.add()
def _populate_edx_platform(
paths_to_copy: list[str], mount_name: str, image: str
) -> list[tuple[str, str]]:
"""
TODO describe
"""
if mount_name == "edx-platform" and image in ["openedx", "openedx-dev"]:
paths_to_copy += [
"Open_edX.egg-info",
"node_modules",
"lms/static/css",
"lms/static/certificates/css",
"cms/static/css",
"common/static/bundles",
"common/static/common/js/vendor",
"common/static/common/css/vendor",
]
return paths_to_copy


@hooks.Filters.COMPOSE_MOUNTS.add()
def _mount_edx_platform_compose(
volumes: list[tuple[str, str]], name: str
Expand All @@ -55,20 +76,22 @@ def _mount_edx_platform_compose(
if name == "edx-platform":
path = "/openedx/edx-platform"
volumes.append(("openedx", path))
volumes.append(("openedx-dev", path))
return volumes


# Auto-magically bind-mount xblock directories and some common dependencies.
hooks.Filters.MOUNTED_DIRECTORIES.add_items(
[
("openedx", r".*[xX][bB]lock.*"),
("openedx", "edx-enterprise"),
("openedx", "edx-ora2"),
("openedx", "edx-search"),
("openedx", "openedx-learning"),
("openedx", r"platform-plugin-.*"),
]
)
for openedx_image in ["openedx", "openedx-dev"]:
hooks.Filters.MOUNTED_DIRECTORIES.add_items(
[
(openedx_image, r".*[xX][bB]lock.*"),
(openedx_image, "edx-enterprise"),
(openedx_image, "edx-ora2"),
(openedx_image, "edx-search"),
(openedx_image, "openedx-learning"),
(openedx_image, r"platform-plugin-.*"),
]
)


@hooks.Filters.MOUNTED_DIRECTORIES.add(priority=hooks.priorities.LOW)
Expand Down
Loading
Loading