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

Programming exercises: Cache dependencies in the Java blackbox template #8351

Merged
merged 28 commits into from
Apr 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
6cf46f1
Make Maven configuration directories possible in templates
BaumiCoder Apr 5, 2024
5bdabfe
Dejagnu Blackbox: Set maven proxy for test
BaumiCoder Apr 5, 2024
eaee55e
Dejagnu Blackbox: Uncomment old caching code
BaumiCoder Apr 5, 2024
37c4bb3
Fix spelling mistakes
b-fein Apr 6, 2024
560c6dd
Remove details of alternative caching approach
b-fein Apr 6, 2024
b621248
Dejagnu Blackbox: Restrict network access
BaumiCoder Apr 6, 2024
8d9c29b
Blackbox: Generalize names in maven settings
BaumiCoder Apr 7, 2024
9901dd6
Adjust method name for setup dockerflags
BaumiCoder Apr 7, 2024
ece62c5
documentation: Caching with Sonatype Nexus
BaumiCoder Apr 7, 2024
0494c2c
Move network restriction to documentation
b-fein Apr 8, 2024
addf113
Use :caption: for code blocks
b-fein Apr 8, 2024
0e2a6a6
Fix spelling mistakes
b-fein Apr 8, 2024
9540fc2
State where settings for Maven Proxy are necessary
b-fein Apr 8, 2024
5b766f3
Fix :caption: usage
BaumiCoder Apr 8, 2024
b707315
Use :caption: for all code blocks
BaumiCoder Apr 8, 2024
a3f066c
Fix gramma mistake
b-fein Apr 8, 2024
26d3cb9
Sonatype Nexus is more general --> mention Maven
BaumiCoder Apr 8, 2024
0fb7fbe
Fix spelling mistake
BaumiCoder Apr 8, 2024
038f17e
Fix format problem
BaumiCoder Apr 8, 2024
72e1ce3
Fix layout
BaumiCoder Apr 8, 2024
f254740
Dejagnu Blackbox: Adjust links to documentation
BaumiCoder Apr 8, 2024
c719f13
Docs: Complete security considerations
BaumiCoder Apr 8, 2024
b6b2eef
Merge remote-tracking branch 'develop' into feature/Dejagnu-templates…
BaumiCoder Apr 8, 2024
5669450
Merge remote-tracking branch 'develop' into feature/Dejagnu-templates…
BaumiCoder Apr 9, 2024
6bf0c7c
Rephrase explanation of the example server
BaumiCoder Apr 10, 2024
225c791
Docs: add blank lines to improve code readability
BaumiCoder Apr 10, 2024
74f115d
Merge branch 'develop' into feature/Dejagnu-templates-caching
BaumiCoder Apr 10, 2024
1cc2804
Merge branch 'develop' into feature/Dejagnu-templates-caching
b-fein Apr 18, 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
175 changes: 167 additions & 8 deletions docs/admin/setup/programming-exercises.rst
Original file line number Diff line number Diff line change
Expand Up @@ -106,8 +106,149 @@ The ``pipeline.groovy`` file can be customized further by instructors after crea
Artemis via the ‘Edit Build Plan’ button on the details page of the exercise.


Caching example for Maven
^^^^^^^^^^^^^^^^^^^^^^^^^
.. _dependecies-sonatype-nexus:

Caching Maven Dependencies with Sonatype Nexus
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

With Sonatype Nexus you can run a caching server in your local network for Maven dependencies.
An alternative approach for caching is with docker volumes, see :ref:`dependecies-docker-volumes`.

.. note::

The following steps assume ``artemis.example.com`` is the host ``10.0.73.42`` and is using port ``8443`` for the cache.
Adapt the URLs for your actual setup.

Sonatype Nexus Setup
""""""""""""""""""""

1. Set up Sonatype Nexus to run on ``artemis.example.com:8443`` e.g. in a `Docker container <https://hub.docker.com/r/sonatype/nexus3/>`_ behind a `proxy <https://help.sonatype.com/en/run-behind-a-reverse-proxy.html>`_.
2. In the initial setup steps: Allow anonymous access.
3. Set up the Maven proxy repository:
a. Create a new repository (**Repository - Repositories - Create repository**) of type ``maven2 (proxy)`` with name ``maven-proxy``.
b. The remote URL is https://repo1.maven.org/maven2/.
4. Optionally create a new cleanup policy under *Repository - Cleanup Policies*
a. Format: ``maven2``
b. Release type: Releases & Pre-releases/Snapshots
c. Cleanup criteria: e.g. ‘Component Usage 14’ will remove all files that have not been downloaded for 14 days.
d. You can now add this cleanup policy to the policies in the repository you created earlier.

Adding proxy to a Maven build
"""""""""""""""""""""""""""""

The following changes have to be made inside the `tests` repository.

Option 1
========

Configure Maven so that it can find your Maven cache:

.. code-block:: xml
:caption: ``pom.xml``

<repositories>
<repository>
<id>artemis-cache</id>
<url>https://artemis.example.com:8443/repository/maven-proxy/</url>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>artemis-cache</id>
<url>https://artemis.example.com:8443/repository/maven-proxy/</url>
</pluginRepository>
</pluginRepositories>

Option 2 (more rigorous alternative)
====================================

This setup forces Maven to exclusively download dependencies from the own proxy.

.. code-block:: xml
:caption: ``.mvn/local-settings.xml``

<settings xmlns="http://maven.apache.org/SETTINGS/1.2.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.2.0 https://maven.apache.org/xsd/settings-1.2.0.xsd">
<mirrors>
<mirror>
<id>artemis-cache</id>
<name>Artemis Cache</name>
<url>https://artemis.example.com:8443/repository/maven-proxy/</url>
<mirrorOf>*</mirrorOf>
<blocked>false</blocked>
</mirror>
</mirrors>
</settings>


.. code-block:: shell
:caption: ``.mvn/maven.config``

--settings
./.mvn/local-settings.xml

Adding proxy to a Gradle build
""""""""""""""""""""""""""""""

The following changes have to be made inside the `tests` repository.

.. code-block:: groovy
:caption: ``build.gradle``

repositories {
maven {
url "https://artemis.example.com:8443/repository/maven-proxy/"
}
// …
}


.. code-block:: kotlin
:caption: Gradle ``build.gradle.kts``

repositories {
maven {
url = uri("https://artemis.example.com:8443/repository/maven-proxy/")
}
// …
}

Security Considerations
"""""""""""""""""""""""

When you are using secret tests as part of your exercise, you might want to restrict network traffic leaving the CI run to avoid students leaking information.

Jenkins
=======

In Jenkins setups, you can restrict the network access by adjusting the ``pipeline.groovy`` script.
Add some flags to the ``dockerFlags`` variable:

.. code:: groovy

dockerFlags += '--add-host "artemis.example.com:10.0.73.42" \
--network "artemis-restricted"'

Additionally, on the CI runner host you will have to create the `artemis-restricted` Docker network and some iptables firewall rules to restrict traffic:

.. code-block:: sh

docker network create --opt com.docker.network.bridge.name=artemis-restr artemis-restricted
iptables -I DOCKER-USER -i artemis-restr -j DROP
iptables -I DOCKER-USER -i artemis-restr -d $IP_OF_ARTEMIS_EXAMPLE_COM_CACHE -p tcp --dport 8443 -j ACCEPT


.. _dependecies-docker-volumes:

Caching with Docker Volumes
^^^^^^^^^^^^^^^^^^^^^^^^^^^

With Docker volumes you can cache Maven dependencies.
An alternative approach for caching is with Sonatype Nexus, see :ref:`dependecies-sonatype-nexus`.

Example for Maven
"""""""""""""""""

The container image used to run the maven-tests already contains a set of commonly used dependencies
(see `artemis-maven-docker <https://github.com/ls1intum/artemis-maven-docker>`__).
Expand Down Expand Up @@ -141,14 +282,14 @@ and changing the ``testRunner`` method into
.. code:: groovy

void testRunner() {
setDockerFlags()
setup()

docker.image(dockerImage).inside(dockerFlags) { c ->
runTestSteps()
}
}

private void setDockerFlags() {
private void setup() {
if (isSolutionBuild) {
dockerFlags += " -v artemis_maven_cache:/maven_cache"
} else {
Expand All @@ -160,17 +301,17 @@ This mounts the cache as writeable only when executing the tests for the solutio
running the tests for students’ code.


Caching example for Gradle
^^^^^^^^^^^^^^^^^^^^^^^^^^
Example for Gradle
""""""""""""""""""

In case of always writeable caches you can set ``-e GRADLE_USER_HOME=/gradle_cache`` as part of the ``dockerFlags``
instead of the ``MAVEN_OPTS`` like above.

For read-only caches like in the Maven example, define ``setDockerFlags()`` as
For read-only caches like in the Maven example, define ``setup()`` as

.. code:: groovy

private void setDockerFlags() {
private void setup() {
if (isSolutionBuild) {
dockerFlags += ' -e GRADLE_USER_HOME="/gradle_cache"'
dockerFlags += ' -v artemis_gradle_cache:/gradle_cache'
Expand All @@ -180,3 +321,21 @@ For read-only caches like in the Maven example, define ``setDockerFlags()`` as
}
}

Security Considerations
"""""""""""""""""""""""

When you are using secret tests as part of your exercise, you might want to disable network traffic leaving the CI run to avoid students leaking information.
Thanks to the fact that the cache is prepared while running for the solution, you can disable the network for students submissions.
Adjust ``dockerFlags`` and ``mavenFlags`` only for student submissions, like this:

.. code:: groovy

private void setup() {
if (isSolutionBuild) {
// handle docker flags
} else {
// handle docker flags
// if not solution repo, disallow network access from containers
dockerFlags += ' --network none'
mavenFlags += ' --offline'
}
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ public class FileService implements DisposableBean {
/**
* These directories get falsely marked as files and should be ignored during copying.
*/
private static final List<String> IGNORED_DIRECTORY_SUFFIXES = List.of(".xcassets", ".colorset", ".appiconset", ".xcworkspace", ".xcodeproj", ".swiftpm", ".tests");
private static final List<String> IGNORED_DIRECTORY_SUFFIXES = List.of(".xcassets", ".colorset", ".appiconset", ".xcworkspace", ".xcodeproj", ".swiftpm", ".tests", ".mvn");

@Override
public void destroy() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<settings xmlns="http://maven.apache.org/SETTINGS/1.2.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.2.0 https://maven.apache.org/xsd/settings-1.2.0.xsd">
<mirrors>
<mirror>
<id>artemis-cache</id>
<name>Artemis Cache</name>
<!--
Here you can specify another Maven proxy e.g. one in your local network to improve performance
Details are in the documentation:
https://docs.artemis.cit.tum.de/admin/setup/programming-exercises.html#caching-maven-dependencies-with-sonatype-nexus
-->
<url>https://repo1.maven.org/maven2/</url>
<mirrorOf>*</mirrorOf>
<blocked>false</blocked>
</mirror>
</mirrors>
</settings>
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
--settings
./.mvn/local-settings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -40,15 +40,18 @@ void testRunner() {
* E.g. container creation, setting docker flags.
*/
private void setup() {
// special jobs to run only for the solution repository
/* special jobs to run only for the solution repository
* This may for example be useful when caching dependencies either in container volumes
* or an external cache to enforce the appropriate access restrictions. You can find
* more information on that in the documentation at
* https://docs.artemis.cit.tum.de/admin/setup/programming-exercises.html#caching-with-docker-volumes
* and
* https://docs.artemis.cit.tum.de/admin/setup/programming-exercises.html#caching-maven-dependencies-with-sonatype-nexus
*/
if ("${env.JOB_NAME}" ==~ /.+-SOLUTION$/) {
dockerFlags += ' -v artemis_blackbox_maven-cache:/maven_cache'
// processing sample solution in this run
} else {
dockerFlags += ' -v artemis_blackbox_maven-cache:/maven_cache:ro'

// if not solution repo, disallow network access from containers
dockerFlags += ' --network none'
mavenFlags += ' --offline'
// processing student submission in this run
}
}

Expand Down
Loading