diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..61fe8de4 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,20 @@ +# Auto detect text files and perform LF normalization +* text=auto + +# Gradle files +gradlew text eol=lf diff=bash +*.gradle text eol=lf diff=java +*.gradle.kts text eol=lf diff=java + +# Force bash scripts to always use lf line endings so that if a repo is accessed +# in Unix via a file share from Windows, the scripts will work. +*.bat text eol=crlf diff=batch +*.sh text eol=lf diff=bash +*.properties text eol=lf +run text eol=lf diff=bash +finish text eol=lf diff=bash + +# These files are binary and should be left untouched +# (binary is a macro for -text -diff) +*.jar binary +*.war binary diff --git a/.github/workflows/master.yml b/.github/workflows/master.yml new file mode 100644 index 00000000..1b09c35f --- /dev/null +++ b/.github/workflows/master.yml @@ -0,0 +1,38 @@ +name: CI +on: + push: + branches: + - master + pull_request: + branches: + - master +jobs: + build: + name: Build and Push Docker Images + runs-on: ubuntu-latest + timeout-minutes: 30 + steps: + - name: Checkout + uses: actions/checkout@v2 + - name: Setup Java + uses: actions/setup-java@v1 + with: + java-version: 8 + - name: Setup Gradle Cache + uses: actions/cache@v1 + with: + path: ~/.gradle/caches + key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*') }} + restore-keys: | + ${{ runner.os }}-gradle- + - name: Log in to Docker Hub + run: docker login -u '${{ secrets.REGISTRY_USER }}' -p '${{ secrets.REGISTRY_PASS }}' '${{ secrets.REGISTRY_URL }}' + - name: Build Docker images + uses: eskatos/gradle-command-action@v1 + with: + arguments: build '-Prepository=${{ secrets.REPOSITORY }}' --info + - name: Push Docker images + uses: eskatos/gradle-command-action@v1 + with: + arguments: push '-Prepository=${{ secrets.REPOSITORY }}' '-PregistryUrl=${{ secrets.REGISTRY_URL }}' '-PregistryUsername=${{ secrets.REGISTRY_USER }}' '-PregistryPassword=${{ secrets.REGISTRY_PASS }}' --info + # @todo add tests. diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml new file mode 100644 index 00000000..bbb073c3 --- /dev/null +++ b/.github/workflows/push.yml @@ -0,0 +1,31 @@ +name: CI +on: + push: + branches: + - '*/*' + - '*' + - '!master' +jobs: + build: + name: Build Docker Images + runs-on: ubuntu-latest + timeout-minutes: 30 + steps: + - name: Checkout + uses: actions/checkout@v2 + - name: Setup Java + uses: actions/setup-java@v1 + with: + java-version: 8 + - name: Setup Gradle Cache + uses: actions/cache@v1 + with: + path: ~/.gradle/caches + key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*') }} + restore-keys: | + ${{ runner.os }}-gradle- + - name: Build Docker images + uses: eskatos/gradle-command-action@v1 + with: + arguments: build --info + # @todo add tests. diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..0e6273db --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +.idea/ +.gradle/ +build +scratch +scratch.md diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000..33df578f --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,14 @@ +{ + "files.associations": { + "*.cfg.tmpl": "properties", + "*.cnf.tmpl": "properties", + "*.conf.tmpl": "properties", + "*.ini.tmpl": "properties", + "*.json.tmpl": "json", + "*.local.tmpl": "shellscript", + "*.properties.tmpl": "properties", + "*.sh.tmpl": "shellscript", + "*.sql.tmpl": "sql", + "*.xml.tmpl": "xml" + } +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 00000000..24e2916a --- /dev/null +++ b/README.md @@ -0,0 +1,622 @@ +# ISLE: Docker Prototype + +[![LICENSE](https://img.shields.io/badge/license-MIT-blue.svg?style=flat-square)](./LICENSE) +![CI](https://github.com/Islandora-Devops/isle-buildkit/workflows/CI/badge.svg?branch=master) + +- [Introduction](#introduction) +- [Requirements](#requirements) +- [Building](#building) + - [Build All Images](#build-all-images) + - [Building without Buildkit](#building-without-buildkit) + - [Build Specific Image](#build-specific-image) + - [Building Continuously](#building-continuously) +- [Running](#running) +- [Scripts](#scripts) +- [Docker Images](#docker-images) +- [Docker Compose](#docker-compose) + - [Watchtower](#watchtower) + - [Traefik](#traefik) +- [ETCD](#etcd) +- [Customizing the Drupal Installation](#customizing-the-drupal-installation) +- [Design Considerations](#design-considerations) + - [Confd](#confd) + - [S6 Overlay](#s6-overlay) + - [Image Hierarchy](#image-hierarchy) + - [Folder Layout](#folder-layout) + - [Build System](#build-system) +- [Design Constraints](#design-constraints) +- [Issues / FAQ](#issues--faq) +- [To Do](#to-do) + +## Introduction + +This repository provides a number of docker images and an example +[docker-compose.yml](./docker-compose.yml) for running the demo version of +Islandora. It is not yet in a production ready state. + +## Requirements + +To build the Docker images using the provided Gradle build scripts with [BuildKit] requires: + +- [Docker 18.09+](https://docs.docker.com/get-docker/) +- [OpenJDK or Oracle JDK 8+](https://www.java.com/en/download/) + +To run the Docker images with Docker Compose requires: + +- [Docker 18.06+](https://docs.docker.com/get-docker/) +- [Docker Compose 1.22+](https://docs.docker.com/compose/install/) + +That being said the images themselves are compatible with older versions of +Docker, if you require running on an older version you'll need to write your own +docker-compose file. + +## Building + +The build scripts rely on Gradle and should function equally well across +platforms. The only difference being the script you call to interact with gradle +(the following assumes you are executing from the **root directory** of the +project): + +**Linux or OSX:** + +```bash +./gradlew +``` + +**Windows:** + +```bash +gradlew.bat +``` + +For the remaining examples the **Linux or OSX** call method will be used, if +using Windows substitute the call to Gradle script. + +Gradle is a project/task based build system to query all the available tasks use +the following command. + +```bash +./gradlew tasks --all +``` + +Which should return something akin to: + +```bash +> Task :tasks + +------------------------------------------------------------ +Tasks runnable from root project +------------------------------------------------------------ + +... + +Islandora tasks +--------------- +abuild:build - Creates Docker image. +activemq:build - Creates Docker image. +alpaca:build - Creates Docker image. +base:build - Creates Docker image. + +... +``` + +In Gradle each Project maps onto a folder in the file system path where it is +delimited by ``:`` instead of ``/`` (Unix) or ``\`` (Windows). + +The root project ``:`` can be omitted. + +So if you want to run a particular task ``taskname`` that resided in the project +folder ``project/subproject`` you would specify it like so: + +```bash +./gradlew :project:subproject:taskname +``` + +To get more verbose output from Gradle use the ``--info`` argument like so: + +```bash +./gradlew :PROJECT:TASK --info +``` + +To build all the docker images you can use the following command: + +### Build All Images + +The following will build all the images in the correct order. + +```bash +./gradlew build +``` + +### Building without Buildkit + +If you are having trouble building, consider building without BuildKit as it's +supported by older versions of Docker. + +```bash +./gradlew build -PuseBuildKit=false +``` + +### Build Specific Image + +To build a specific image and it's dependencies, for example +``islandora/tomcat``, you can use the following: + +```bash +./gradlew tomcat:build +``` + +### Building Continuously + +It is often helpful to build continuously where-in any change you make to any of +the Dockerfiles or other project files, will automatically trigger the building +of that image and any downstream dependencies. To do this add the +``--continuous`` flag like so: + +```bash +./gradlew build --continuous +``` + +When this is combined with the use of ``watchtower`` and +``restart: unless-stopped`` in the [docker-compose.yml](./docker-compose.yml) +file. Images will be redeployed with the latest changes while you develop +automatically. See the [Docker Compose](#Docker-Compose) section of this +document for more details. + +## Running + +At the moment the example [docker-compose.yml] is the only orchestration +mechanism provided to launch all the containers, and have them work as a whole. + +To start the containers use the following command: + +```bash +docker-compose up -d +``` + +With [Docker Compose] there are many features such as displaying logs among +other things for which you can find detailed descriptions in the +[Docker Composer CLI Documentation](https://docs.docker.com/compose/reference/overview/) + +For more information on the structure and design of the example +[docker-compose.yml] file see the [Docker Compose](#Docker-Compose) section of +this document. + +## Scripts + +Some helper scripts are provided to make development and testing more pleasurable. + +- [./commands/drush.sh](./commands/drush.sh) - Wrapper around [drush] in the ``drupal service`` container. +- [./commands/etcdctrl.sh](./commands/etcdctrl.sh) - Wrapper around [etcdctrl] in the ``etcd service`` container. +- [./commands/mysql.sh](./commands/mysql.sh) - Wrapper around [mysql] client in the ``database service`` container. +- [./commands/open-in-browser.sh](./commands/shell.sh) - Attempts to open the given service in the users browser. +- [./commands/shell.sh](./commands/shell.sh) - Open ``ash`` shell in the given service container. + +All of the above commands include a usage statement, which can be accessed with ``-h`` flag like so: + +```bash +$ ./commands/shell.sh + usage: shell.sh SERVICE + + Opens an ash shell in the given SERVICE's container. + + OPTIONS: + -h --help Show this help. + -x --debug Debug this script. + + Examples: + shell.sh database +``` + +## Docker Images + +The following docker images are provided: + +- [abuild](./abuild/README.md) +- [activemq](./activemq/README.md) +- [alpaca](./alpaca/README.md) +- [base](./base/README.md) +- [blazegraph](./blazegraph/README.md) +- [build](./build/README.md) +- [cantaloupe](./cantaloupe/README.md) +- [composer](./composer/README.md) +- [crayfish](./crayfish/README.md) +- [crayfits](./crayfits/README.md) +- [drupal](./drupal/README.md) +- [fcrepo](./fcrepo/README.md) +- [fits](./fits/README.md) +- [gemini](./gemini/README.md) +- [homarus](./homarus/README.md) +- [houdini](./houdini/README.md) +- [hypercube](./hypercube/README.md) +- [imagemagick](./imagemagick/README.md) +- [java](./java/README.md) +- [karaf](./karaf/README.md) +- [mariadb](./mariadb/README.md) +- [matomo](./matomo/README.md) +- [milliner](./milliner/README.md) +- [nginx](./nginx/README.md) +- [recast](./recast/README.md) +- [sandbox](./sandbox/README.md) +- [solr](./solr/README.md) +- [tomcat](./tomcat/README.md) + +Many are intermediate images used to build other images in the list, for example +[java](./java/README.md). Please see the README of each image to find out what +settings, and ports, are exposed and what functionality it provides. + +## Docker Compose + +The example [docker-compose.yml] provided with this repository is a +template for those who wish to use [Docker Compose] for orchestration. The +images are not limited to running via [Docker Compose]. As time permits +additional tooling will be added to support [Kubernetes], and deploying to +[Amazon Elastic Container Service], and perhaps others. + +The example [docker-compose.yml] runs the [sandbox](./sandbox/README.md) version +of Islandora, for the purposes of testing the images, and Islandora. When +creating a ``docker-compose.yml`` for running a production Islandora 8 site. you +will use your own image. Please see +[Customizing the Drupal Installation](#customizing-the-drupal-installation) for +instructions on how to do so. + +In addition to the images provided as described in the section +[Docker Images](#docker-images). Several others are used by the +[docker-compose.yml] file. + +### Watchtower + +The [watchtower](https://hub.docker.com/r/v2tec/watchtower/) container monitors +the running Docker containers and watches for changes to the images that those +containers were originally started from. If watchtower detects that an image has +changed, it will automatically restart the container using the new image. This +allows for automatic deployment, and overall faster development time. + +Note however Watchtower will not restart stopped container or containers that +exited due to error. To ensure a container is always running, unless explicitly +stopped, add ``restart: unless-stopped`` property to the container in the +[docker-compose.yml] file. For example: + +```yaml +database: + image: islandora/mariadb:latest + restart: unless-stopped +``` + +### Traefik + +The [traefik](https://containo.us/traefik/) container acts as a reverse proxy, +and exposes some containers through port ``80`` on the localhost via the +[loopback](https://www.tldp.org/LDP/nag/node66.html). This allows access to the +following urls. + +- +- +- +- +- + +Note if you cannot map ``traefik`` to the hosts port 80, you will need to +manually modify your ``/etc/hosts`` file and add entries for each of the urls +above like so, assuming the IP of ``traefik`` container is ``x.x.x.x`` on its +virtual network, and you can access that address from your machine. + +```properties +x.x.x.x activemq.localhost +x.x.x.x blazegraph.localhost +x.x.x.x drupal.localhost +x.x.x.x fcrepo.localhost +x.x.x.x matomo.localhost +``` + +Since Drupal passes its ``Base URL`` along to other services in AS2 as a means +of allowing them to find their way back. As well as having services like Fedora +exposed at the same URL they are accessed by the micro-services to end users. We +need to allow containers within the network to be accessible via the same URL, +though not by routing through ``traefik`` since it is and edge router. + +So alias like the following are defined: + +```yaml +drupal: + image: islandora/sandbox:latest + # ... + networks: + default: + aliases: + - drupal.localhost +``` + +These are set on the ``default`` network as that is the internal network (no +access to the outside) on which all containers reside. + +## ETCD + +The [etcd](https://github.com/etcd-io/etcd) container is a distributed reliable +key-value store, which this project uses for configuration settings and secrets. +Chosen in particular for it's existing integration with +[Kubernetes](https://kubernetes.io/docs/concepts/overview/components/#etcd). + +Alternatively if removed from the [docker-compose.yml] file or explicitly not +started the containers will fall back to pulling configuration from +**environment variables**. + +A convenience script is provided that allows for users to put and get key/values +from the store after it has been started. For example changing the log level of +[houdini](./houdini/README.md) to ``DEBUG``. + +```bash +./commands/etcdctl.sh put /houdini/log/level DEBUG +``` + +Or checking what the current log level is set to (*if not set to the default, in +which case the key/value store is not used*): + +```bash +./commands/etcdctl.sh get /houdini/log/level +``` + +## Customizing the Drupal Installation + +This needs to be thought about more in-depth, and needs fleshing out. Ideally we +will provide the base image for building / deploying the Drupal image. End users +will consume these containers and provide their ``composer.json`` and +``composer.lock`` files, along with the name of the +[Drupal Installation Profile] (either the one we will provide or one they create +on their own). At the moment the [composer](./composer/README.md) project is +provided as an early example of this. Where it user the +``islandora/nginx as compose`` image to perform do the composer installation, +and ``islandora/drupal`` as the container to run the installation created in the +previous step. + +Additionally more documentation is needed to describe how developers can use the +existing images for local development allowing them to create their own +``composer.json`` and ``composer.lock`` files as well as any custom modules, +themes, etc. + +## Design Considerations + +All of the images build by this project are derived from the +[Alpine Docker Image](https://hub.docker.com/_/alpine) which is a Linux +distribution built around ``musl`` ``libc`` and ``BusyBox``. The image is only 5 +MB in size and has access to a package repository. It has been chosen for its +small size, and ease of generating custom packages (as is done in the +[imagemagick](./imagemagick/README.md) image). + +The [base](./base/README.md) image includes two tools essential to the +functioning of all the images. + +- [Confd](https://github.com/kelseyhightower/confd) - Configuration Management +- [S6 Overlay](https://github.com/just-containers/s6-overlay) - Process Manager / Initialization system. + +### Confd + +``confd`` is used for all Configuration Management, it is how images are +customized on startup and during runtime. For each Docker image there will be a +folder ``rootfs/etc/confd`` that has the following layout: + +```bash +./rootfs/etc/confd +├── conf.d +│ └── file.ext.toml +├── confd.toml +└── templates + └── file.ext.tmpl +``` + +``confd.toml`` Is the configuration of ``confd`` and will typically limit the +namespace from which ``confd`` will read key values. For example in ``activemq``: + +```toml +backend = "env" +confdir = "/etc/confd" +log-level = "debug" +interval = 600 +noop = false +prefix = "/activemq" +``` + +The prefix is set to ``/activemq`` which means only keys / value pairs under +this prefix can be used by templates. We restrict images by prefix to force them +to define their own settings, reducing dependencies between images, and to allow +for greater customization. For example you could have Gemini use PostgreSQL as a +backend and Drupal using MariaDB since they do not share the same Database +configuration. + +The ``file.ext.toml`` and ``file.ext.tmpl`` work as a pair where the ``toml`` +file defines where the template will be render to and who owns it, and the +``tmpl`` file being the template in question. Ideally these files should match +the same name of the file they are generating minus the ``toml`` or ``tmpl`` +suffix. This is to make the discovery of them easier. + +### S6 Overlay + +From this tool we only really take advantage of two features: + +- Initialization scripts (*found in ``rootfs/etc/cont-init.d``*) +- Service scripts (*found in ``rootfs/etc/services.d``*) + +Initialization scripts are run when the container is started and they execute in +alphabetical order. So to control the execution order they are prefix with +numbers. + +One initialization script ``01-confd-render-templates.sh`` is shared by all the +images. It does a first past render of the ``confd`` templates so subsequent +scripts can run. The rest of the scripts do the minimal steps required to get +the container into a ready state before the Service scripts start. + +The services scripts have the following structure: + +```bash +./rootfs/etc/services.d +└── SERVICE_NAME + ├── finish + └── run +``` + +The ``run`` script is responsible for starting the service in the +**foreground**. The ``finish`` script can perform any cleanup necessary before +stopping the service, but in general it is used to kill the container, like so: + +```bash +s6-svscanctl -t /var/run/s6/services +``` + +There are only a few Service scripts: + +- activemq +- confd +- fpm +- karaf +- mysqld +- nginx +- solr +- tomcat + +Of these only ``confd`` is running in every container, it periodically listens +for changes in either ``etcd`` or the ``environment variables`` and will +re-render the templates upon any change. + +### Image Hierarchy + +In order to save space and reduce the amount of duplication across images, they +are arranged in a hierarchy, that roughly follows below: + +```bash +├── abuild +│ └── imagemagick +└── base + ├── java + │ ├── activemq + │ ├── karaf + │ │ └── alpaca + │ ├── solr + │ └── tomcat + │ ├── blazegraph + │ ├── cantaloupe + │ ├── fcrepo + │ └── fits + ├── mariadb + └── nginx + ├── composer + ├── crayfish + │ ├── gemini + │ ├── homarus + │ ├── houdini (consumes "imagemagick" as well during its build stage) + │ ├── hypercube + │ ├── milliner + │ └── recast + ├── crayfits + ├── drupal + │ └── sandbox + └── matomo +``` + +[abuild](./abuild/README.md) and [imagemagick](./imagemagick/README.md) stand +outside of the hierarchy as they are use only to build packages that are +consumed by other images during their build stage. + +### Folder Layout + +To make reasoning about what files go where each image follows the same +filesystem layout for copying files into the image. + +A folder called ``rootfs`` maps directly onto the linux filesystem of the final +image. So for example ``rootfs/opt/islandora/configs/jwt`` will be +``/opt/islandora/configs/jwt`` in the generated image. + +### Build System + +Gradle is used as the build system, it is setup such that it will automatically +detect which folders should be considered +[projects](https://docs.gradle.org/current/dsl/org.gradle.api.Project.html) and +what dependencies exist between them. The only caveat is +that the projects cannot be nested, though that use case does not really apply. + +The dependencies are resolved by parsing the Dockerfile and looking for ``FROM`` +statements to determine which images are required to build it. + +This means to add a new Docker image to the project you do not need to modify +the build scripts, simply add a new folder and place your Dockerfile inside of +it and it will be discovered built in the correct order relative to the other +images. + +## Design Constraints + +To be able to support a wide variety of backends for ``confd``, as well as +orchestration tools, all calls to ``getv`` **must provide a default**. With the +exception of keys that do not get used unless defined like +``DRUPAL_SITE_{SITE}_NAME``. This means the whatever backend for configuration, +wether it be ``etcd``, ``consul``, or ``environment variables``, containers can +successfully start without any other container present. + +This does not completely remove dependencies between containers, for example, +when the [sandbox](../docker/sandbox/README.md) starts it requires a running +[fcrepo](../docker/fcrepo/README.md) to be able to ingest nodes created by +``islandora_default`` features. In these cases an initialization script can +block until another container is available or a timeout has been reached. For +example: + +```bash +local fcrepo_host="{{ getv "/fcrepo/host" "fcrepo.localhost" }}" +local fcrepo_port="{{ getv "/fcrepo/host" "80" }}" +local fcrepo_url= + +# Indexing fails if port 80 is given explicitly. +if [[ "${fcrepo_port}" == "80" ]]; then + fcrepo_url="http://${fcrepo_host}/fcrepo/rest/" +else + fcrepo_url="http://${fcrepo_host}:${fcrepo_port}/fcrepo/rest/" +fi + +#... + +# Need access to Solr before we can actually import the right config. +if timeout 300 wait-for-open-port.sh "${fcrepo_host}" "${fcrepo_port}" ; then + echo "Fcrepo Found" +else + echo "Could not connect to Fcrepo" + exit 1 +fi +``` + +This allows container to start up in any order, and to be orchestrated by any tool. + +## Issues / FAQ + +**Question:** I'm getting the following error when building: + +```bash +failed to solve with frontend dockerfile.v0: failed to solve with frontend gateway.v0: runc did not terminate successfully: context canceled +``` + +**Answer:** If possible upgrade Docker to the latest version, and switch to using the +[Overlay2](https://docs.docker.com/storage/storagedriver/overlayfs-driver/#configure-docker-with-the-overlay-or-overlay2-storage-driver) +filesystem with Docker. If that doesn't work trying building [without BuildKit](#building-without-buildkit). + +## To Do + +- Blazegraph isn't working +- Check if Cantaloupe is working +- Add support for multiple backends to fedora (currently only file is being used) +- Confirm all derivative generation is working and check if additional tools + need to be build or custom builds of say `poppler utils` or some other tool, + etc are needed (need to test against a variety of inputs for each mimetype as + there may be some edge case). +- Change public/private key generation to not rely on shared volume use the configuration management +- Do we need to support tls for etcd? Probably not since it shouldn't be exposed outside of the network. Though would be nice. +- Change solr configuration to no rely on shared volume +- Ideally no shared volumes as then container can be more easily moved between nodes in a cluster +- Get working under ECS/EKS +- Get working with Kubernetes with auto scaling for micro-services +- Developer workflow documentation / examples + +[Amazon Elastic Container Service]: https://aws.amazon.com/ecs/ +[Buildkit]: https://github.com/moby/buildkit/blob/master/frontend/dockerfile/docs/experimental.md +[Docker Compose]: https://docs.docker.com/compose/ +[docker-compose.yml]: ./docker-compose.yml +[Drupal Installation Profile]: https://www.drupal.org/docs/8/distributions/creating-distributions/how-to-write-a-drupal-8-installation-profile +[drush]: https://drushcommands.com/ +[etcdctrl]: https://etcd.io/docs/v3.4.0/dev-guide/interacting_v3/ +[Kubernetes]: https://kubernetes.io/ +[mysql]: https://dev.mysql.com/doc/refman/8.0/en/mysql.html diff --git a/abuild/.dockerignore b/abuild/.dockerignore new file mode 100644 index 00000000..b43bf86b --- /dev/null +++ b/abuild/.dockerignore @@ -0,0 +1 @@ +README.md diff --git a/abuild/Dockerfile b/abuild/Dockerfile new file mode 100644 index 00000000..bbe26470 --- /dev/null +++ b/abuild/Dockerfile @@ -0,0 +1,12 @@ +# syntax=docker/dockerfile:experimental +FROM alpine:3.11.6 + +RUN --mount=type=cache,target=/var/cache/apk \ + --mount=type=cache,target=/etc/cache/apk \ + ln -s /var/cache/apk /etc/apk/cache && \ + apk add --update \ + alpine-sdk \ + coreutils \ + && \ + adduser -G abuild -g "Alpine Package Builder" -s /bin/ash -D builder && \ + echo "builder ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers diff --git a/abuild/README.md b/abuild/README.md new file mode 100644 index 00000000..357c4dc0 --- /dev/null +++ b/abuild/README.md @@ -0,0 +1,76 @@ +# ABuild + +Docker image for `abuild` which is a tool used for create `apk` package for +consumption by other docker containers. + +It is not meant to be deployed as a service, but rather as base for when +creating packages as is done in `islandora/imagemagick`. + +Consumers are expected to follow this pattern: + +Create a folder `/build` in the project directory where the `APKBUILD` file +resides (which describes how to compile and build the package). + +Define a docker file that: + +1. Installs the packages required for building (but not necessarily running) the + package. +2. Run `abuild-keygen` to generate a private/public key pair for signing the + package. +3. Run `abuild` to build the package using `APKBUILD`. + +```dockerfile +# syntax=docker/dockerfile:experimental +FROM islandora/abuild:latest + +# Include packages required for building the package (not necessarily the ones require for running). +RUN --mount=type=cache,target=/var/cache/apk \ + --mount=type=cache,target=/etc/cache/apk \ + apk --update add \ + package-require-for-building-1 \ + package-require-for-building-2 \ + +COPY /build /build + +WORKDIR /build + +RUN chown -R builder /build + +ARG PACKAGER="Packer Name " + +USER builder + +RUN export PACKAGER="${PACKAGER}" && \ + abuild-keygen -ain && \ + abuild-apk update && \ + abuild +``` + +Subsequent images which consume the package can then bring it in via a +combination of multi-stage build, and Buildkit bind mounts like so: + +```dockerfile +FROM islandora/package_image:latest as PACKAGE_IMAGE + +FROM islandora/crayfish:latest + +RUN --mount=type=bind,from=PACKAGE_IMAGE,source=/home/builder/packages/x86_64,target=/packages \ + --mount=type=bind,from=PACKAGE_IMAGE,source=/etc/apk/keys,target=/etc/apk/keys \ + --mount=type=cache,target=/root/.composer/cache \ + apk add /packages/PACKAGE_NAME-*.apk && \ + ... other build steps ...&& \ + cleanup.sh +``` + +Where the image is brought in as `PACKAGE_IMAGE` and the directory where the +generated `.pkg` resides as well as the location of `apk` key files are mounted +into the destination image. + +## Dependencies + +Requires `alpine:3.11.6` docker image to build. + +## Reference + +- +- diff --git a/activemq/.dockerignore b/activemq/.dockerignore new file mode 100644 index 00000000..b43bf86b --- /dev/null +++ b/activemq/.dockerignore @@ -0,0 +1 @@ +README.md diff --git a/activemq/Dockerfile b/activemq/Dockerfile new file mode 100644 index 00000000..98ca7c81 --- /dev/null +++ b/activemq/Dockerfile @@ -0,0 +1,20 @@ +# syntax=docker/dockerfile:experimental +FROM local/java:latest + +RUN --mount=id=downloads,type=cache,target=/opt/downloads \ + ACTIVEMQ_VERSION="5.14.5" && \ + install-apache-service.sh \ + --name activemq \ + --version "${ACTIVEMQ_VERSION}" \ + --key "62ED4DF0BACB8793" \ + --mirror "https://archive.apache.org/dist/activemq/${ACTIVEMQ_VERSION}" \ + --file "apache-activemq-${ACTIVEMQ_VERSION}-bin.tar.gz" \ + examples webapps-demo docs + +WORKDIR /opt/activemq + +EXPOSE 61616 5672 61613 1883 61614 8161 + +VOLUME [ "/opt/activemq/data" ] + +COPY rootfs / diff --git a/activemq/README.md b/activemq/README.md new file mode 100644 index 00000000..b7621ed0 --- /dev/null +++ b/activemq/README.md @@ -0,0 +1,94 @@ +# ActiveMQ + +Docker image for [ActiveMQ] version 5.14.5. + +Please refer to the [ActiveMQ Documentation] for more in-depth information. + +As a quick example this will bring up an instance of ActiveMQ, and allow you to +log into the [WebConsole] on `http://localhost:8161` as the user `admin` with +the password `password`. + +```bash +docker run --rm -ti -p 8161:8161 islandora/activemq +``` + +> N.B. if no credentials are given you will not be able to log in via the +[WebConsole]. + +## Dependencies + +Requires `islandora/java` docker image to build. Please refer to the +[Java Image README](../java/README.md) for additional information including +additional settings, volumes, ports, etc. + +## Ports + +| Port | Description | +| :---- | :----------- | +| 1883 | [MQTT] | +| 5672 | [AMPQ] | +| 8161 | [WebConsole] | +| 61613 | [STOMP] | +| 61614 | [WS] | +| 61616 | [OpenWire] | + +## Volumes + +| Path | Description | +| :----------------- | :------------------ | +| /opt/activemq/data | [AMQ Message Store] | + +## Settings + +| Environment Variable | Etcd Key | Default | Description | +| :-------------------------- | :--------------------------- | :------- | :--------------------------------------- | +| ACTIVEMQ_USER | /activemq/user | admin | See [Security]: credentials.properties | +| ACTIVEMQ_PASSWORD | /activemq/password | password | See [Security]: credentials.properties | +| ACTIVEMQ_WEB_ADMIN_NAME | /activemq/web/admin/name | admin | See [WebConsole]: jetty-realm.properties | +| ACTIVEMQ_WEB_ADMIN_PASSWORD | /activemq/web/admin/password | password | See [WebConsole]: jetty-realm.properties | +| ACTIVEMQ_WEB_ADMIN_ROLES | /activemq/web/admin/roles | admin | See [WebConsole]: jetty-realm.properties | + +Additional users/groups/etc can be defined by adding more environment variables, +following the above conventions: + +| Environment Variable | Etcd Key | Description | +| :-------------------------------- | :--------------------------------- | :--------------------------------------- | +| ACTIVEMQ_USER_{USER}_NAME | /activemq/user/{USER}/name | See [Security]: users.properties | +| ACTIVEMQ_USER_{USER}_PASSWORD | /activemq/user/{USER}/password | See [Security]: users.properties | +| ACTIVEMQ_GROUP_{GROUP}_NAME | /activemq/group/{GROUP}/name | See [Security]: groups.properties | +| ACTIVEMQ_GROUP_{GROUP}_MEMBERS | /activemq/group/{GROUP}/members | See [Security]: groups.properties | +| ACTIVEMQ_WEB_USER_{USER}_NAME | /activemq/web/user/{USER}/name | See [WebConsole]: jetty-realm.properties | +| ACTIVEMQ_WEB_USER_{USER}_PASSWORD | /activemq/web/user/{USER}/password | See [WebConsole]: jetty-realm.properties | +| ACTIVEMQ_WEB_USER_{USER}_ROLES | /activemq/web/user/{USER}/roles | See [WebConsole]: jetty-realm.properties | + +> N.B. These do not have defaults. + +For example to add a new user `someone` to the [WebConsole] you would need to +define the following: + +| Environment Variable | Etcd Key | Value | +| :--------------------------------- | :---------------------------------- | :------- | +| ACTIVEMQ_WEB_USER_SOMEONE_NAME | /activemq/web/user/someone/name | someone | +| ACTIVEMQ_WEB_USER_SOMEONE_PASSWORD | /activemq/web/user/someone/password | password | +| ACTIVEMQ_WEB_USER_SOMEONE_ROLES | /activemq/web/user/someone/roles | admin | + +## Logs + +| Path | Description | +| :------------------------------ | :------------- | +| STDOUT | [ActiveMQ Log] | +| /opt/activemq/data/activemq.log | [ActiveMQ Log] | +| /opt/activemq/data/audit.log | [Audit Log] | + +[ActiveMQ Documentation]: https://activemq.apache.org/components/classic/documentation +[ActiveMQ Log]: https://activemq.apache.org/how-do-i-change-the-logging +[ActiveMQ]: http://activemq.apache.org/ +[AMPQ]: https://activemq.apache.org/amqp +[AMQ Message Store]: https://activemq.apache.org/amq-message-store +[Audit Log]: https://activemq.apache.org/audit-logging +[MQTT]: https://activemq.apache.org/mqtt +[OpenWire]: https://activemq.apache.org/openwire +[Security]: https://activemq.apache.org/security +[STOMP]: https://activemq.apache.org/stomp +[WebConsole]: https://activemq.apache.org/web-console +[WS]: https://activemq.apache.org/ws-notification diff --git a/activemq/rootfs/etc/confd/conf.d/credentials.properties.toml b/activemq/rootfs/etc/confd/conf.d/credentials.properties.toml new file mode 100644 index 00000000..8db2948b --- /dev/null +++ b/activemq/rootfs/etc/confd/conf.d/credentials.properties.toml @@ -0,0 +1,7 @@ +[template] +src = "credentials.properties.tmpl" +dest = "/opt/activemq/conf/credentials.properties" +uid = 100 +gid = 1000 +mode = "0640" +keys = [ "/user", "/password" ] diff --git a/activemq/rootfs/etc/confd/conf.d/groups.properties.toml b/activemq/rootfs/etc/confd/conf.d/groups.properties.toml new file mode 100644 index 00000000..beb212b3 --- /dev/null +++ b/activemq/rootfs/etc/confd/conf.d/groups.properties.toml @@ -0,0 +1,7 @@ +[template] +src = "groups.properties.tmpl" +dest = "/opt/activemq/conf/groups.properties" +uid = 100 +gid = 1000 +mode = "0640" +keys = [ "/group" ] diff --git a/activemq/rootfs/etc/confd/conf.d/jetty-realm.properties.toml b/activemq/rootfs/etc/confd/conf.d/jetty-realm.properties.toml new file mode 100644 index 00000000..d58f38a1 --- /dev/null +++ b/activemq/rootfs/etc/confd/conf.d/jetty-realm.properties.toml @@ -0,0 +1,7 @@ +[template] +src = "jetty-realm.properties.tmpl" +dest = "/opt/activemq/conf/jetty-realm.properties" +uid = 100 +gid = 1000 +mode = "0640" +keys = [ "/web/user" ] diff --git a/activemq/rootfs/etc/confd/conf.d/users.properties.toml b/activemq/rootfs/etc/confd/conf.d/users.properties.toml new file mode 100644 index 00000000..6adc80b9 --- /dev/null +++ b/activemq/rootfs/etc/confd/conf.d/users.properties.toml @@ -0,0 +1,7 @@ +[template] +src = "users.properties.tmpl" +dest = "/opt/activemq/conf/users.properties" +uid = 100 +gid = 1000 +mode = "0640" +keys = [ "/user" ] diff --git a/activemq/rootfs/etc/confd/confd.toml b/activemq/rootfs/etc/confd/confd.toml new file mode 100644 index 00000000..bbfe3bbc --- /dev/null +++ b/activemq/rootfs/etc/confd/confd.toml @@ -0,0 +1,6 @@ +backend = "env" +confdir = "/etc/confd" +log-level = "debug" +interval = 600 +noop = false +prefix = "/activemq" diff --git a/activemq/rootfs/etc/confd/templates/credentials.properties.tmpl b/activemq/rootfs/etc/confd/templates/credentials.properties.tmpl new file mode 100644 index 00000000..fdc94116 --- /dev/null +++ b/activemq/rootfs/etc/confd/templates/credentials.properties.tmpl @@ -0,0 +1,3 @@ +# Defines credentials that will be used by components (like web console) to access the broker +activemq.username={{ getv "/user" "admin" }} +activemq.password={{ getv "/password" "password" }} diff --git a/activemq/rootfs/etc/confd/templates/groups.properties.tmpl b/activemq/rootfs/etc/confd/templates/groups.properties.tmpl new file mode 100644 index 00000000..ef272b95 --- /dev/null +++ b/activemq/rootfs/etc/confd/templates/groups.properties.tmpl @@ -0,0 +1,4 @@ +# Defines groups and the users that belong to them. +# group=user[,user ...] +{{ range $dir := lsdir "/group" }}{{ getv (printf "/group/%s/name" $dir) }}={{ getv (printf "/group/%s/members" $dir) }} +{{ end }} diff --git a/activemq/rootfs/etc/confd/templates/jetty-realm.properties.tmpl b/activemq/rootfs/etc/confd/templates/jetty-realm.properties.tmpl new file mode 100644 index 00000000..f1c6291a --- /dev/null +++ b/activemq/rootfs/etc/confd/templates/jetty-realm.properties.tmpl @@ -0,0 +1,5 @@ +# Defines users that can access the web (console, demo, etc.) +# username: password [,rolename ...] +{{ getv "/web/admin/name" "admin" }}: {{ getv "/web/admin/password" "password" }}, {{ getv "/web/admin/roles" "admin" }} +{{ range $dir := lsdir "/web/user" }}{{ getv (printf "/web/user/%s/name" $dir) }}: {{ getv (printf "/web/user/%s/password" $dir) }}, {{ getv (printf "/web/user/%s/roles" $dir) }} +{{ end }} diff --git a/activemq/rootfs/etc/confd/templates/users.properties.tmpl b/activemq/rootfs/etc/confd/templates/users.properties.tmpl new file mode 100644 index 00000000..b44780bf --- /dev/null +++ b/activemq/rootfs/etc/confd/templates/users.properties.tmpl @@ -0,0 +1,2 @@ +{{ range $dir := lsdir "/user" }}{{ getv (printf "/user/%s/name" $dir) }}={{ getv (printf "/user/%s/password" $dir) }} +{{ end }} diff --git a/activemq/rootfs/etc/services.d/activemq/finish b/activemq/rootfs/etc/services.d/activemq/finish new file mode 100644 index 00000000..f8984dd3 --- /dev/null +++ b/activemq/rootfs/etc/services.d/activemq/finish @@ -0,0 +1,4 @@ +#!/usr/bin/execlineb -S1 +# -*- mode: sh -*- +# vi: set ft=sh : +s6-svscanctl -t /var/run/s6/services diff --git a/activemq/rootfs/etc/services.d/activemq/run b/activemq/rootfs/etc/services.d/activemq/run new file mode 100644 index 00000000..1c175abc --- /dev/null +++ b/activemq/rootfs/etc/services.d/activemq/run @@ -0,0 +1,6 @@ +#!/usr/bin/execlineb -P +# -*- mode: sh -*- +# vi: set ft=sh : +with-contenv +s6-setuidgid activemq +/opt/activemq/bin/activemq console diff --git a/alpaca/.dockerignore b/alpaca/.dockerignore new file mode 100644 index 00000000..b43bf86b --- /dev/null +++ b/alpaca/.dockerignore @@ -0,0 +1 @@ +README.md diff --git a/alpaca/Dockerfile b/alpaca/Dockerfile new file mode 100644 index 00000000..0d983e17 --- /dev/null +++ b/alpaca/Dockerfile @@ -0,0 +1,43 @@ +# syntax=docker/dockerfile:experimental +FROM local/karaf:latest + +# Install common features and repos +RUN bin/start && \ + ALPACA_VERSION=1.0.3 && \ + ACTIVEMQ_VERSION=5.15.0 && \ + CAMEL_VERSION=2.20.4 && \ + bin/client -r 10 -d 5 "feature:repo-add mvn:ca.islandora.alpaca/islandora-karaf/${ALPACA_VERSION}/xml/features" && \ + bin/client -r 10 -d 5 "feature:repo-add mvn:org.apache.activemq/activemq-karaf/${ACTIVEMQ_VERSION}/xml/features" && \ + bin/client -r 10 -d 5 "feature:repo-add mvn:org.apache.camel.karaf/apache-camel/${CAMEL_VERSION}/xml/features" && \ + bin/client -r 10 -d 5 "feature:install fcrepo-service-activemq" && \ + bin/client -r 10 -d 5 "feature:install fcrepo-service-camel" && \ + bin/client -r 10 -d 5 "feature:install islandora-http-client" && \ + bin/stop && \ + rm -rf instances/* + +# Derivative connector +RUN bin/start && \ + bin/client -r 10 -d 5 "feature:install islandora-connector-derivative" && \ + bin/stop && \ + rm -rf instances/* + +# Fcrepo indexing THIS IS THE PROBLEM +RUN bin/start && \ + bin/client -r 10 -d 5 "feature:install islandora-indexing-fcrepo" && \ + bin/stop && \ + rm -rf instances/* + +# Triple indexing +RUN bin/start && \ + bin/client -r 10 -d 5 "feature:install fcrepo-indexing-triplestore" && \ + bin/client -r 10 -d 5 "feature:install islandora-indexing-triplestore" && \ + bin/stop && \ + rm -rf instances/* + +RUN chown -R karaf:karaf /opt/karaf + +COPY rootfs / + +VOLUME [ "/opt/karaf/data/" ] + +ENV JAVA_OPTS="-Dfile.encoding=UTF-8 -Dnet.sf.ehcache.skipUpdateCheck=true -XX:+UseConcMarkSweepGC -XX:+CMSClassUnloadingEnabled -XX:+UseParNewGC -XX:MaxPermSize=128m -Xms512m -Xmx8g" \ No newline at end of file diff --git a/alpaca/README.md b/alpaca/README.md new file mode 100644 index 00000000..6fb02361 --- /dev/null +++ b/alpaca/README.md @@ -0,0 +1,79 @@ +# Alpaca + +Docker image for [Alpaca] version 1.0.3. + +Please refer to the [Alpaca Documentation] for more in-depth information. + +As a quick example this will bring up an instance of Alpaca, and allow you to +log view the [WebConsole] on as the user `admin` with +the password `password`. + +```bash +docker run --rm -ti -p 8181:8181 \ + -e "KARAF_ADMIN_NAME=admin" \ + -e "KARAF_ADMIN_PASSWORD=password" \ + islandora/alpaca +``` + +## Dependencies + +Requires `islandora/karaf` docker image to build. Please refer to the +[Karaf Image README](../karaf/README.md) for additional information including +additional settings, volumes, ports, etc. + +## Settings + +| Environment Variable | Etcd Key | Default | Description | +| :----------------------------------------- | :----------------------------------------- | :-------------------------------------------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------- | +| ALPACA_ACTIVEMQ_PASSWORD | /alpaca/activemq/password | password | Password to authenticate with | +| ALPACA_ACTIVEMQ_URL | /alpaca/activemq/url | tcp://broker:61616 | The url for connecting to the ActiveMQ broker, shared by all components | +| ALPACA_ACTIVEMQ_USER | /alpaca/activemq/user | admin | User to authenticate as | +| ALPACA_FCREPO_AUTH_HOST | /alpaca/fcrepo/auth/host | | User to authenticate as | +| ALPACA_FCREPO_AUTH_PASSWORD | /alpaca/fcrepo/auth/password | | Password to authenticate with | +| ALPACA_FCREPO_AUTH_USER | /alpaca/fcrepo/auth/user | | URL to authenticate against | +| ALPACA_FCREPO_URL | /alpaca/fcrepo/url | http://fcrepo/fcrepo/rest | The url of fcrepo rest API | +| ALPACA_FITS_QUEUE | /alpaca/fits/queue | broker:queue:islandora-connector-fits | ActiveMQ Queue to consume from | +| ALPACA_FITS_REDELIVERIES | /alpaca/fits/redeliveries | 10 | Number of attempts to redeliver if an exception occurs | +| ALPACA_FITS_SERVICE | /alpaca/fits/service | http://crayfits:8000 | Url of micro-service | +| ALPACA_HOMARUS_QUEUE | /alpaca/homarus/queue | broker:queue:islandora-connector-homarus | ActiveMQ Queue to consume from | +| ALPACA_HOMARUS_REDELIVERIES | /alpaca/homarus/redeliveries | 10 | Number of attempts to redeliver if an exception occurs | +| ALPACA_HOMARUS_SERVICE | /alpaca/homarus/service | http://homarus:8000/convert | Url of micro-service | +| ALPACA_HOUDINI_QUEUE | /alpaca/houdini/queue | broker:queue:islandora-connector-houdini | ActiveMQ Queue to consume from | +| ALPACA_HOUDINI_REDELIVERIES | /alpaca/houdini/redeliveries | 10 | Number of attempts to redeliver if an exception occurs | +| ALPACA_HOUDINI_SERVICE | /alpaca/houdini/service | http://houdini:8000/convert | Url of micro-service | +| ALPACA_HTTP_TOKEN | /alpaca/http/token | islandora | The static token value to be used for authentication by the HttpClient available as an OSGi service for other services to use against the Fedora repository | +| ALPACA_INDEXING_GEMINI_URL | /alpaca/indexing/gemini/url | http://gemini:8000 | Url of micro-service | +| ALPACA_INDEXING_MILLINER_URL | /alpaca/indexing/milliner/url | http://milliner:8000 | Url of micro-service | +| ALPACA_INDEXING_REDELIVERIES | /alpaca/indexing/redeliveries | 10 | Number of attempts to redeliver if an exception occurs | +| ALPACA_INDEXING_STREAM_FILE_DELETE | /alpaca/indexing/stream/file/delete | broker:queue:islandora-indexing-fcrepo-file-delete | ActiveMQ Queue to consume from | +| ALPACA_INDEXING_STREAM_FILE_INDEX | /alpaca/indexing/stream/file/index | broker:queue:islandora-indexing-fcrepo-file | ActiveMQ Queue to consume from | +| ALPACA_INDEXING_STREAM_INPUT | /alpaca/indexing/stream/input | broker:topic:fedora | ActiveMQ Topic to consume | +| ALPACA_INDEXING_STREAM_MEDIA_INDEX | /alpaca/indexing/stream/media/index | broker:queue:islandora-indexing-fcrepo-media | ActiveMQ Queue to consume from | +| ALPACA_INDEXING_STREAM_NODE_DELETE | /alpaca/indexing/stream/node/delete | broker:queue:islandora-indexing-fcrepo-delete | ActiveMQ Queue to consume from | +| ALPACA_INDEXING_STREAM_NODE_INDEX | /alpaca/indexing/stream/node/index | broker:queue:islandora-indexing-fcrepo-content | ActiveMQ Queue to consume from | +| ALPACA_INDEXING_STREAM_TRIPLESTORE_DELETE | /alpaca/indexing/stream/triplestore/delete | broker:queue:islandora-indexing-triplestore-delete | ActiveMQ Queue to consume from | +| ALPACA_INDEXING_STREAM_TRIPLESTORE_INDEX | /alpaca/indexing/stream/triplestore/index | broker:queue:islandora-indexing-triplestore-index | ActiveMQ Queue to consume from | +| ALPACA_INDEXING_STREAM_TRIPLESTORE_REINDEX | /alpaca/indexing/stream/reindex | broker:queue:triplestore.reindex | ActiveMQ Queue to consume from | +| ALPACA_INDEXING_URL | /alpaca/indexing/url | http://blazegraph/bigdata/namespace/islandora/sparql | Url to triple store indexer | +| ALPACA_LOGGER_CAMEL_LEVEL | /alpaca/logger/camel/level | WARN | Camel [Log Level] | +| ALPACA_LOGGER_ISLANDORA_LEVEL | /alpaca/logger/islandora/level | WARN | Islandora [Log Level] | +| ALPACA_LOGGER_ROOT_LEVEL | /alpaca/logger/root/level | WARN | Root [Log Level] | +| ALPACA_OCR_QUEUE | /alpaca/ocr/queue | broker:queue:islandora-connector-ocr | ActiveMQ Queue to consume from | +| ALPACA_OCR_REDELIVERIES | /alpaca/ocr/redeliveries | 10 | Number of attempts to redeliver if an exception occurs | +| ALPACA_OCR_SERVICE | /alpaca/ocr/service | http://hypercube:8000 | Url of micro-service | + +## Logs + +| Path | Description | +| :-------------------------------- | :--------------- | +| /opt/karaf/data/log/camel.log | Camel Log | +| /opt/karaf/data/log/islandora.log | Islandora Log | + +[Alpaca Documentation]: https://islandora.github.io/documentation/ +[Alpaca]: https://github.com/Islandora/Alpaca +[JMX]: https://karaf.apache.org/manual/latest/#_monitoring_and_management_using_jmx +[Karaf Directory Structure]: https://karaf.apache.org/manual/latest/#_directory_structure +[Log Level]: https://logging.apache.org/log4j/2.x/manual/customloglevels.html +[RMI]: https://karaf.apache.org/manual/latest/monitoring +[SSH]: https://karaf.apache.org/manual/latest/remote +[WebConsole]: https://karaf.apache.org/manual/latest/webconsole diff --git a/alpaca/rootfs/etc/confd/conf.d/ca.islandora.alpaca.connector.fits.blueprint.xml.toml b/alpaca/rootfs/etc/confd/conf.d/ca.islandora.alpaca.connector.fits.blueprint.xml.toml new file mode 100644 index 00000000..3e24c34e --- /dev/null +++ b/alpaca/rootfs/etc/confd/conf.d/ca.islandora.alpaca.connector.fits.blueprint.xml.toml @@ -0,0 +1,7 @@ +[template] +src = "ca.islandora.alpaca.connector.fits.blueprint.xml.tmpl" +dest = "/opt/karaf/deploy/ca.islandora.alpaca.connector.fits.blueprint.xml" +uid = 100 +gid = 1000 +mode = "0644" +keys = [ "/fits" ] diff --git a/alpaca/rootfs/etc/confd/conf.d/ca.islandora.alpaca.connector.homarus.blueprint.xml.toml b/alpaca/rootfs/etc/confd/conf.d/ca.islandora.alpaca.connector.homarus.blueprint.xml.toml new file mode 100644 index 00000000..708413b4 --- /dev/null +++ b/alpaca/rootfs/etc/confd/conf.d/ca.islandora.alpaca.connector.homarus.blueprint.xml.toml @@ -0,0 +1,7 @@ +[template] +src = "ca.islandora.alpaca.connector.homarus.blueprint.xml.tmpl" +dest = "/opt/karaf/deploy/ca.islandora.alpaca.connector.homarus.blueprint.xml" +uid = 100 +gid = 1000 +mode = "0644" +keys = [ "/homarus" ] diff --git a/alpaca/rootfs/etc/confd/conf.d/ca.islandora.alpaca.connector.houdini.blueprint.xml.toml b/alpaca/rootfs/etc/confd/conf.d/ca.islandora.alpaca.connector.houdini.blueprint.xml.toml new file mode 100644 index 00000000..2dcba334 --- /dev/null +++ b/alpaca/rootfs/etc/confd/conf.d/ca.islandora.alpaca.connector.houdini.blueprint.xml.toml @@ -0,0 +1,7 @@ +[template] +src = "ca.islandora.alpaca.connector.houdini.blueprint.xml.tmpl" +dest = "/opt/karaf/deploy/ca.islandora.alpaca.connector.houdini.blueprint.xml" +uid = 100 +gid = 1000 +mode = "0644" +keys = [ "/houdini" ] diff --git a/alpaca/rootfs/etc/confd/conf.d/ca.islandora.alpaca.connector.ocr.blueprint.xml.toml b/alpaca/rootfs/etc/confd/conf.d/ca.islandora.alpaca.connector.ocr.blueprint.xml.toml new file mode 100644 index 00000000..e75d086e --- /dev/null +++ b/alpaca/rootfs/etc/confd/conf.d/ca.islandora.alpaca.connector.ocr.blueprint.xml.toml @@ -0,0 +1,7 @@ +[template] +src = "ca.islandora.alpaca.connector.ocr.blueprint.xml.tmpl" +dest = "/opt/karaf/deploy/ca.islandora.alpaca.connector.ocr.blueprint.xml" +uid = 100 +gid = 1000 +mode = "0644" +keys = [ "/ocr" ] diff --git a/alpaca/rootfs/etc/confd/conf.d/ca.islandora.alpaca.http.client.cfg.toml b/alpaca/rootfs/etc/confd/conf.d/ca.islandora.alpaca.http.client.cfg.toml new file mode 100644 index 00000000..24b552e6 --- /dev/null +++ b/alpaca/rootfs/etc/confd/conf.d/ca.islandora.alpaca.http.client.cfg.toml @@ -0,0 +1,7 @@ +[template] +src = "ca.islandora.alpaca.http.client.cfg.tmpl" +dest = "/opt/karaf/etc/ca.islandora.alpaca.http.client.cfg" +uid = 100 +gid = 1000 +mode = "0644" +keys = [ "/http" ] diff --git a/alpaca/rootfs/etc/confd/conf.d/ca.islandora.alpaca.indexing.fcrepo.cfg.toml b/alpaca/rootfs/etc/confd/conf.d/ca.islandora.alpaca.indexing.fcrepo.cfg.toml new file mode 100644 index 00000000..43f1825b --- /dev/null +++ b/alpaca/rootfs/etc/confd/conf.d/ca.islandora.alpaca.indexing.fcrepo.cfg.toml @@ -0,0 +1,7 @@ +[template] +src = "ca.islandora.alpaca.indexing.fcrepo.cfg.tmpl" +dest = "/opt/karaf/etc/ca.islandora.alpaca.indexing.fcrepo.cfg" +uid = 100 +gid = 1000 +mode = "0644" +keys = [ "/indexing" ] diff --git a/alpaca/rootfs/etc/confd/conf.d/ca.islandora.alpaca.indexing.triplestore.cfg.toml b/alpaca/rootfs/etc/confd/conf.d/ca.islandora.alpaca.indexing.triplestore.cfg.toml new file mode 100644 index 00000000..6cdc21e5 --- /dev/null +++ b/alpaca/rootfs/etc/confd/conf.d/ca.islandora.alpaca.indexing.triplestore.cfg.toml @@ -0,0 +1,7 @@ +[template] +src = "ca.islandora.alpaca.indexing.triplestore.cfg.tmpl" +dest = "/opt/karaf/etc/ca.islandora.alpaca.indexing.triplestore.cfg" +uid = 100 +gid = 1000 +mode = "0644" +keys = [ "/indexing" ] diff --git a/alpaca/rootfs/etc/confd/conf.d/org.fcrepo.camel.indexing.triplestore.cfg.toml b/alpaca/rootfs/etc/confd/conf.d/org.fcrepo.camel.indexing.triplestore.cfg.toml new file mode 100644 index 00000000..92385107 --- /dev/null +++ b/alpaca/rootfs/etc/confd/conf.d/org.fcrepo.camel.indexing.triplestore.cfg.toml @@ -0,0 +1,7 @@ +[template] +src = "org.fcrepo.camel.indexing.triplestore.cfg.tmpl" +dest = "/opt/karaf/etc/org.fcrepo.camel.indexing.triplestore.cfg" +uid = 100 +gid = 1000 +mode = "0644" +keys = [ "/indexing" ] diff --git a/alpaca/rootfs/etc/confd/conf.d/org.fcrepo.camel.service.activemq.cfg.toml b/alpaca/rootfs/etc/confd/conf.d/org.fcrepo.camel.service.activemq.cfg.toml new file mode 100644 index 00000000..393f8cc1 --- /dev/null +++ b/alpaca/rootfs/etc/confd/conf.d/org.fcrepo.camel.service.activemq.cfg.toml @@ -0,0 +1,7 @@ +[template] +src = "org.fcrepo.camel.service.activemq.cfg.tmpl" +dest = "/opt/karaf/etc/org.fcrepo.camel.service.activemq.cfg" +uid = 100 +gid = 1000 +mode = "0644" +keys = [ "/activemq" ] diff --git a/alpaca/rootfs/etc/confd/conf.d/org.fcrepo.camel.service.cfg.toml b/alpaca/rootfs/etc/confd/conf.d/org.fcrepo.camel.service.cfg.toml new file mode 100644 index 00000000..35c2a5e5 --- /dev/null +++ b/alpaca/rootfs/etc/confd/conf.d/org.fcrepo.camel.service.cfg.toml @@ -0,0 +1,7 @@ +[template] +src = "org.fcrepo.camel.service.cfg.tmpl" +dest = "/opt/karaf/etc/org.fcrepo.camel.service.cfg" +uid = 100 +gid = 1000 +mode = "0644" +keys = [ "/fcrepo" ] diff --git a/alpaca/rootfs/etc/confd/conf.d/org.ops4j.pax.logging.cfg.toml b/alpaca/rootfs/etc/confd/conf.d/org.ops4j.pax.logging.cfg.toml new file mode 100644 index 00000000..c6fa6d91 --- /dev/null +++ b/alpaca/rootfs/etc/confd/conf.d/org.ops4j.pax.logging.cfg.toml @@ -0,0 +1,7 @@ +[template] +src = "org.ops4j.pax.logging.cfg.tmpl" +dest = "/opt/karaf/etc/org.ops4j.pax.logging.cfg" +uid = 100 +gid = 1000 +mode = "0644" +keys = [ "/log" ] diff --git a/alpaca/rootfs/etc/confd/confd.toml b/alpaca/rootfs/etc/confd/confd.toml new file mode 100644 index 00000000..0415e04e --- /dev/null +++ b/alpaca/rootfs/etc/confd/confd.toml @@ -0,0 +1,6 @@ +backend = "env" +confdir = "/etc/confd" +log-level = "debug" +interval = 600 +noop = false +prefix = "/alpaca" diff --git a/alpaca/rootfs/etc/confd/templates/ca.islandora.alpaca.connector.fits.blueprint.xml.tmpl b/alpaca/rootfs/etc/confd/templates/ca.islandora.alpaca.connector.fits.blueprint.xml.tmpl new file mode 100644 index 00000000..0cd13abf --- /dev/null +++ b/alpaca/rootfs/etc/confd/templates/ca.islandora.alpaca.connector.fits.blueprint.xml.tmpl @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + ca.islandora.alpaca.connector.derivative + + + diff --git a/alpaca/rootfs/etc/confd/templates/ca.islandora.alpaca.connector.homarus.blueprint.xml.tmpl b/alpaca/rootfs/etc/confd/templates/ca.islandora.alpaca.connector.homarus.blueprint.xml.tmpl new file mode 100644 index 00000000..e2bbc7e8 --- /dev/null +++ b/alpaca/rootfs/etc/confd/templates/ca.islandora.alpaca.connector.homarus.blueprint.xml.tmpl @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + ca.islandora.alpaca.connector.derivative + + + diff --git a/alpaca/rootfs/etc/confd/templates/ca.islandora.alpaca.connector.houdini.blueprint.xml.tmpl b/alpaca/rootfs/etc/confd/templates/ca.islandora.alpaca.connector.houdini.blueprint.xml.tmpl new file mode 100644 index 00000000..3c919de9 --- /dev/null +++ b/alpaca/rootfs/etc/confd/templates/ca.islandora.alpaca.connector.houdini.blueprint.xml.tmpl @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + ca.islandora.alpaca.connector.derivative + + + diff --git a/alpaca/rootfs/etc/confd/templates/ca.islandora.alpaca.connector.ocr.blueprint.xml.tmpl b/alpaca/rootfs/etc/confd/templates/ca.islandora.alpaca.connector.ocr.blueprint.xml.tmpl new file mode 100644 index 00000000..19e67394 --- /dev/null +++ b/alpaca/rootfs/etc/confd/templates/ca.islandora.alpaca.connector.ocr.blueprint.xml.tmpl @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + ca.islandora.alpaca.connector.derivative + + + diff --git a/alpaca/rootfs/etc/confd/templates/ca.islandora.alpaca.http.client.cfg.tmpl b/alpaca/rootfs/etc/confd/templates/ca.islandora.alpaca.http.client.cfg.tmpl new file mode 100644 index 00000000..c1a25f04 --- /dev/null +++ b/alpaca/rootfs/etc/confd/templates/ca.islandora.alpaca.http.client.cfg.tmpl @@ -0,0 +1 @@ +token.value={{ getv "/http/token" "islandora" }} diff --git a/alpaca/rootfs/etc/confd/templates/ca.islandora.alpaca.indexing.fcrepo.cfg.tmpl b/alpaca/rootfs/etc/confd/templates/ca.islandora.alpaca.indexing.fcrepo.cfg.tmpl new file mode 100644 index 00000000..49a7e682 --- /dev/null +++ b/alpaca/rootfs/etc/confd/templates/ca.islandora.alpaca.indexing.fcrepo.cfg.tmpl @@ -0,0 +1,8 @@ +error.maxRedeliveries={{ getv "/indexing/redeliveries" "10" }} +file.delete.stream={{ getv "/indexing/stream/file/delete" "broker:queue:islandora-indexing-fcrepo-file-delete" }} +file.stream={{ getv "/indexing/stream/file/index" "broker:queue:islandora-indexing-fcrepo-file" }} +gemini.baseUrl={{ getv "/indexing/gemini/url" "http://gemini:8000" }} +media.stream={{ getv "/indexing/stream/media/index" "broker:queue:islandora-indexing-fcrepo-media" }} +milliner.baseUrl={{ getv "/indexing/milliner/url" "http://milliner:8000" }} +node.delete.stream={{ getv "/indexing/stream/node/delete" "broker:queue:islandora-indexing-fcrepo-delete" }} +node.stream={{ getv "/indexing/stream/node/index" "broker:queue:islandora-indexing-fcrepo-content" }} diff --git a/alpaca/rootfs/etc/confd/templates/ca.islandora.alpaca.indexing.triplestore.cfg.tmpl b/alpaca/rootfs/etc/confd/templates/ca.islandora.alpaca.indexing.triplestore.cfg.tmpl new file mode 100644 index 00000000..aa09e7a2 --- /dev/null +++ b/alpaca/rootfs/etc/confd/templates/ca.islandora.alpaca.indexing.triplestore.cfg.tmpl @@ -0,0 +1,4 @@ +index.stream={{ getv "/indexing/stream/triplestore/index" "broker:queue:islandora-indexing-triplestore-index" }} +delete.stream={{ getv "/indexing/stream/triplestore/delete" "broker:queue:islandora-indexing-triplestore-delete" }} +triplestore.baseUrl={{ getv "/indexing/url" "http://blazegraph/bigdata/namespace/islandora/sparql" }} +error.maxRedeliveries={{ getv "/indexing/redeliveries" "10" }} diff --git a/alpaca/rootfs/etc/confd/templates/org.fcrepo.camel.indexing.triplestore.cfg.tmpl b/alpaca/rootfs/etc/confd/templates/org.fcrepo.camel.indexing.triplestore.cfg.tmpl new file mode 100644 index 00000000..5d6003cc --- /dev/null +++ b/alpaca/rootfs/etc/confd/templates/org.fcrepo.camel.indexing.triplestore.cfg.tmpl @@ -0,0 +1,3 @@ +input.stream={{ getv "/indexing/stream/input" "broker:topic:fedora"}} +triplestore.baseUrl={{ getv "/indexing/url" "http://blazegraph/bigdata/namespace/islandora/sparql" }} +triplestore.reindex.stream={{ getv "/indexing/stream/triplestore/reindex" "broker:queue:triplestore.reindex" }} diff --git a/alpaca/rootfs/etc/confd/templates/org.fcrepo.camel.service.activemq.cfg.tmpl b/alpaca/rootfs/etc/confd/templates/org.fcrepo.camel.service.activemq.cfg.tmpl new file mode 100644 index 00000000..c2e28736 --- /dev/null +++ b/alpaca/rootfs/etc/confd/templates/org.fcrepo.camel.service.activemq.cfg.tmpl @@ -0,0 +1,6 @@ +# The JMS connection URI, used for connecting to a local or remote ActiveMQ broker +jms.brokerUrl={{ getv "/activemq/url" "tcp://activemq:61616" }} + +# If authentication is enabled on the activemq broker, add appropriate values here +jms.username={{ getv "/activemq/user" "" }} +jms.password={{ getv "/activemq/password" "" }} diff --git a/alpaca/rootfs/etc/confd/templates/org.fcrepo.camel.service.cfg.tmpl b/alpaca/rootfs/etc/confd/templates/org.fcrepo.camel.service.cfg.tmpl new file mode 100644 index 00000000..c5e1f646 --- /dev/null +++ b/alpaca/rootfs/etc/confd/templates/org.fcrepo.camel.service.cfg.tmpl @@ -0,0 +1,7 @@ +# The baseUrl for the fedora repository. +fcrepo.baseUrl={{ getv "/fcrep/url" "http://fcrepo/fcrepo/rest" }} + +# If authentication is enabled on the Fedora repository, add appropriate values here +fcrepo.authUsername={{ getv "/fcrep/auth/user" "" }} +fcrepo.authPassword={{ getv "/fcrep/auth/password" "" }} +fcrepo.authHost={{ getv "/fcrep/host" "" }} diff --git a/alpaca/rootfs/etc/confd/templates/org.ops4j.pax.logging.cfg.tmpl b/alpaca/rootfs/etc/confd/templates/org.ops4j.pax.logging.cfg.tmpl new file mode 100644 index 00000000..31c51588 --- /dev/null +++ b/alpaca/rootfs/etc/confd/templates/org.ops4j.pax.logging.cfg.tmpl @@ -0,0 +1,34 @@ +# Root logger +log4j.rootLogger={{ getv "/logger/root/level" "WARN" }}, out, osgi:* +log4j.throwableRenderer=org.apache.log4j.OsgiThrowableRenderer + +# File appender +log4j.appender.out=org.apache.log4j.RollingFileAppender +log4j.appender.out.layout=org.apache.log4j.PatternLayout +log4j.appender.out.layout.ConversionPattern=%d{ISO8601} | %-5.5p | %-16.16t | %-32.32c{1} | %X{bundle.id} - %X{bundle.name} - %X{bundle.version} | %m%n +log4j.appender.out.file=${karaf.data}/log/karaf.log +log4j.appender.out.append=true +log4j.appender.out.maxFileSize=1MB +log4j.appender.out.maxBackupIndex=10 + +# Camel Logger +log4j.appender.camel=org.apache.log4j.RollingFileAppender +log4j.appender.camel.layout=org.apache.log4j.PatternLayout +log4j.appender.camel.layout.ConversionPattern=%d{ISO8601} | %-5.5p | %-16.16t | %-32.32c{1} | %X{bundle.id} - %X{bundle.name} - %X{bundle.version} | %m%n +log4j.appender.camel.file=${karaf.data}/log/camel.log +log4j.appender.camel.append=false +log4j.appender.camel.maxFileSize=1MB +log4j.appender.camel.maxBackupIndex=10 + +log4j.logger.org.apache.camel={{ getv "/logger/camel/level" "WARN" }}, camel + +# Islandora Logger +log4j.appender.islandora=org.apache.log4j.RollingFileAppender +log4j.appender.islandora.layout=org.apache.log4j.PatternLayout +log4j.appender.islandora.layout.ConversionPattern=%d{ISO8601} | %-5.5p | %-16.16t | %-32.32c{1} | %X{bundle.id} - %X{bundle.name} - %X{bundle.version} | %m%n +log4j.appender.islandora.file=${karaf.data}/log/islandora.log +log4j.appender.islandora.append=false +log4j.appender.islandora.maxFileSize=1MB +log4j.appender.islandora.maxBackupIndex=10 + +log4j.logger.ca.islandora.camel={{ getv "/logger/islandora/level" "WARN" }}, islandora diff --git a/base/.dockerignore b/base/.dockerignore new file mode 100644 index 00000000..b43bf86b --- /dev/null +++ b/base/.dockerignore @@ -0,0 +1 @@ +README.md diff --git a/base/Dockerfile b/base/Dockerfile new file mode 100644 index 00000000..89e4ca37 --- /dev/null +++ b/base/Dockerfile @@ -0,0 +1,45 @@ +# syntax=docker/dockerfile:experimental +FROM alpine:3.11.6 + +# Install packages and tools required by all downstream images. +RUN --mount=type=cache,target=/var/cache/apk \ + --mount=type=cache,target=/etc/cache/apk \ + --mount=id=downloads,type=cache,target=/opt/downloads \ + ln -s /var/cache/apk /etc/apk/cache && \ + apk add --update \ + bash \ + curl \ + git \ + gnupg \ + mariadb-client \ + mysql-client \ + netcat-openbsd \ + openssl \ + postgresql-client \ + wget \ + && \ + S6_VERSION="1.22.1.0" && \ + CONFD_VERSION="0.15.0" && \ + CONFD_SHA256="7f3aba1d803543dd1df3944d014f055112cf8dadf0a583c76dd5f46578ebe3c2" && \ + wget -N -P /opt/downloads https://github.com/just-containers/s6-overlay/releases/download/v${S6_VERSION}/s6-overlay-amd64.tar.gz && \ + wget -N -P /opt/downloads https://github.com/just-containers/s6-overlay/releases/download/v${S6_VERSION}/s6-overlay-amd64.tar.gz.sig && \ + gpg --keyserver hkp://keys.gnupg.net:80 --recv-key 2536CA16DF4FCDA2 && \ + gpg /opt/downloads/s6-overlay-amd64.tar.gz.sig && \ + wget -N -P /opt/downloads https://github.com/kelseyhightower/confd/releases/download/v${CONFD_VERSION}/confd-${CONFD_VERSION}-linux-amd64 && \ + sha256sum /opt/downloads/confd-${CONFD_VERSION}-linux-amd64 | cut -f1 -d' ' | xargs test ${CONFD_SHA256} == && \ + tar -xzf /opt/downloads/s6-overlay-amd64.tar.gz -C / && \ + cp /opt/downloads/confd-${CONFD_VERSION}-linux-amd64 /usr/local/bin/confd && \ + chmod a+x /usr/local/bin/confd && \ + echo '' > /root/.ash_history + +# Start s6 +ENTRYPOINT [ "/init" ] + +LABEL License="MIT License" + +# https://github.com/just-containers/s6-overlay#customizing-s6-behaviour +ENV S6_LOGGING=0 \ + S6_BEHAVIOUR_IF_STAGE2_FAILS=2 \ + TERM=xterm + +COPY rootfs / diff --git a/base/README.md b/base/README.md new file mode 100644 index 00000000..374af3b4 --- /dev/null +++ b/base/README.md @@ -0,0 +1,31 @@ +# Base + +Base Docker image from which almost all others are derived. It is not meant to +be run on its own. + +It's based off off [Alpine Linux], and includes [s6 overlay] and [confd]. + +## Dependencies + +Requires `alpine:3.11.6` + +## Settings + +| Environment Variable | Default | Description | +| :---------------------- | :------ | :--------------------------------------- | +| ETCD_HOST | etcd | The host where etcd, can be found | +| ETCD_HOST_PORT | 2379 | The port where etcd can be accessed | +| ETCD_CONNECTION_TIMEOUT | 0 | Timeout to wait for a connection to etcd | + +If [etcd] cannot be reached the container will use environment variables as a +[backend] for [confd]. The timeout is set to `0` by default to ensure containers +start quickly in a development environment where etcd is not running. + +Users do not require [etcd] to run the containers, environment variables can be +used instead for simplicity. + +[Alpine Linux]: https://alpinelinux.org +[backend]: https://github.com/kelseyhightower/confd/blob/34a6ce8897ab3bde10f49c30c815fe496d592860/docs/configuration-guide.md +[confd]: https://github.com/kelseyhightower/confd +[etcd]: https://github.com/etcd-io/etcd +[s6 overlay]: https://github.com/just-containers/s6-overlay diff --git a/base/rootfs/etc/cleanup.d/empty-ash-history.sh b/base/rootfs/etc/cleanup.d/empty-ash-history.sh new file mode 100755 index 00000000..5da7ff59 --- /dev/null +++ b/base/rootfs/etc/cleanup.d/empty-ash-history.sh @@ -0,0 +1,2 @@ +#!/bin/sh +echo '' > /root/.ash_history diff --git a/base/rootfs/etc/cleanup.d/empty-bash-history.sh b/base/rootfs/etc/cleanup.d/empty-bash-history.sh new file mode 100755 index 00000000..290e95f7 --- /dev/null +++ b/base/rootfs/etc/cleanup.d/empty-bash-history.sh @@ -0,0 +1,2 @@ +#!/bin/sh +echo '' > /root/.bash_history diff --git a/base/rootfs/etc/cleanup.d/empty-tmp.sh b/base/rootfs/etc/cleanup.d/empty-tmp.sh new file mode 100755 index 00000000..31c594e8 --- /dev/null +++ b/base/rootfs/etc/cleanup.d/empty-tmp.sh @@ -0,0 +1,2 @@ +#!/bin/sh +rm -rf /tmp/* diff --git a/base/rootfs/etc/confd/conf.d/.gitignore b/base/rootfs/etc/confd/conf.d/.gitignore new file mode 100644 index 00000000..d6b7ef32 --- /dev/null +++ b/base/rootfs/etc/confd/conf.d/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/base/rootfs/etc/confd/confd.toml b/base/rootfs/etc/confd/confd.toml new file mode 100644 index 00000000..c1565b39 --- /dev/null +++ b/base/rootfs/etc/confd/confd.toml @@ -0,0 +1,5 @@ +backend = "env" +confdir = "/etc/confd" +log-level = "debug" +interval = 600 +noop = false diff --git a/base/rootfs/etc/confd/templates/.gitignore b/base/rootfs/etc/confd/templates/.gitignore new file mode 100644 index 00000000..d6b7ef32 --- /dev/null +++ b/base/rootfs/etc/confd/templates/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/base/rootfs/etc/cont-finish.d/.gitignore b/base/rootfs/etc/cont-finish.d/.gitignore new file mode 100644 index 00000000..d6b7ef32 --- /dev/null +++ b/base/rootfs/etc/cont-finish.d/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/base/rootfs/etc/cont-init.d/01-confd-render-templates.sh b/base/rootfs/etc/cont-init.d/01-confd-render-templates.sh new file mode 100644 index 00000000..013f066e --- /dev/null +++ b/base/rootfs/etc/cont-init.d/01-confd-render-templates.sh @@ -0,0 +1,17 @@ +#!/usr/bin/with-contenv bash +set -e + +readonly ETCD_HOST=${ETCD_HOST:-etcd} +readonly ETCD_HOST_PORT=${ETCD_HOST_PORT:-2379} +readonly ETCD_CONNECTION_TIMEOUT=${ETCD_CONNECTION_TIMEOUT:-0} +readonly CONFD_LOG_LEVEL=${CONFD_LOG_LEVEL:-error} +readonly CONFD_POLLING_INTERVAL=${CONFD_POLLING_INTERVAL:-30} + +echo "Looking for etcd server... http://${ETCD_HOST}:${ETCD_HOST_PORT}" +if timeout ${ETCD_CONNECTION_TIMEOUT} wait-for-open-port.sh ${ETCD_HOST} ${ETCD_HOST_PORT} &> /dev/null; then + echo "Found etcd server..." + confd -onetime -sync-only -log-level ${CONFD_LOG_LEVEL} -backend etcdv3 -node ${ETCD_HOST}:${ETCD_HOST_PORT} +else + echo "Timeout exceeded using env backend..." + confd -onetime -sync-only -log-level ${CONFD_LOG_LEVEL} -backend env +fi diff --git a/base/rootfs/etc/fix-attrs.d/.gitignore b/base/rootfs/etc/fix-attrs.d/.gitignore new file mode 100644 index 00000000..d6b7ef32 --- /dev/null +++ b/base/rootfs/etc/fix-attrs.d/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/base/rootfs/etc/services.d/confd/finish b/base/rootfs/etc/services.d/confd/finish new file mode 100644 index 00000000..b8f06413 --- /dev/null +++ b/base/rootfs/etc/services.d/confd/finish @@ -0,0 +1,2 @@ +#!/usr/bin/with-contenv bash +s6-svscanctl -t /var/run/s6/services \ No newline at end of file diff --git a/base/rootfs/etc/services.d/confd/run b/base/rootfs/etc/services.d/confd/run new file mode 100644 index 00000000..70bd8c0d --- /dev/null +++ b/base/rootfs/etc/services.d/confd/run @@ -0,0 +1,17 @@ +#!/usr/bin/with-contenv bash +set -e + +readonly ETCD_HOST=${ETCD_HOST:-etcd} +readonly ETCD_HOST_PORT=${ETCD_HOST_PORT:-2379} +readonly ETCD_CONNECTION_TIMEOUT=${ETCD_CONNECTION_TIMEOUT:-0} +readonly CONFD_LOG_LEVEL=${CONFD_LOG_LEVEL:-error} +readonly CONFD_POLLING_INTERVAL=${CONFD_POLLING_INTERVAL:-5} + +echo "Looking for etcd server... http://${ETCD_HOST}:${ETCD_HOST_PORT}" +if timeout ${ETCD_CONNECTION_TIMEOUT} wait-for-open-port.sh ${ETCD_HOST} ${ETCD_HOST_PORT} &> /dev/null; then + echo "Found etcd server..." + confd -log-level ${CONFD_LOG_LEVEL} -interval ${CONFD_POLLING_INTERVAL} -backend etcdv3 -node ${ETCD_HOST}:${ETCD_HOST_PORT} +else + echo "Timeout exceeded using env backend..." + confd -log-level ${CONFD_LOG_LEVEL} -interval ${CONFD_POLLING_INTERVAL} -backend env +fi \ No newline at end of file diff --git a/base/rootfs/opt/.gitignore b/base/rootfs/opt/.gitignore new file mode 100644 index 00000000..d6b7ef32 --- /dev/null +++ b/base/rootfs/opt/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/base/rootfs/run/islandora/.gitignore b/base/rootfs/run/islandora/.gitignore new file mode 100644 index 00000000..d6b7ef32 --- /dev/null +++ b/base/rootfs/run/islandora/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/base/rootfs/sbin/apk-install.sh b/base/rootfs/sbin/apk-install.sh new file mode 100755 index 00000000..504bbbef --- /dev/null +++ b/base/rootfs/sbin/apk-install.sh @@ -0,0 +1,2 @@ +#!/bin/sh +apk add --update "$@" diff --git a/base/rootfs/sbin/apk-uninstall.sh b/base/rootfs/sbin/apk-uninstall.sh new file mode 100755 index 00000000..223e0374 --- /dev/null +++ b/base/rootfs/sbin/apk-uninstall.sh @@ -0,0 +1,2 @@ +#!/bin/sh +apk del --purge --update "$@" diff --git a/base/rootfs/usr/local/bin/cleanup.sh b/base/rootfs/usr/local/bin/cleanup.sh new file mode 100755 index 00000000..ba844e5f --- /dev/null +++ b/base/rootfs/usr/local/bin/cleanup.sh @@ -0,0 +1,65 @@ +#!/usr/bin/env bash + +set -e + +readonly PROGNAME=$(basename $0) +readonly ARGS="$@" + +function usage { + cat <<- EOF + usage: $PROGNAME + + Runs all the scripts in /etc/cleanup.d + + OPTIONS: + -h --help Show this help. + -x --debug Debug this script. + + Examples: + Clone repository: + $PROGNAME +EOF +} + +function cmdline { + local arg= + for arg + do + local delim="" + case "$arg" in + # Translate --gnu-long-options to -g (short options) + --help) args="${args}-h ";; + --debug) args="${args}-x ";; + # Pass through anything else + *) [[ "${arg:0:1}" == "-" ]] || delim="\"" + args="${args}${delim}${arg}${delim} ";; + esac + done + + # Reset the positional parameters to the short options + eval set -- $args + + while getopts "hx" OPTION + do + case $OPTION in + h) + usage + exit 0 + ;; + x) + readonly DEBUG='-x' + set -x + ;; + esac + done + + return 0 +} + +function main { + cmdline ${ARGS} + for file in /etc/cleanup.d/*; do + $file + done +} +main diff --git a/base/rootfs/usr/local/bin/git-clone-cached.sh b/base/rootfs/usr/local/bin/git-clone-cached.sh new file mode 100755 index 00000000..62356eff --- /dev/null +++ b/base/rootfs/usr/local/bin/git-clone-cached.sh @@ -0,0 +1,104 @@ +#!/usr/bin/env bash + +set -e + +readonly PROGNAME=$(basename $0) +readonly ARGS="$@" + +readonly DOWNLOAD_CACHE_DIRECTORY=/opt/downloads + +function usage { + cat <<- EOF + usage: $PROGNAME options [FILE]... + + Does a git clone utilizing the Buildkit caching mechanism. + + OPTIONS: + -u --url The URL of the repository to clone. + -c --commit The commit hash or tag to checkout. + -w --worktree The directory to checkout the repository into. + -s --strip Remove the git repo as well as any files passed as parameters to save space. + -h --help Show this help. + -x --debug Debug this script. + + Examples: + Clone repository: + $PROGNAME \\ + --url https://github.com/Islandora-CLAW/Alpaca.git \\ + --commit "${COMMIT}" \\ + --worktree /opt/alpaca +EOF +} + +function cmdline { + local arg= + for arg + do + local delim="" + case "$arg" in + # Translate --gnu-long-options to -g (short options) + --url) args="${args}-u ";; + --commit) args="${args}-c ";; + --worktree) args="${args}-w ";; + --strip) args="${args}-s ";; + --help) args="${args}-h ";; + --debug) args="${args}-x ";; + # Pass through anything else + *) [[ "${arg:0:1}" == "-" ]] || delim="\"" + args="${args}${delim}${arg}${delim} ";; + esac + done + + # Reset the positional parameters to the short options + eval set -- $args + + while getopts "u:c:w:shx" OPTION + do + case $OPTION in + u) + readonly URL=${OPTARG} + ;; + c) + readonly COMMIT=${OPTARG} + ;; + w) + readonly WORKTREE=${OPTARG} + ;; + h) + usage + exit 0 + ;; + x) + readonly DEBUG='-x' + set -x + ;; + esac + done + + if [[ -z $URL || -z $COMMIT || -z $WORKTREE ]]; then + echo "Missing one or more required options: --url --commit --worktree" + exit 1 + fi + + # All remaning parameters are files to be removed from the repo if --strip was specified. + shift $((OPTIND-1)) + readonly REMOVE=("$@") + + return 0 +} + +function main { + cmdline ${ARGS} + local repo=$(basename ${WORKTREE}) + git clone --mirror ${URL} ${DOWNLOAD_CACHE_DIRECTORY}/${repo} || true + git clone ${DOWNLOAD_CACHE_DIRECTORY}/${repo} ${WORKTREE} + git -C ${WORKTREE} fetch --all + git -C ${WORKTREE} reset --hard ${COMMIT} + if [[ -z $STRIP ]]; then + rm -fr ${WORKTREE}/.git + for i in "${REMOVE[@]}"; do + rm -fr "${WORKTREE}/${i}" + done + fi +} +main diff --git a/base/rootfs/usr/local/bin/wait-for-mysql.sh b/base/rootfs/usr/local/bin/wait-for-mysql.sh new file mode 100755 index 00000000..32e6f610 --- /dev/null +++ b/base/rootfs/usr/local/bin/wait-for-mysql.sh @@ -0,0 +1,114 @@ +#!/usr/bin/env bash + +set -e + +readonly PROGNAME=$(basename $0) +readonly ARGS="$@" + +function usage { + cat <<- EOF + usage: $PROGNAME options + + Waits for an connection to an mysql database as the given user, or until the + timeout is exceeded. + + Exits non-zero if not successful. + + OPTIONS: + -H --host The URL of the repository to clone. + -P --port The commit hash or tag to checkout. + -u --user The directory to checkout the repository into. + -p --password Remove the git repo as well as any files passed as parameters to save space. + -t --timeout Time to wait for a connection to the database, defaults to 60 seconds. + -h --help Show this help. + -x --debug Debug this script. + + Examples: + Check if database is acccessible: + $PROGNAME \\ + --host mariadb \\ + --port 3306 \\ + --user root \\ + --password password +EOF +} + +function cmdline { + local arg= + for arg + do + local delim="" + case "$arg" in + # Translate --gnu-long-options to -g (short options) + --host) args="${args}-H ";; + --port) args="${args}-P ";; + --user) args="${args}-u ";; + --password) args="${args}-p ";; + --timeout) args="${args}-t ";; + --help) args="${args}-h ";; + --debug) args="${args}-x ";; + # Pass through anything else + *) [[ "${arg:0:1}" == "-" ]] || delim="\"" + args="${args}${delim}${arg}${delim} ";; + esac + done + + # Reset the positional parameters to the short options + eval set -- $args + + while getopts "H:P:u:p:thx" OPTION + do + case $OPTION in + H) + readonly DB_HOST=${OPTARG} + ;; + P) + readonly DB_PORT=${OPTARG} + ;; + u) + readonly DB_USER=${OPTARG} + ;; + p) + readonly DB_PASSWORD=${OPTARG} + ;; + t) + readonly TIMEOUT=${OPTARG} + ;; + h) + usage + exit 0 + ;; + x) + readonly DEBUG='-x' + set -x + ;; + esac + done + + if [[ -z $DB_HOST || -z $DB_PORT || -z $DB_USER || -x $DB_PASSWORD ]]; then + echo "Missing one or more required options: --host --port --user --password" + exit 1 + fi + + return 0 +} + +function main { + cmdline ${ARGS} + local duration=${TIMEOUT:-300} + echo "Waiting for up to ${duration} seconds to connect to Database ${DB_HOST}:${DB_PORT}" + if timeout ${duration} wait-for-open-port.sh ${DB_HOST} ${DB_PORT}; then + echo "Database found" + else + exit 1 + fi + echo "Validating Database credentials for ${DB_USER}" + if mysqladmin -s --user=${DB_USER} --password=${DB_PASSWORD} --host=${DB_HOST} --port=${DB_PORT} --protocol=tcp ping; then + echo "Credentials are valid" + exit 0 + else + echo "Credentials are invalid" + exit 1 + fi +} +main diff --git a/base/rootfs/usr/local/bin/wait-for-open-port.sh b/base/rootfs/usr/local/bin/wait-for-open-port.sh new file mode 100755 index 00000000..fece693a --- /dev/null +++ b/base/rootfs/usr/local/bin/wait-for-open-port.sh @@ -0,0 +1,80 @@ +#!/usr/bin/env bash + +set -e + +readonly PROGNAME=$(basename $0) +readonly ARGS="$@" + +function usage { + cat <<- EOF + usage: $PROGNAME HOST PORT + + Waits for the given PORT to be open on HOST, re-checks every second. + + Use in conjunction with timeout. + + OPTIONS: + -h --help Show this help. + -x --debug Debug this script. + + Examples: + Check if database is acccessible: + timeout 10 $PROGNAME database 3306 +EOF +} + +function cmdline { + local arg= + for arg + do + local delim="" + case "$arg" in + # Translate --gnu-long-options to -g (short options) + --help) args="${args}-h ";; + --debug) args="${args}-x ";; + # Pass through anything else + *) [[ "${arg:0:1}" == "-" ]] || delim="\"" + args="${args}${delim}${arg}${delim} ";; + esac + done + + # Reset the positional parameters to the short options + eval set -- $args + + while getopts "hx" OPTION + do + case $OPTION in + h) + usage + exit 0 + ;; + x) + readonly DEBUG='-x' + set -x + ;; + esac + done + + shift $((OPTIND-1)) + + if [ "$#" -ne 2 ]; then + echo "Illegal number of parameters" + usage + return 1 + fi + + readonly HOST=${1}; shift + readonly PORT=${1} + + return 0 +} + +function main { + cmdline ${ARGS} + echo "Waiting for ${PORT} on ${HOST} to open." + while ! nc -z -w5 $HOST $PORT &> /dev/null; do + sleep 1 + done + exit 0; +} +main diff --git a/blazegraph/.dockerignore b/blazegraph/.dockerignore new file mode 100644 index 00000000..b43bf86b --- /dev/null +++ b/blazegraph/.dockerignore @@ -0,0 +1 @@ +README.md diff --git a/blazegraph/Dockerfile b/blazegraph/Dockerfile new file mode 100644 index 00000000..d5981331 --- /dev/null +++ b/blazegraph/Dockerfile @@ -0,0 +1,17 @@ +# syntax=docker/dockerfile:experimental +FROM local/tomcat:latest + +RUN --mount=id=downloads,type=cache,target=/opt/downloads \ + BLAZEGRAPH_VERSION=CANDIDATE_2_1_5 && \ + install-war-into-tomcat.sh \ + --name "bigdata" \ + --url "https://github.com/blazegraph/database/releases/download/BLAZEGRAPH_RELEASE_${BLAZEGRAPH_VERSION}/blazegraph.war" \ + --key "b22f1a1aa8e536443db9a57da63720813374ef59e4021cfa9ad0e98f9a420e85" + +COPY rootfs / + +RUN mkdir /data && \ + chown tomcat:tomcat /data && \ + chown -R tomcat:tomcat /opt/tomcat + +VOLUME /data diff --git a/blazegraph/README.md b/blazegraph/README.md new file mode 100644 index 00000000..85a71bfe --- /dev/null +++ b/blazegraph/README.md @@ -0,0 +1,37 @@ +# Blazegraph + +Docker image for [Blazegraph] version 2.1.5. + +Please refer to the [Blazegraph Documentation] for more in-depth information. + +As a quick example this will bring up an instance of [Blazegraph], and allow you +to view on . + +```bash +docker run --rm -ti -p 80:80 islandora/blazegraph +``` + +## Dependencies + +Requires `islandora/tomcat` docker image to build. Please refer to the +[Tomcat Image README](../tomcat/README.md) for additional information including +additional settings, volumes, ports, etc. + +## Volumes + +| Path | Description | +| :---- | :--------------------------- | +| /data | Location of the backing file | + +## Logs + +| Path | Description | +| :--------------------------------- | :---------- | +| /opt/tomcat/logs/rules.log | | +| /opt/tomcat/logs/queryLog.csv | | +| /opt/tomcat/logs/queryRunState.log | | +| /opt/tomcat/logs/solutions.csv | | +| /opt/tomcat/logs/sparql.txt | | + +[Blazegraph Documentation]: https://github.com/blazegraph/database/wiki/About_Blazegraph +[Blazegraph]: https://blazegraph.com/ diff --git a/blazegraph/rootfs/etc/confd/conf.d/RWStore.properties.toml b/blazegraph/rootfs/etc/confd/conf.d/RWStore.properties.toml new file mode 100644 index 00000000..6a68991a --- /dev/null +++ b/blazegraph/rootfs/etc/confd/conf.d/RWStore.properties.toml @@ -0,0 +1,6 @@ +[template] +src = "RWStore.properties.tmpl" +dest = "/opt/tomcat/webapps/bigdata/WEB-INF/classes/RWStore.properties" +uid = 100 +gid = 1000 +keys = ["/"] diff --git a/blazegraph/rootfs/etc/confd/conf.d/log4j.properties.toml b/blazegraph/rootfs/etc/confd/conf.d/log4j.properties.toml new file mode 100644 index 00000000..0a634d63 --- /dev/null +++ b/blazegraph/rootfs/etc/confd/conf.d/log4j.properties.toml @@ -0,0 +1,6 @@ +[template] +src = "log4j.properties.tmpl" +dest = "/opt/tomcat/webapps/bigdata/WEB-INF/classes/log4j.properties" +uid = 100 +gid = 1000 +keys = ["/"] diff --git a/blazegraph/rootfs/etc/confd/confd.toml b/blazegraph/rootfs/etc/confd/confd.toml new file mode 100644 index 00000000..e6508b2d --- /dev/null +++ b/blazegraph/rootfs/etc/confd/confd.toml @@ -0,0 +1,6 @@ +backend = "env" +confdir = "/etc/confd" +log-level = "debug" +interval = 600 +noop = false +prefix = "/blazegraph" diff --git a/blazegraph/rootfs/etc/confd/templates/RWStore.properties.tmpl b/blazegraph/rootfs/etc/confd/templates/RWStore.properties.tmpl new file mode 100644 index 00000000..7303205d --- /dev/null +++ b/blazegraph/rootfs/etc/confd/templates/RWStore.properties.tmpl @@ -0,0 +1,49 @@ +# +# Note: These options are applied when the journal and the triple store are +# first created. + +## +## Journal options. +## + +# The backing file. This contains all your data. You want to put this someplace +# safe. The default locator will wind up in the directory from which you start +# your servlet container. +com.bigdata.journal.AbstractJournal.file=/data/bigdata.jnl + +# The persistence engine. Use 'Disk' for the WORM or 'DiskRW' for the RWStore. +com.bigdata.journal.AbstractJournal.bufferMode=DiskRW + +# Setup for the RWStore recycler rather than session protection. +com.bigdata.service.AbstractTransactionService.minReleaseAge=1 + +# Enable group commit. See http://wiki.blazegraph.com/wiki/index.php/GroupCommit and BLZG-192. +#com.bigdata.journal.Journal.groupCommit=true + +com.bigdata.btree.writeRetentionQueue.capacity=4000 +com.bigdata.btree.BTree.branchingFactor=128 + +# 200M initial extent. +com.bigdata.journal.AbstractJournal.initialExtent=209715200 +com.bigdata.journal.AbstractJournal.maximumExtent=209715200 + +## +## Setup for QUADS mode without the full text index. +## +com.bigdata.rdf.sail.truthMaintenance=false +com.bigdata.rdf.store.AbstractTripleStore.quads=true +com.bigdata.rdf.store.AbstractTripleStore.statementIdentifiers=false +com.bigdata.rdf.store.AbstractTripleStore.textIndex=false +com.bigdata.rdf.store.AbstractTripleStore.axiomsClass=com.bigdata.rdf.axioms.NoAxioms + +# Bump up the branching factor for the lexicon indices on the default kb. +com.bigdata.namespace.kb.lex.com.bigdata.btree.BTree.branchingFactor=400 + +# Bump up the branching factor for the statement indices on the default kb. +com.bigdata.namespace.kb.spo.com.bigdata.btree.BTree.branchingFactor=1024 + +# Uncomment to enable collection of OS level performance counters. When +# collected they will be self-reported through the /counters servlet and +# the workbench "Performance" tab. +# +com.bigdata.journal.Journal.collectPlatformStatistics=false diff --git a/blazegraph/rootfs/etc/confd/templates/log4j.properties.tmpl b/blazegraph/rootfs/etc/confd/templates/log4j.properties.tmpl new file mode 100644 index 00000000..4f5c76f0 --- /dev/null +++ b/blazegraph/rootfs/etc/confd/templates/log4j.properties.tmpl @@ -0,0 +1,110 @@ +# Default log4j configuration. See the individual classes for the +# specific loggers, but generally they are named for the class in +# which they are defined. + +# Default log4j configuration for testing purposes. +# +# You probably want to set the default log level to ERROR. +# +log4j.rootCategory=WARN, dest1 +#log4j.rootCategory=WARN, dest2 + +# Loggers. +# Note: logging here at INFO or DEBUG will significantly impact throughput! +log4j.logger.com.bigdata=WARN +log4j.logger.com.bigdata.btree=WARN + +# Normal data loader (single threaded). +#log4j.logger.com.bigdata.rdf.store.DataLoader=INFO + +# dest1 +log4j.appender.dest1=org.apache.log4j.ConsoleAppender +log4j.appender.dest1.layout=org.apache.log4j.PatternLayout +log4j.appender.dest1.layout.ConversionPattern=%-5p: %F:%L: %m%n + +# dest2 includes the thread name and elapsed milliseconds. +# Note: %r is elapsed milliseconds. +# Note: %t is the thread name. +# See http://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/PatternLayout.html +log4j.appender.dest2=org.apache.log4j.ConsoleAppender +log4j.appender.dest2.layout=org.apache.log4j.PatternLayout +log4j.appender.dest2.layout.ConversionPattern=%-5p: %r %X{hostname} %X{serviceUUID} %X{taskname} %X{timestamp} %X{resources} %t %l: %m%n + +## +# Rule execution log. This is a formatted log file (comma delimited). +log4j.logger.com.bigdata.relation.rule.eval.RuleLog=INFO,ruleLog +log4j.additivity.com.bigdata.relation.rule.eval.RuleLog=false +log4j.appender.ruleLog=org.apache.log4j.FileAppender +log4j.appender.ruleLog.Threshold=ALL +log4j.appender.ruleLog.File=/opt/tomcat/logs/rules.log +log4j.appender.ruleLog.Append=true +# I find that it is nicer to have this unbuffered since you can see what +# is going on and to make sure that I have complete rule evaluation logs +# on shutdown. +log4j.appender.ruleLog.BufferedIO=false +log4j.appender.ruleLog.layout=org.apache.log4j.PatternLayout +log4j.appender.ruleLog.layout.ConversionPattern=%m + +## +# Summary query evaluation log (tab delimited file). Uncomment the next line to enable. +#log4j.logger.com.bigdata.bop.engine.QueryLog=INFO,queryLog +log4j.additivity.com.bigdata.bop.engine.QueryLog=false +log4j.appender.queryLog=org.apache.log4j.FileAppender +log4j.appender.queryLog.Threshold=ALL +log4j.appender.queryLog.File=/opt/tomcat/logs/queryLog.csv +log4j.appender.queryLog.Append=true +# I find that it is nicer to have this unbuffered since you can see what +# is going on and to make sure that I have complete rule evaluation logs +# on shutdown. +log4j.appender.queryLog.BufferedIO=false +log4j.appender.queryLog.layout=org.apache.log4j.PatternLayout +log4j.appender.queryLog.layout.ConversionPattern=%m + +## +# BOp run state trace (tab delimited file). Uncomment the next line to enable. +#log4j.logger.com.bigdata.bop.engine.RunState$TableLog=INFO,queryRunStateLog +log4j.additivity.com.bigdata.bop.engine.RunState$TableLog=false +log4j.appender.queryRunStateLog=org.apache.log4j.FileAppender +log4j.appender.queryRunStateLog.Threshold=ALL +log4j.appender.queryRunStateLog.File=/opt/tomcat/logs/queryRunState.log +log4j.appender.queryRunStateLog.Append=true +# I find that it is nicer to have this unbuffered since you can see what +# is going on and to make sure that I have complete rule evaluation logs +# on shutdown. +log4j.appender.queryRunStateLog.BufferedIO=false +log4j.appender.queryRunStateLog.layout=org.apache.log4j.PatternLayout +log4j.appender.queryRunStateLog.layout.ConversionPattern=%m + +## +# Solutions trace (tab delimited file). Uncomment the next line to enable. +#log4j.logger.com.bigdata.bop.engine.SolutionsLog=INFO,solutionsLog +log4j.additivity.com.bigdata.bop.engine.SolutionsLog=false +log4j.appender.solutionsLog=org.apache.log4j.ConsoleAppender +#log4j.appender.solutionsLog=org.apache.log4j.FileAppender +log4j.appender.solutionsLog.Threshold=ALL +log4j.appender.solutionsLog.File=/opt/tomcat/logs/solutions.csv +log4j.appender.solutionsLog.Append=true +# I find that it is nicer to have this unbuffered since you can see what +# is going on and to make sure that I have complete rule evaluation logs +# on shutdown. +log4j.appender.solutionsLog.BufferedIO=false +log4j.appender.solutionsLog.layout=org.apache.log4j.PatternLayout +log4j.appender.solutionsLog.layout.ConversionPattern=SOLUTION:\t%m + +## +# SPARQL query trace (plain text file). Uncomment 2nd line to enable. +log4j.logger.com.bigdata.rdf.sparql.ast.eval.ASTEvalHelper=WARN +#log4j.logger.com.bigdata.rdf.sparql.ast.eval.ASTEvalHelper=INFO,sparqlLog +log4j.additivity.com.bigdata.rdf.sparql.ast.eval.ASTEvalHelper=false +log4j.appender.sparqlLog=org.apache.log4j.ConsoleAppender +#log4j.appender.sparqlLog=org.apache.log4j.FileAppender +log4j.appender.sparqlLog.Threshold=ALL +log4j.appender.sparqlLog.File=/opt/tomcat/logs/sparql.txt +log4j.appender.sparqlLog.Append=true +# I find that it is nicer to have this unbuffered since you can see what +# is going on and to make sure that I have complete rule evaluation logs +# on shutdown. +log4j.appender.sparqlLog.BufferedIO=false +log4j.appender.sparqlLog.layout=org.apache.log4j.PatternLayout +log4j.appender.sparqlLog.layout.ConversionPattern=#----------%d-----------tx=%X{tx}\n%m\n + diff --git a/build.gradle.kts b/build.gradle.kts new file mode 100644 index 00000000..df109087 --- /dev/null +++ b/build.gradle.kts @@ -0,0 +1,277 @@ +import com.bmuschko.gradle.docker.tasks.image.DockerBuildImage +import com.bmuschko.gradle.docker.tasks.image.DockerPushImage +import com.bmuschko.gradle.docker.tasks.image.Dockerfile +import com.bmuschko.gradle.docker.tasks.image.Dockerfile.* +import java.lang.RuntimeException + +plugins { + id("com.bmuschko.docker-remote-api") version "6.4.0" +} + +extensions.findByName("buildScan")?.withGroovyBuilder { + setProperty("termsOfServiceUrl", "https://gradle.com/terms-of-service") + setProperty("termsOfServiceAgree", "yes") +} + +val useBuildKit: String by project +val repository: String by project +val cacheRepository: String by project + +val registryUrl: String by project +val registryUsername: String by project +val registryPassword: String by project + +// https://docs.docker.com/engine/reference/builder/#from +// FROM [--platform=] [AS ] +// FROM [--platform=] [:] [AS ] +// FROM [--platform=] [@] [AS ] +val extractProjectDependenciesFromDockerfileRegex = """FROM[ \t]+(:?--platform=[^ ]+[ \t]+)?local/([^ :@]+):(.*)""".toRegex() + +// If Buildkit is enabled instructions are left as is otherwise Buildkit specific flags are removed. +val extractBuildkitFlagFromInstruction = """(--mount.+ \\)""".toRegex() +val preprocessRunInstruction: (Instruction) -> Instruction = if (useBuildKit.toBoolean()) { + // No-op + { instruction -> instruction } +} else { + // Strip Buildkit specific flags. + { instruction -> + // Assumes only mount flags are used and each one is separated onto it's own line. + val text = instruction.text.replace(extractBuildkitFlagFromInstruction, """\\""") + GenericInstruction(text) + } +} + +data class BindMount(val from: String, val source: String, val target: String) { + companion object { + private val EXTRACT_BIND_MOUNT_REGEX = """--mount=type=bind,([^\\]+)""".toRegex() + + fun fromInstruction(instruction: Instruction) = EXTRACT_BIND_MOUNT_REGEX.find(instruction.text)?.let { + val properties = it.groupValues[1].split(',').map { property -> + val parts = property.split('=') + Pair(parts[0], parts[1]) + }.toMap() + BindMount(properties["from"]!!, properties["source"]!!, properties["target"]!!) + } + } + // eg. COPY --from=imagemagick /home/builder/packages/x86_64 /packages + fun toCopyInstruction() = GenericInstruction("COPY --from=${from} $source $target") +} + +fun extractBindMountFlagFromInstruction() { + +} +//--mount=type=bind,from=imagemagick,source=/home/builder/packages/x86_64,target=/packages +// Generate a list of image tages for the given image, using the project, version and tag properties. +fun imagesTags(image: String, project: Project): Set { + val tags: String by project + return setOf( + "$image:latest", + "$image:${project.version}" + ) + tags.split(' ').filter { it.isNotEmpty() }.map { "$image:$it" } +} + +subprojects { + // Make all build directories relative to the root, only supports projects up to a depth of one for now. + buildDir = rootProject.buildDir.resolve(projectDir.relativeTo(rootDir)) + layout.buildDirectory.set(buildDir) + + // If there is a docker file in the project add the appropriate tasks. + if (projectDir.resolve("Dockerfile").exists()) { + apply(plugin = "com.bmuschko.docker-remote-api") + + val imageTags = imagesTags("$repository/$name", project) + val cachedImageTags = imagesTags("$cacheRepository/$name", project) + + val createDockerfile = tasks.register("createDockerFile") { + instructionsFromTemplate(projectDir.resolve("Dockerfile")) + // To simplify processing the instructions group them by keyword. + val originalInstructions = instructions.get().toList() + val groupedInstructions = mutableListOf>>( + Pair(originalInstructions.first().keyword, mutableListOf(originalInstructions.first())) + ) + originalInstructions.drop(1).forEach { instruction -> + // An empty keyword means the line of text belongs to the previous instruction keyword. + if (instruction.keyword != "") { + groupedInstructions.add(Pair(instruction.keyword, mutableListOf(instruction))) + } + else { + groupedInstructions.last().second.add(instruction) + } + } + // Using bind mounts from other images needs to be mapped to COPY instructions, if not using Buildkit. + // Add these COPY instructions prior to the RUN instructions that used the bind mount. + val iterator = groupedInstructions.listIterator() + while(iterator.hasNext()) { + val (keyword, instructions) = iterator.next() + when (keyword) { + RunCommandInstruction.KEYWORD -> { + // Get any bind mount flags and convert them into copy instructions. + val bindMounts = instructions.mapNotNull { instruction-> + BindMount.fromInstruction(instruction) + } + bindMounts.forEach { bindMount -> + // Add before RUN instruction, previous is safe here as there has to always be at least a + // single FROM instruction preceeding it. + iterator.previous() + iterator.add(Pair(CopyFileInstruction.KEYWORD, mutableListOf(bindMount.toCopyInstruction()))) + iterator.next() + } + } + } + } + // Process instructions in place, and flatten to list. + val processedInstructions = groupedInstructions.flatMap { (keyword, instructions) -> + when (keyword) { + // Use the 'repository' name for the images when building, defaults to 'local'. + FromInstruction.KEYWORD -> { + instructions.map { instruction -> + extractProjectDependenciesFromDockerfileRegex.find(instruction.text)?.let { + val name = it.groupValues[2] + val remainder = it.groupValues[3] + FromInstruction(From("$repository/$name:$remainder")) + } ?: instruction + } + } + // Strip Buildkit flags if applicable. + RunCommandInstruction.KEYWORD -> instructions.map { preprocessRunInstruction(it) } + else -> instructions + } + } + instructions.set(processedInstructions) + destFile.set(buildDir.resolve("Dockerfile")) + } + + val prepareContext = tasks.register("prepareContext") { + from(projectDir) + from(createDockerfile.map { it.destFile.get() }) + into(buildDir.resolve("context")) + } + + val buildDockerImage = if (useBuildKit.toBoolean()) { + tasks.register("build") { + group = "islandora" + description = "Creates Docker image." + images.addAll(imageTags) + inputDir.set(layout.dir(prepareContext.map { it.destinationDir })) + // Use the remote cache to build this image if possible. + cacheFrom.addAll(cachedImageTags) + // Allow image to be used as a cache when building on other machine. + buildArgs.put("BUILDKIT_INLINE_CACHE", "1") + } + } else { + tasks.register("build") { + group = "islandora" + description = "Creates Docker image." + images.addAll(imageTags) + inputDir.set(layout.dir(prepareContext.map { it.destinationDir })) + } + } + + tasks.register("push") { + images.set(buildDockerImage.map { + when (it) { + is DockerBuildKitBuildImage -> it.images.get() + is DockerBuildImage -> it.images.get() + else -> throw RuntimeException("Impossible to reach this state, but we must satisfy the type system.") + } + }) + registryCredentials { + url.set(registryUrl) + username.set(registryUsername) + password.set(registryPassword) + } + } + } +} + +subprojects { + tasks.withType { + val contents = projectDir.resolve("Dockerfile").readText() + // Extract the image name without the prefix 'local' it should match an existing project. + val matches = extractProjectDependenciesFromDockerfileRegex.findAll(contents) + + // If the project is found and it has a build task, link the dependency. + matches.forEach { + rootProject.findProject(it.groupValues[2]) + ?.tasks + ?.withType() + ?.first() + ?.let { buildTask -> + // If generated image id changes, rebuild. + inputs.file(buildTask.imageIdFile.asFile) + dependsOn(buildTask) + // This used to replace the FROM statements such that the referred to the Image ID rather + // than "latest". Though this is currently broken when BuildKit is enabled: + // https://github.com/moby/moby/issues/39769 + // Now it uses whatever repository we're building / latest since that is variable. + } + } + } +} + +//============================================================================= +// Helper functions. +//============================================================================= + +// Override the DockerBuildImage command to use the CLI since BuildKit is not supported in the java docker api. +// https://github.com/docker-java/docker-java/issues/1381 +open class DockerBuildKitBuildImage : DefaultTask() { + @InputDirectory + @PathSensitive(PathSensitivity.RELATIVE) + val inputDir = project.objects.directoryProperty() + + @Input + @get:Optional + val cacheFrom = project.objects.listProperty() + + @Input + @get:Optional + val buildArgs = project.objects.mapProperty() + + @Input + @get:Optional + val images = project.objects.setProperty() + + @OutputFile + val imageIdFile = project.objects.fileProperty() + + @Internal + val imageId = project.objects.property() + + init { + logging.captureStandardOutput(LogLevel.INFO) + logging.captureStandardError(LogLevel.ERROR) + imageIdFile.set(project.buildDir.resolve(".docker/${path.replace(":", "_")}-imageId.txt")) + } + + private fun cacheFromValid(image: String): Boolean { + return try { + val result = project.exec { + environment("DOCKER_CLI_EXPERIMENTAL", "enabled") + workingDir = inputDir.get().asFile + commandLine = listOf("docker", "manifest", "inspect", image) + } + result.exitValue == 0; + } + catch (e: Exception) { + logger.error("Failed to find cache image: ${image}, either it does not exist, or authentication failed.") + false + } + } + + @TaskAction + fun exec() { + val command = mutableListOf("docker", "build") + command.addAll(cacheFrom.get().filter { cacheFromValid(it) }.flatMap { listOf("--cache-from", it) }) + command.addAll(buildArgs.get().flatMap { listOf("--build-arg", "${it.key}=${it.value}") }) + command.addAll(images.get().flatMap { listOf("--tag", it) }) + command.addAll(listOf("--iidfile", imageIdFile.get().asFile.absolutePath)) + command.add(".") + project.exec { + environment("DOCKER_BUILDKIT" to 1) + workingDir = inputDir.get().asFile + commandLine = command + } + imageId.set(imageIdFile.map { it.asFile.readText() }) + } +} diff --git a/cantaloupe/.dockerignore b/cantaloupe/.dockerignore new file mode 100644 index 00000000..b43bf86b --- /dev/null +++ b/cantaloupe/.dockerignore @@ -0,0 +1 @@ +README.md diff --git a/cantaloupe/Dockerfile b/cantaloupe/Dockerfile new file mode 100644 index 00000000..6e2c0ed0 --- /dev/null +++ b/cantaloupe/Dockerfile @@ -0,0 +1,31 @@ +# syntax=docker/dockerfile:experimental +FROM local/tomcat:latest + +# Opted for OpenJPG over Kakadu but that could be changed. +# Check 00-cantaloupe-setup-environment for the defaults. +# For reference see: https://cantaloupe-project.github.io/manual/3.3/processors.html +RUN --mount=type=cache,target=/var/cache/apk \ + --mount=type=cache,target=/etc/cache/apk \ + apk-install.sh \ + imagemagick \ + ffmpeg \ + openjpeg + +RUN --mount=id=downloads,type=cache,target=/opt/downloads \ + CANTALOUPE_VERSION="3.3.1" && \ + wget -N -P /opt/downloads "https://github.com/medusa-project/cantaloupe/releases/download/v${CANTALOUPE_VERSION}/Cantaloupe-${CANTALOUPE_VERSION}.zip" && \ + unzip "/opt/downloads/Cantaloupe-${CANTALOUPE_VERSION}.zip" -d /tmp && \ + install-war-into-tomcat.sh \ + --name "cantaloupe" \ + --file "/tmp/Cantaloupe-${CANTALOUPE_VERSION}/Cantaloupe-${CANTALOUPE_VERSION}.war" \ + --key "a56593bae377b4db6b1e0cd5c8a9d62fdda41632f6295b5d4fe846e66c15768a" && \ + rm -fr /tmp/Cantaloupe-* + + +COPY rootfs / + +RUN mkdir /data && \ + chown tomcat:tomcat /data && \ + chown -R tomcat:tomcat /opt/tomcat + +VOLUME /data diff --git a/cantaloupe/README.md b/cantaloupe/README.md new file mode 100644 index 00000000..8dde76f6 --- /dev/null +++ b/cantaloupe/README.md @@ -0,0 +1,205 @@ +# Cantaloupe + +Docker image for [Cantaloupe] version 3.3.1. + +Please refer to the [Cantaloupe Documentation] for more in-depth information. + +As a quick example this will bring up an instance of [Cantaloupe], and allow you +to view on . + +```bash +docker run --rm -ti -p 80:80 islandora/cantaloupe +``` + +## Dependencies + +Requires `islandora/tomcat` docker image to build. Please refer to the +[Tomcat Image README](../tomcat/README.md) for additional information including +additional settings, volumes, ports, etc. + +## Volumes + +| Path | Description | +| :---- | :------------------- | +| /data | [Cantaloupe Caching] | + +## Settings + +| Environment Variable | Etcd Key | Default | +| :------------------------------------------------------------------------------------- | :-------------------------------------------------------------------------------------- | :--------------------------------------------------------- | +| CANTALOUPE_HTTP_ENABLED | /cantaloupe/http/enabled | true | +| CANTALOUPE_HTTP_HOST | /cantaloupe/http/host | 0.0.0.0 | +| CANTALOUPE_HTTP_PORT | /cantaloupe/http/port | 8182 | +| CANTALOUPE_HTTPS_ENABLED | /cantaloupe/https/enabled | false | +| CANTALOUPE_HTTPS_HOST | /cantaloupe/https/host | 0.0.0.0 | +| CANTALOUPE_HTTPS_PORT | /cantaloupe/https/port | 8183 | +| CANTALOUPE_HTTPS_KEY_STORE_TYPE | /cantaloupe/https/key/store/type | JKS | +| CANTALOUPE_HTTPS_KEY_STORE_PASSWORD | /cantaloupe/https/key/store/password | password | +| CANTALOUPE_HTTPS_KEY_STORE_PATH | /cantaloupe/https/key/store/path | /path/to/keystore.jks | +| CANTALOUPE_HTTPS_KEY_PASSWORD | /cantaloupe/https/key/password | password | +| CANTALOUPE_AUTH_BASIC_ENABLED | /cantaloupe/auth/basic/enabled | false | +| CANTALOUPE_AUTH_BASIC_USERNAME | /cantaloupe/auth/basic/username | admin | +| CANTALOUPE_AUTH_BASIC_SECRET | /cantaloupe/auth/basic/secret | password | +| CANTALOUPE_ADMIN_ENABLED | /cantaloupe/admin/enabled | true | +| CANTALOUPE_ADMIN_PASSWORD | /cantaloupe/admin/password | password | +| CANTALOUPE_BASE_URI | /cantaloupe/base/uri | | +| CANTALOUPE_SLASH_SUBSTITUTE | /cantaloupe/slash/substitute | | +| CANTALOUPE_MAX_PIXELS | /cantaloupe/max/pixels | 400000000 | +| CANTALOUPE_PRINT_STACK_TRACE_ON_ERROR_PAGES | /cantaloupe/print/stack/trace/on/error/pages | true | +| CANTALOUPE_DELEGATE_SCRIPT_ENABLED | /cantaloupe/delegate/script/enabled | false | +| CANTALOUPE_DELEGATE_SCRIPT_PATHNAME | /cantaloupe/delegate/script/pathname | delegates.rb | +| CANTALOUPE_DELEGATE_SCRIPT_CACHE_ENABLED | /cantaloupe/delegate/script/cache/enabled | false | +| CANTALOUPE_ENDPOINT_IIIF_1_ENABLED | /cantaloupe/endpoint/iiif/1/enabled | true | +| CANTALOUPE_ENDPOINT_IIIF_2_ENABLED | /cantaloupe/endpoint/iiif/2/enabled | true | +| CANTALOUPE_ENDPOINT_IIIF_CONTENT_DISPOSITION | /cantaloupe/endpoint/iiif/content/disposition | inline | +| CANTALOUPE_ENDPOINT_IIIF_MIN_TILE_SIZE | /cantaloupe/endpoint/iiif/min/tile/size | 1024 | +| CANTALOUPE_ENDPOINT_IIIF_2_RESTRICT_TO_SIZES | /cantaloupe/endpoint/iiif/2/restrict/to/sizes | false | +| CANTALOUPE_ENDPOINT_API_ENABLED | /cantaloupe/endpoint/api/enabled | false | +| CANTALOUPE_ENDPOINT_API_USERNAME | /cantaloupe/endpoint/api/username | | +| CANTALOUPE_ENDPOINT_API_SECRET | /cantaloupe/endpoint/api/secret | | +| CANTALOUPE_RESOLVER_STATIC | /cantaloupe/resolver/static | HttpResolver | +| CANTALOUPE_RESOLVER_DELEGATE | /cantaloupe/resolver/delegate | false | +| CANTALOUPE_FILESYSTEMRESOLVER_LOOKUP_STRATEGY | /cantaloupe/filesystemresolver/lookup/strategy | BasicLookupStrategy | +| CANTALOUPE_FILESYSTEMRESOLVER_BASICLOOKUPSTRATEGY_PATH_PREFIX | /cantaloupe/filesystemresolver/basiclookupstrategy/path/prefix | /var/www/drupal/web/ | +| CANTALOUPE_FILESYSTEMRESOLVER_BASICLOOKUPSTRATEGY_PATH_SUFFIX | /cantaloupe/filesystemresolver/basiclookupstrategy/path/suffix | | +| CANTALOUPE_HTTPRESOLVER_LOOKUP_STRATEGY | /cantaloupe/httpresolver/lookup/strategy | BasicLookupStrategy | +| CANTALOUPE_HTTPRESOLVER_BASICLOOKUPSTRATEGY_URL_PREFIX | /cantaloupe/httpresolver/basiclookupstrategy/url/prefix | | +| CANTALOUPE_HTTPRESOLVER_BASICLOOKUPSTRATEGY_URL_SUFFIX | /cantaloupe/httpresolver/basiclookupstrategy/url/suffix | | +| CANTALOUPE_HTTPRESOLVER_AUTH_BASIC_USERNAME | /cantaloupe/httpresolver/auth/basic/username | | +| CANTALOUPE_HTTPRESOLVER_AUTH_BASIC_SECRET | /cantaloupe/httpresolver/auth/basic/secret | | +| CANTALOUPE_JDBCRESOLVER_URL | /cantaloupe/jdbcresolver/url | jdbc:postgresql://database:5432/cantaloupe | +| CANTALOUPE_JDBCRESOLVER_USER | /cantaloupe/jdbcresolver/user | admin | +| CANTALOUPE_JDBCRESOLVER_PASSWORD | /cantaloupe/jdbcresolver/password | password | +| CANTALOUPE_JDBCRESOLVER_CONNECTION_TIMEOUT | /cantaloupe/jdbcresolver/connection/timeout | 10 | +| CANTALOUPE_AMAZONS3RESOLVER_ACCESS_KEY_ID | /cantaloupe/amazons3resolver/access/key/id | | +| CANTALOUPE_AMAZONS3RESOLVER_SECRET_KEY | /cantaloupe/amazons3resolver/secret/key | | +| CANTALOUPE_AMAZONS3RESOLVER_BUCKET_NAME | /cantaloupe/amazons3resolver/bucket/name | | +| CANTALOUPE_AMAZONS3RESOLVER_BUCKET_REGION | /cantaloupe/amazons3resolver/bucket/region | | +| CANTALOUPE_AMAZONS3RESOLVER_LOOKUP_STRATEGY | /cantaloupe/amazons3resolver/lookup/strategy | BasicLookupStrategy | +| CANTALOUPE_AZURESTORAGERESOLVER_ACCOUNT_NAME | /cantaloupe/azurestorageresolver/account/name | | +| CANTALOUPE_AZURESTORAGERESOLVER_ACCOUNT_KEY | /cantaloupe/azurestorageresolver/account/key | | +| CANTALOUPE_AZURESTORAGERESOLVER_CONTAINER_NAME | /cantaloupe/azurestorageresolver/container/name | | +| CANTALOUPE_AZURESTORAGERESOLVER_LOOKUP_STRATEGY | /cantaloupe/azurestorageresolver/lookup/strategy | BasicLookupStrategy | +| CANTALOUPE_PROCESSOR_AVI | /cantaloupe/processor/avi | FfmpegProcessor | +| CANTALOUPE_PROCESSOR_BMP | /cantaloupe/processor/bmp | ImageMagickProcessor | +| CANTALOUPE_PROCESSOR_DCM | /cantaloupe/processor/dcm | ImageMagickProcessor | +| CANTALOUPE_PROCESSOR_GIF | /cantaloupe/processor/gif | ImageMagickProcessor | +| CANTALOUPE_PROCESSOR_JP2 | /cantaloupe/processor/jp2 | OpenJpegProcessor | +| CANTALOUPE_PROCESSOR_JPG | /cantaloupe/processor/jpg | ImageMagickProcessor | +| CANTALOUPE_PROCESSOR_MOV | /cantaloupe/processor/mov | FfmpegProcessor | +| CANTALOUPE_PROCESSOR_MP4 | /cantaloupe/processor/mp4 | FfmpegProcessor | +| CANTALOUPE_PROCESSOR_MPG | /cantaloupe/processor/mpg | FfmpegProcessor | +| CANTALOUPE_PROCESSOR_PDF | /cantaloupe/processor/pdf | ImageMagickProcessor | +| CANTALOUPE_PROCESSOR_PNG | /cantaloupe/processor/png | ImageMagickProcessor | +| CANTALOUPE_PROCESSOR_TIF | /cantaloupe/processor/tif | ImageMagickProcessor | +| CANTALOUPE_PROCESSOR_WEBM | /cantaloupe/processor/webm | FfmpegProcessor | +| CANTALOUPE_PROCESSOR_WEBP | /cantaloupe/processor/webp | ImageMagickProcessor | +| CANTALOUPE_PROCESSOR_FALLBACK | /cantaloupe/processor/fallback | Java2dProcessor | +| CANTALOUPE_PROCESSOR_NORMALIZE | /cantaloupe/processor/normalize | false | +| CANTALOUPE_PROCESSOR_BACKGROUND_COLOR | /cantaloupe/processor/background/color | black | +| CANTALOUPE_PROCESSOR_DOWNSCALE_FILTER | /cantaloupe/processor/downscale/filter | bicubic | +| CANTALOUPE_PROCESSOR_UPSCALE_FILTER | /cantaloupe/processor/upscale/filter | bicubic | +| CANTALOUPE_PROCESSOR_SHARPEN | /cantaloupe/processor/sharpen | 0 | +| CANTALOUPE_PROCESSOR_JPG_PROGRESSIVE | /cantaloupe/processor/jpg/progressive | true | +| CANTALOUPE_PROCESSOR_JPG_QUALITY | /cantaloupe/processor/jpg/quality | 80 | +| CANTALOUPE_PROCESSOR_TIF_COMPRESSION | /cantaloupe/processor/tif/compression | LZW | +| CANTALOUPE_STREAMPROCESSOR_RETRIEVAL_STRATEGY | /cantaloupe/streamprocessor/retrieval/strategy | StreamStrategy | +| CANTALOUPE_FFMPEGPROCESSOR_PATH_TO_BINARIES | /cantaloupe/ffmpegprocessor/path/to/binaries | | +| CANTALOUPE_GRAPHICSMAGICKPROCESSOR_PATH_TO_BINARIES | /cantaloupe/graphicsmagickprocessor/path/to/binaries | | +| CANTALOUPE_IMAGEMAGICKPROCESSOR_PATH_TO_BINARIES | /cantaloupe/imagemagickprocessor/path/to/binaries | | +| CANTALOUPE_KAKADUPROCESSOR_PATH_TO_BINARIES | /cantaloupe/kakaduprocessor/path/to/binaries | | +| CANTALOUPE_OPENJPEGPROCESSOR_PATH_TO_BINARIES | /cantaloupe/openjpegprocessor/path/to/binaries | | +| CANTALOUPE_PDFBOXPROCESSOR_DPI | /cantaloupe/pdfboxprocessor/dpi | 150 | +| CANTALOUPE_CACHE_CLIENT_ENABLED | /cantaloupe/cache/client/enabled | true | +| CANTALOUPE_CACHE_CLIENT_MAX_AGE | /cantaloupe/cache/client/max/age | 2592000 | +| CANTALOUPE_CACHE_CLIENT_SHARED_MAX_AGE | /cantaloupe/cache/client/shared/max/age | | +| CANTALOUPE_CACHE_CLIENT_PUBLIC | /cantaloupe/cache/client/public | true | +| CANTALOUPE_CACHE_CLIENT_PRIVATE | /cantaloupe/cache/client/private | false | +| CANTALOUPE_CACHE_CLIENT_NO_CACHE | /cantaloupe/cache/client/no/cache | false | +| CANTALOUPE_CACHE_CLIENT_NO_STORE | /cantaloupe/cache/client/no/store | false | +| CANTALOUPE_CACHE_CLIENT_MUST_REVALIDATE | /cantaloupe/cache/client/must/revalidate | false | +| CANTALOUPE_CACHE_CLIENT_PROXY_REVALIDATE | /cantaloupe/cache/client/proxy/revalidate | false | +| CANTALOUPE_CACHE_CLIENT_NO_TRANSFORM | /cantaloupe/cache/client/no/transform | true | +| CANTALOUPE_CACHE_SOURCE | /cantaloupe/cache/source | FilesystemCache | +| CANTALOUPE_CACHE_DERIVATIVE | /cantaloupe/cache/derivative | FilesystemCache | +| CANTALOUPE_CACHE_SERVER_TTL_SECONDS | /cantaloupe/cache/server/ttl/seconds | 2592000 | +| CANTALOUPE_CACHE_SERVER_PURGE_MISSING | /cantaloupe/cache/server/purge/missing | false | +| CANTALOUPE_CACHE_SERVER_RESOLVE_FIRST | /cantaloupe/cache/server/resolve/first | false | +| CANTALOUPE_CACHE_SERVER_WORKER_ENABLED | /cantaloupe/cache/server/worker/enabled | false | +| CANTALOUPE_CACHE_SERVER_WORKER_INTERVAL | /cantaloupe/cache/server/worker/interval | 86400 | +| CANTALOUPE_FILESYSTEMCACHE_PATHNAME | /cantaloupe/filesystemcache/pathname | /data | +| CANTALOUPE_FILESYSTEMCACHE_DIR_DEPTH | /cantaloupe/filesystemcache/dir/depth | 3 | +| CANTALOUPE_FILESYSTEMCACHE_DIR_NAME_LENGTH | /cantaloupe/filesystemcache/dir/name/length | 2 | +| CANTALOUPE_JDBCCACHE_URL | /cantaloupe/jdbccache/url | jdbc:postgresql://database:5432/cantaloupe | +| CANTALOUPE_JDBCCACHE_USER | /cantaloupe/jdbccache/user | admin | +| CANTALOUPE_JDBCCACHE_PASSWORD | /cantaloupe/jdbccache/password | password | +| CANTALOUPE_JDBCCACHE_CONNECTION_TIMEOUT | /cantaloupe/jdbccache/connection/timeout | 10 | +| CANTALOUPE_JDBCCACHE_DERIVATIVE_IMAGE_TABLE | /cantaloupe/jdbccache/derivative/image/table | derivative_cache | +| CANTALOUPE_JDBCCACHE_INFO_TABLE | /cantaloupe/jdbccache/info/table | info_cache | +| CANTALOUPE_AMAZONS3CACHE_ACCESS_KEY_ID | /cantaloupe/amazons3cache/access/key/id | | +| CANTALOUPE_AMAZONS3CACHE_SECRET_KEY | /cantaloupe/amazons3cache/secret/key | | +| CANTALOUPE_AMAZONS3CACHE_BUCKET_NAME | /cantaloupe/amazons3cache/bucket/name | | +| CANTALOUPE_AMAZONS3CACHE_BUCKET_REGION | /cantaloupe/amazons3cache/bucket/region | | +| CANTALOUPE_AMAZONS3CACHE_OBJECT_KEY_PREFIX | /cantaloupe/amazons3cache/object/key/prefix | | +| CANTALOUPE_AZURESTORAGECACHE_ACCOUNT_NAME | /cantaloupe/azurestoragecache/account/name | | +| CANTALOUPE_AZURESTORAGECACHE_ACCOUNT_KEY | /cantaloupe/azurestoragecache/account/key | | +| CANTALOUPE_AZURESTORAGECACHE_CONTAINER_NAME | /cantaloupe/azurestoragecache/container/name | | +| CANTALOUPE_AZURESTORAGECACHE_OBJECT_KEY_PREFIX | /cantaloupe/azurestoragecache/object/key/prefix | | +| CANTALOUPE_OVERLAYS_ENABLED | /cantaloupe/overlays/enabled | false | +| CANTALOUPE_OVERLAYS_STRATEGY | /cantaloupe/overlays/strategy | BasicStrategy | +| CANTALOUPE_OVERLAYS_BASICSTRATEGY_TYPE | /cantaloupe/overlays/basicstrategy/type | image | +| CANTALOUPE_OVERLAYS_BASICSTRATEGY_IMAGE | /cantaloupe/overlays/basicstrategy/image | /path/to/overlay.png | +| CANTALOUPE_OVERLAYS_BASICSTRATEGY_STRING | /cantaloupe/overlays/basicstrategy/string | Copyright. All rights reserved. | +| CANTALOUPE_OVERLAYS_BASICSTRATEGY_STRING_FONT | /cantaloupe/overlays/basicstrategy/string/font | Helvetica | +| CANTALOUPE_OVERLAYS_BASICSTRATEGY_STRING_FONT_SIZE | /cantaloupe/overlays/basicstrategy/string/font/size | 24 | +| CANTALOUPE_OVERLAYS_BASICSTRATEGY_STRING_FONT_MIN_SIZE | /cantaloupe/overlays/basicstrategy/string/font/min/size | 18 | +| CANTALOUPE_OVERLAYS_BASICSTRATEGY_STRING_FONT_WEIGHT | /cantaloupe/overlays/basicstrategy/string/font/weight | 1.0 | +| CANTALOUPE_OVERLAYS_BASICSTRATEGY_STRING_GLYPH_SPACING | /cantaloupe/overlays/basicstrategy/string/glyph/spacing | 0.02 | +| CANTALOUPE_OVERLAYS_BASICSTRATEGY_STRING_COLOR | /cantaloupe/overlays/basicstrategy/string/color | white | +| CANTALOUPE_OVERLAYS_BASICSTRATEGY_STRING_STROKE_COLOR | /cantaloupe/overlays/basicstrategy/string/stroke/color | black | +| CANTALOUPE_OVERLAYS_BASICSTRATEGY_STRING_STROKE_WIDTH | /cantaloupe/overlays/basicstrategy/string/stroke/width | 1 | +| CANTALOUPE_OVERLAYS_BASICSTRATEGY_STRING_BACKGROUND_COLOR | /cantaloupe/overlays/basicstrategy/string/background/color | rgba(0, 0, 0, 100) | +| CANTALOUPE_OVERLAYS_BASICSTRATEGY_POSITION | /cantaloupe/overlays/basicstrategy/position | bottom right | +| CANTALOUPE_OVERLAYS_BASICSTRATEGY_INSET | /cantaloupe/overlays/basicstrategy/inset | 10 | +| CANTALOUPE_OVERLAYS_BASICSTRATEGY_OUTPUT_WIDTH_THRESHOLD | /cantaloupe/overlays/basicstrategy/output/width/threshold | 400 | +| CANTALOUPE_OVERLAYS_BASICSTRATEGY_OUTPUT_HEIGHT_THRESHOLD | /cantaloupe/overlays/basicstrategy/output/height/threshold | 300 | +| CANTALOUPE_REDACTION_ENABLED | /cantaloupe/redaction/enabled | false | +| CANTALOUPE_METADATA_PRESERVE | /cantaloupe/metadata/preserve | false | +| CANTALOUPE_METADATA_RESPECT_ORIENTATION | /cantaloupe/metadata/respect/orientation | false | +| CANTALOUPE_LOG_APPLICATION_LEVEL | /cantaloupe/log/application/level | debug | +| CANTALOUPE_LOG_APPLICATION_CONSOLEAPPENDER_ENABLED | /cantaloupe/log/application/consoleappender/enabled | true | +| CANTALOUPE_LOG_APPLICATION_FILEAPPENDER_ENABLED | /cantaloupe/log/application/fileappender/enabled | false | +| CANTALOUPE_LOG_APPLICATION_FILEAPPENDER_PATHNAME | /cantaloupe/log/application/fileappender/pathname | /opt/tomcat/logs/cantaloupe.application.log | +| CANTALOUPE_LOG_APPLICATION_ROLLINGFILEAPPENDER_ENABLED | /cantaloupe/log/application/rollingfileappender/enabled | false | +| CANTALOUPE_LOG_APPLICATION_ROLLINGFILEAPPENDER_PATHNAME | /cantaloupe/log/application/rollingfileappender/pathname | /opt/tomcat/logs/cantaloupe.application.log | +| CANTALOUPE_LOG_APPLICATION_ROLLINGFILEAPPENDER_POLICY | /cantaloupe/log/application/rollingfileappender/policy | TimeBasedRollingPolicy | +| CANTALOUPE_LOG_APPLICATION_ROLLINGFILEAPPENDER_TIMEBASEDROLLINGPOLICY_FILENAME_PATTERN | /cantaloupe/log/application/rollingfileappender/timebasedrollingpolicy/filename/pattern | /opt/tomcat/logs/cantaloupe.application-%d{yyyy-MM-dd}.log | +| CANTALOUPE_LOG_APPLICATION_ROLLINGFILEAPPENDER_TIMEBASEDROLLINGPOLICY_MAX_HISTORY | /cantaloupe/log/application/rollingfileappender/timebasedrollingpolicy/max/history | 30 | +| CANTALOUPE_LOG_APPLICATION_SYSLOGAPPENDER_ENABLED | /cantaloupe/log/application/syslogappender/enabled | false | +| CANTALOUPE_LOG_APPLICATION_SYSLOGAPPENDER_HOST | /cantaloupe/log/application/syslogappender/host | | +| CANTALOUPE_LOG_APPLICATION_SYSLOGAPPENDER_PORT | /cantaloupe/log/application/syslogappender/port | 514 | +| CANTALOUPE_LOG_APPLICATION_SYSLOGAPPENDER_FACILITY | /cantaloupe/log/application/syslogappender/facility | LOCAL0 | +| CANTALOUPE_LOG_ACCESS_CONSOLEAPPENDER_ENABLED | /cantaloupe/log/access/consoleappender/enabled | false | +| CANTALOUPE_LOG_ACCESS_FILEAPPENDER_ENABLED | /cantaloupe/log/access/fileappender/enabled | true | +| CANTALOUPE_LOG_ACCESS_FILEAPPENDER_PATHNAME | /cantaloupe/log/access/fileappender/pathname | /opt/tomcat/logs/cantaloupe.access.log | +| CANTALOUPE_LOG_ACCESS_ROLLINGFILEAPPENDER_ENABLED | /cantaloupe/log/access/rollingfileappender/enabled | false | +| CANTALOUPE_LOG_ACCESS_ROLLINGFILEAPPENDER_PATHNAME | /cantaloupe/log/access/rollingfileappender/pathname | /opt/tomcat/logs/cantaloupe.access.log | +| CANTALOUPE_LOG_ACCESS_ROLLINGFILEAPPENDER_POLICY | /cantaloupe/log/access/rollingfileappender/policy | TimeBasedRollingPolicy | +| CANTALOUPE_LOG_ACCESS_ROLLINGFILEAPPENDER_TIMEBASEDROLLINGPOLICY_FILENAME_PATTERN | /cantaloupe/log/access/rollingfileappender/timebasedrollingpolicy/filename/pattern | /opt/tomcat/logs/cantaloupe.access-%d{yyyy-MM-dd}.log | +| CANTALOUPE_LOG_ACCESS_ROLLINGFILEAPPENDER_TIMEBASEDROLLINGPOLICY_MAX_HISTORY | /cantaloupe/log/access/rollingfileappender/timebasedrollingpolicy/max/history | 30 | +| CANTALOUPE_LOG_ACCESS_SYSLOGAPPENDER_ENABLED | /cantaloupe/log/access/syslogappender/enabled | false | +| CANTALOUPE_LOG_ACCESS_SYSLOGAPPENDER_HOST | /cantaloupe/log/access/syslogappender/host | | +| CANTALOUPE_LOG_ACCESS_SYSLOGAPPENDER_PORT | /cantaloupe/log/access/syslogappender/port | 514 | +| CANTALOUPE_LOG_ACCESS_SYSLOGAPPENDER_FACILITY | /cantaloupe/log/access/syslogappender/facility | LOCAL0 | + +## Logs + +| Path | Description | +| :------------------------------------------ | :---------------- | +| /opt/tomcat/logs/cantaloupe.access.log | [Cantaloupe Logs] | +| /opt/tomcat/logs/cantaloupe.application.log | [Cantaloupe Logs] | + +[Cantaloupe Caching]: https://cantaloupe-project.github.io/manual/3.1/caching.html +[Cantaloupe Documentation]: https://cantaloupe-project.github.io/manual/3.1/getting-started.html +[Cantaloupe Logs]: https://cantaloupe-project.github.io/manual/3.1/logging.html +[Cantaloupe]: https://cantaloupe-project.github.io/ diff --git a/cantaloupe/rootfs/etc/confd/conf.d/cataloupe.properties.toml b/cantaloupe/rootfs/etc/confd/conf.d/cataloupe.properties.toml new file mode 100644 index 00000000..65a5bda1 --- /dev/null +++ b/cantaloupe/rootfs/etc/confd/conf.d/cataloupe.properties.toml @@ -0,0 +1,7 @@ +[template] +src = "cantaloupe.properties.tmpl" +dest = "/opt/tomcat/conf/cantaloupe.properties" +uid = 100 +gid = 1000 +mode = "0640" +keys = [ "/" ] diff --git a/cantaloupe/rootfs/etc/confd/conf.d/setenv.sh.toml b/cantaloupe/rootfs/etc/confd/conf.d/setenv.sh.toml new file mode 100644 index 00000000..7f0fbd2f --- /dev/null +++ b/cantaloupe/rootfs/etc/confd/conf.d/setenv.sh.toml @@ -0,0 +1,6 @@ +[template] +src = "setenv.sh.tmpl" +dest = "/opt/tomcat/bin/setenv.sh" +uid = 100 +gid = 1000 +keys = ["/java/opts", "/catalina/opts"] diff --git a/cantaloupe/rootfs/etc/confd/confd.toml b/cantaloupe/rootfs/etc/confd/confd.toml new file mode 100644 index 00000000..5ad14b76 --- /dev/null +++ b/cantaloupe/rootfs/etc/confd/confd.toml @@ -0,0 +1,6 @@ +backend = "env" +confdir = "/etc/confd" +log-level = "debug" +interval = 600 +noop = false +prefix = "/cantaloupe" diff --git a/cantaloupe/rootfs/etc/confd/templates/cantaloupe.properties.tmpl b/cantaloupe/rootfs/etc/confd/templates/cantaloupe.properties.tmpl new file mode 100644 index 00000000..cc370a1a --- /dev/null +++ b/cantaloupe/rootfs/etc/confd/templates/cantaloupe.properties.tmpl @@ -0,0 +1,311 @@ +########################################################################### +# GENERAL SETTINGS +########################################################################### + +http.enabled = {{ getv "/http/enabled" "true" }} +http.host = {{ getv "/http/host" "0.0.0.0" }} +http.port = {{ getv "/http/port" "8182" }} +https.enabled = {{ getv "/https/enabled" "false" }} +https.host = {{ getv "/https/host" "0.0.0.0" }} +https.port = {{ getv "/https/port" "8183" }} +https.key_store_type = {{ getv "/https/key/store/type" "JKS" }} +https.key_store_password = {{ getv "/https/key/store/password" "password" }} +https.key_store_path = {{ getv "/https/key/store/path" "/path/to/keystore.jks" }} +https.key_password = {{ getv "/https/key/password" "password" }} +auth.basic.enabled = {{ getv "/auth/basic/enabled" "false" }} +auth.basic.username = {{ getv "/auth/basic/username" "admin" }} +auth.basic.secret = {{ getv "/auth/basic/secret" "password" }} +admin.enabled = {{ getv "/admin/enabled" "true" }} +admin.password = {{ getv "/admin/password" "password" }} +base_uri = {{ getv "/base/uri" "" }} +slash_substitute = {{ getv "/slash/substitute" "" }} +max_pixels = {{ getv "/max/pixels" "400000000" }} +print_stack_trace_on_error_pages = {{ getv "/print/stack/trace/on/error/pages" "true" }} + +########################################################################### +# DELEGATE SCRIPT +########################################################################### + +delegate_script.enabled = {{ getv "/delegate/script/enabled" "false" }} +delegate_script.pathname = {{ getv "/delegate/script/pathname" "delegates.rb" }} +delegate_script.cache.enabled = {{ getv "/delegate/script/cache/enabled" "false" }} + +########################################################################### +# ENDPOINTS +########################################################################### + +endpoint.iiif.1.enabled = {{ getv "/endpoint/iiif/1/enabled" "true" }} +endpoint.iiif.2.enabled = {{ getv "/endpoint/iiif/2/enabled" "true" }} +endpoint.iiif.content_disposition = {{ getv "/endpoint/iiif/content/disposition" "inline" }} +endpoint.iiif.min_tile_size = {{ getv "/endpoint/iiif/min/tile/size" "1024" }} +endpoint.iiif.2.restrict_to_sizes = {{ getv "/endpoint/iiif/2/restrict/to/sizes" "false" }} +endpoint.api.enabled = {{ getv "/endpoint/api/enabled" "false" }} +endpoint.api.username = {{ getv "/endpoint/api/username" "" }} +endpoint.api.secret = {{ getv "/endpoint/api/secret" "" }} + +########################################################################### +# RESOLVERS +########################################################################### + +resolver.static = {{ getv "/resolver/static" "HttpResolver" }} +resolver.delegate = {{ getv "/resolver/delegate" "false" }} + +#---------------------------------------- +# FilesystemResolver +#---------------------------------------- + +FilesystemResolver.lookup_strategy = {{ getv "/filesystemresolver/lookup/strategy" "BasicLookupStrategy" }} +FilesystemResolver.BasicLookupStrategy.path_prefix = {{ getv "/filesystemresolver/basiclookupstrategy/path/prefix" "/var/www/drupal/web/" }} +FilesystemResolver.BasicLookupStrategy.path_suffix = {{ getv "/filesystemresolver/basiclookupstrategy/path/suffix" "" }} + +#---------------------------------------- +# HttpResolver +#---------------------------------------- + +HttpResolver.lookup_strategy = {{ getv "/httpresolver/lookup/strategy" "BasicLookupStrategy" }} +HttpResolver.BasicLookupStrategy.url_prefix = {{ getv "/httpresolver/basiclookupstrategy/url/prefix" "" }} +HttpResolver.BasicLookupStrategy.url_suffix = {{ getv "/httpresolver/basiclookupstrategy/url/suffix" "" }} +HttpResolver.auth.basic.username = {{ getv "/httpresolver/auth/basic/username" "" }} +HttpResolver.auth.basic.secret = {{ getv "/httpresolver/auth/basic/secret" "" }} + +#---------------------------------------- +# JdbcResolver +#---------------------------------------- + +JdbcResolver.url = {{ getv "/jdbcresolver/url" "jdbc:postgresql://database:5432/cantaloupe" }} +JdbcResolver.user = {{ getv "/jdbcresolver/user" "admin" }} +JdbcResolver.password = {{ getv "/jdbcresolver/password" "password" }} +JdbcResolver.connection_timeout = {{ getv "/jdbcresolver/connection/timeout" "10" }} + +#---------------------------------------- +# AmazonS3Resolver +#---------------------------------------- + +AmazonS3Resolver.access_key_id = {{ getv "/amazons3resolver/access/key/id" "" }} +AmazonS3Resolver.secret_key = {{ getv "/amazons3resolver/secret/key" "" }} +AmazonS3Resolver.bucket.name = {{ getv "/amazons3resolver/bucket/name" "" }} +AmazonS3Resolver.bucket.region = {{ getv "/amazons3resolver/bucket/region" "" }} +AmazonS3Resolver.lookup_strategy = {{ getv "/amazons3resolver/lookup/strategy" "BasicLookupStrategy" }} + +#---------------------------------------- +# AzureStorageResolver +#---------------------------------------- + +AzureStorageResolver.account_name = {{ getv "/azurestorageresolver/account/name" "" }} +AzureStorageResolver.account_key = {{ getv "/azurestorageresolver/account/key" "" }} +AzureStorageResolver.container_name = {{ getv "/azurestorageresolver/container/name" "" }} +AzureStorageResolver.lookup_strategy = {{ getv "/azurestorageresolver/lookup/strategy" "BasicLookupStrategy" }} + +########################################################################### +# PROCESSORS +########################################################################### + +#---------------------------------------- +# Processor Selection +#---------------------------------------- + +processor.avi = {{ getv "/processor/avi" "FfmpegProcessor" }} +processor.bmp = {{ getv "/processor/bmp" "ImageMagickProcessor" }} +processor.dcm = {{ getv "/processor/dcm" "ImageMagickProcessor" }} +processor.gif = {{ getv "/processor/gif" "ImageMagickProcessor" }} +processor.jp2 = {{ getv "/processor/jp2" "OpenJpegProcessor" }} +processor.jpg = {{ getv "/processor/jpg" "ImageMagickProcessor" }} +processor.mov = {{ getv "/processor/mov" "FfmpegProcessor" }} +processor.mp4 = {{ getv "/processor/mp4" "FfmpegProcessor" }} +processor.mpg = {{ getv "/processor/mpg" "FfmpegProcessor" }} +processor.pdf = {{ getv "/processor/pdf" "ImageMagickProcessor" }} +processor.png = {{ getv "/processor/png" "ImageMagickProcessor" }} +processor.tif = {{ getv "/processor/tif" "ImageMagickProcessor" }} +processor.webm = {{ getv "/processor/webm" "FfmpegProcessor" }} +processor.webp = {{ getv "/processor/webp" "ImageMagickProcessor" }} +processor.fallback = {{ getv "/processor/fallback" "Java2dProcessor" }} + +#---------------------------------------- +# Global Processor Configuration +#---------------------------------------- + +processor.normalize = {{ getv "/processor/normalize" "false" }} +processor.background_color = {{ getv "/processor/background/color" "black" }} +processor.downscale_filter = {{ getv "/processor/downscale/filter" "bicubic" }} +processor.upscale_filter = {{ getv "/processor/upscale/filter" "bicubic" }} +processor.sharpen = {{ getv "/processor/sharpen" "0" }} +processor.jpg.progressive = {{ getv "/processor/jpg/progressive" "true" }} +processor.jpg.quality = {{ getv "/processor/jpg/quality" "80" }} +processor.tif.compression = {{ getv "/processor/tif/compression" "LZW" }} +StreamProcessor.retrieval_strategy = {{ getv "/streamprocessor/retrieval/strategy" "StreamStrategy" }} + +#---------------------------------------- +# FfmpegProcessor +#---------------------------------------- + +FfmpegProcessor.path_to_binaries = {{ getv "/ffmpegprocessor/path/to/binaries" "" }} + +#---------------------------------------- +# GraphicsMagickProcessor +#---------------------------------------- + +GraphicsMagickProcessor.path_to_binaries = {{ getv "/graphicsmagickprocessor/path/to/binaries" "" }} + +#---------------------------------------- +# ImageMagickProcessor +#---------------------------------------- + +ImageMagickProcessor.path_to_binaries = {{ getv "/imagemagickprocessor/path/to/binaries" "" }} + +#---------------------------------------- +# KakaduProcessor +#---------------------------------------- + +KakaduProcessor.path_to_binaries = {{ getv "/kakaduprocessor/path/to/binaries" "" }} + +#---------------------------------------- +# OpenJpegProcessor +#---------------------------------------- + +OpenJpegProcessor.path_to_binaries = {{ getv "/openjpegprocessor/path/to/binaries" "" }} + +#---------------------------------------- +# PdfBoxProcessor +#---------------------------------------- + +PdfBoxProcessor.dpi = {{ getv "/pdfboxprocessor/dpi" "150" }} + +########################################################################### +# CLIENT-SIDE CACHING +########################################################################### + +cache.client.enabled = {{ getv "/cache/client/enabled" "true" }} +cache.client.max_age = {{ getv "/cache/client/max/age" "2592000" }} +cache.client.shared_max_age = {{ getv "/cache/client/shared/max/age" "" }} +cache.client.public = {{ getv "/cache/client/public" "true" }} +cache.client.private = {{ getv "/cache/client/private" "false" }} +cache.client.no_cache = {{ getv "/cache/client/no/cache" "false" }} +cache.client.no_store = {{ getv "/cache/client/no/store" "false" }} +cache.client.must_revalidate = {{ getv "/cache/client/must/revalidate" "false" }} +cache.client.proxy_revalidate = {{ getv "/cache/client/proxy/revalidate" "false" }} +cache.client.no_transform = {{ getv "/cache/client/no/transform" "true" }} + +########################################################################### +# SERVER-SIDE CACHING +########################################################################### + +cache.source = {{ getv "/cache/source" "FilesystemCache" }} +cache.derivative = {{ getv "/cache/derivative" "FilesystemCache" }} +cache.server.ttl_seconds = {{ getv "/cache/server/ttl/seconds" "2592000" }} +cache.server.purge_missing = {{ getv "/cache/server/purge/missing" "false" }} +cache.server.resolve_first = {{ getv "/cache/server/resolve/first" "false" }} +cache.server.worker.enabled = {{ getv "/cache/server/worker/enabled" "false" }} +cache.server.worker.interval = {{ getv "/cache/server/worker/interval" "86400" }} + +#---------------------------------------- +# FilesystemCache +#---------------------------------------- + +FilesystemCache.pathname = {{ getv "/filesystemcache/pathname" "/data" }} +FilesystemCache.dir.depth = {{ getv "/filesystemcache/dir/depth" "3" }} +FilesystemCache.dir.name_length = {{ getv "/filesystemcache/dir/name/length" "2" }} + +#---------------------------------------- +# JdbcCache +#---------------------------------------- + +JdbcCache.url = {{ getv "/jdbccache/url" "jdbc:postgresql://database:5432/cantaloupe" }} +JdbcCache.user = {{ getv "/jdbccache/user" "admin" }} +JdbcCache.password = {{ getv "/jdbccache/password" "password" }} +JdbcCache.connection_timeout = {{ getv "/jdbccache/connection/timeout" "10" }} +JdbcCache.derivative_image_table = {{ getv "/jdbccache/derivative/image/table" "derivative_cache" }} +JdbcCache.info_table = {{ getv "/jdbccache/info/table" "info_cache" }} + +#---------------------------------------- +# AmazonS3Cache +#---------------------------------------- + +AmazonS3Cache.access_key_id = {{ getv "/amazons3cache/access/key/id" "" }} +AmazonS3Cache.secret_key = {{ getv "/amazons3cache/secret/key" "" }}} +AmazonS3Cache.bucket.name = {{ getv "/amazons3cache/bucket/name" "" }}} +AmazonS3Cache.bucket.region = {{ getv "/amazons3cache/bucket/region" "" }}} +AmazonS3Cache.object_key_prefix = {{ getv "/amazons3cache/object/key/prefix" "" }}} + +#---------------------------------------- +# AzureStorageCache +#---------------------------------------- + +AzureStorageCache.account_name = {{ getv "/azurestoragecache/account/name" "" }} +AzureStorageCache.account_key = {{ getv "/azurestoragecache/account/key" "" }} +AzureStorageCache.container_name = {{ getv "/azurestoragecache/container/name" "" }} +AzureStorageCache.object_key_prefix = {{ getv "/azurestoragecache/object/key/prefix" "" }} + +########################################################################### +# OVERLAYS +########################################################################### + +overlays.enabled = {{ getv "/overlays/enabled" "false" }} +overlays.strategy = {{ getv "/overlays/strategy" "BasicStrategy" }} +overlays.BasicStrategy.type = {{ getv "/overlays/basicstrategy/type" "image" }} +overlays.BasicStrategy.image = {{ getv "/overlays/basicstrategy/image" "/path/to/overlay.png" }} +overlays.BasicStrategy.string = {{ getv "/overlays/basicstrategy/string" "Copyright. All rights reserved." }} +overlays.BasicStrategy.string.font = {{ getv "/overlays/basicstrategy/string/font" "Helvetica" }} +overlays.BasicStrategy.string.font.size = {{ getv "/overlays/basicstrategy/string/font/size" "24" }} +overlays.BasicStrategy.string.font.min_size = {{ getv "/overlays/basicstrategy/string/font/min/size" "18" }} +overlays.BasicStrategy.string.font.weight = {{ getv "/overlays/basicstrategy/string/font/weight" "1.0" }} +overlays.BasicStrategy.string.glyph_spacing = {{ getv "/overlays/basicstrategy/string/glyph/spacing" "0.02" }} +overlays.BasicStrategy.string.color = {{ getv "/overlays/basicstrategy/string/color" "white" }} +overlays.BasicStrategy.string.stroke.color = {{ getv "/overlays/basicstrategy/string/stroke/color" "black" }} +overlays.BasicStrategy.string.stroke.width = {{ getv "/overlays/basicstrategy/string/stroke/width" "1" }} +overlays.BasicStrategy.string.background.color = {{ getv "/overlays/basicstrategy/string/background/color" "rgba(0, 0, 0, 100)" }} +overlays.BasicStrategy.position = {{ getv "/overlays/basicstrategy/position" "bottom right" }} +overlays.BasicStrategy.inset = {{ getv "/overlays/basicstrategy/inset" "10" }} +overlays.BasicStrategy.output_width_threshold = {{ getv "/overlays/basicstrategy/output/width/threshold" "400" }} +overlays.BasicStrategy.output_height_threshold = {{ getv "/overlays/basicstrategy/output/height/threshold" "300" }} + +########################################################################### +# REDACTIONS +########################################################################### + +redaction.enabled = {{ getv "/redaction/enabled" "false" }} + +########################################################################### +# METADATA +########################################################################### + +metadata.preserve = {{ getv "/metadata/preserve" "false" }} +metadata.respect_orientation = {{ getv "/metadata/respect/orientation" "false" }} + +########################################################################### +# LOGGING +########################################################################### + +#---------------------------------------- +# Application Log +#---------------------------------------- + +log.application.level = {{ getv "/log/application/level" "debug" }} +log.application.ConsoleAppender.enabled = {{ getv "/log/application/consoleappender/enabled" "true" }} +log.application.FileAppender.enabled = {{ getv "/log/application/fileappender/enabled" "false" }} +log.application.FileAppender.pathname = {{ getv "/log/application/fileappender/pathname" "/opt/tomcat/logs/cantaloupe.application.log" }} +log.application.RollingFileAppender.enabled = {{ getv "/log/application/rollingfileappender/enabled" "false" }} +log.application.RollingFileAppender.pathname = {{ getv "/log/application/rollingfileappender/pathname" "/opt/tomcat/logs/cantaloupe.application.log" }} +log.application.RollingFileAppender.policy = {{ getv "/log/application/rollingfileappender/policy" "TimeBasedRollingPolicy" }} +log.application.RollingFileAppender.TimeBasedRollingPolicy.filename_pattern = {{ getv "/log/application/rollingfileappender/timebasedrollingpolicy/filename/pattern" "/opt/tomcat/logs/cantaloupe.application-%d{yyyy-MM-dd}.log" }} +log.application.RollingFileAppender.TimeBasedRollingPolicy.max_history = {{ getv "/log/application/rollingfileappender/timebasedrollingpolicy/max/history" "30" }} +log.application.SyslogAppender.enabled = {{ getv "/log/application/syslogappender/enabled" "false" }} +log.application.SyslogAppender.host = {{ getv "/log/application/syslogappender/host" "" }} +log.application.SyslogAppender.port = {{ getv "/log/application/syslogappender/port" "514" }} +log.application.SyslogAppender.facility = {{ getv "/log/application/syslogappender/facility" "LOCAL0" }} + +#---------------------------------------- +# Access Log +#---------------------------------------- + +log.access.ConsoleAppender.enabled = {{ getv "/log/access/consoleappender/enabled" "false" }} +log.access.FileAppender.enabled = {{ getv "/log/access/fileappender/enabled" "true" }} +log.access.FileAppender.pathname = {{ getv "/log/access/fileappender/pathname" "/opt/tomcat/logs/cantaloupe.access.log" }} +log.access.RollingFileAppender.enabled = {{ getv "/log/access/rollingfileappender/enabled" "false" }} +log.access.RollingFileAppender.pathname = {{ getv "/log/access/rollingfileappender/pathname" "/opt/tomcat/logs/cantaloupe.access.log" }} +log.access.RollingFileAppender.policy = {{ getv "/log/access/rollingfileappender/policy" "TimeBasedRollingPolicy" }} +log.access.RollingFileAppender.TimeBasedRollingPolicy.filename_pattern = {{ getv "/log/access/rollingfileappender/timebasedrollingpolicy/filename/pattern" "/opt/tomcat/logs/cantaloupe.access-%d{yyyy-MM-dd}.log" }} +log.access.RollingFileAppender.TimeBasedRollingPolicy.max_history = {{ getv "/log/access/rollingfileappender/timebasedrollingpolicy/max/history" "30" }} +log.access.SyslogAppender.enabled = {{ getv "/log/access/syslogappender/enabled" "false" }} +log.access.SyslogAppender.host = {{ getv "/log/access/syslogappender/host" "" }} +log.access.SyslogAppender.port = {{ getv "/log/access/syslogappender/port" "514" }} +log.access.SyslogAppender.facility = {{ getv "/log/access/syslogappender/facility" "LOCAL0" }} diff --git a/cantaloupe/rootfs/etc/confd/templates/setenv.sh.tmpl b/cantaloupe/rootfs/etc/confd/templates/setenv.sh.tmpl new file mode 100755 index 00000000..c4643303 --- /dev/null +++ b/cantaloupe/rootfs/etc/confd/templates/setenv.sh.tmpl @@ -0,0 +1,4 @@ +#!/bin/sh +export JAVA_OPTS="{{ getv "/java/opts" "" }}" +export CATALINA_OPTS="{{ getv "/catalina/opts" "" }}" +export CATALINA_OPTS="${CATALINA_OPTS} -Dcantaloupe.config=/opt/tomcat/conf/cantaloupe.properties" diff --git a/commands/drush.sh b/commands/drush.sh new file mode 100755 index 00000000..09c9d9c7 --- /dev/null +++ b/commands/drush.sh @@ -0,0 +1,71 @@ +#!/usr/bin/env bash +set -e + +readonly PROGNAME=$(basename $0) +readonly PROGDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +readonly ROOT="$(realpath ${PROGDIR}/..)" + +readonly ARGS="$@" + +function usage { + cat <<- EOF + usage: $PROGNAME [OPTIONS] + + Executes the drush command inside of the drupal service container. + + OPTIONS: + -h --help Show this help. + -x --debug Debug this script. + + Additionally any options that are provided by the drush command. + + Examples: + Clear the Drupal cache: + $PROGNAME cr +EOF +} + +function cmdline { + local arg= + for arg + do + local delim="" + case "$arg" in + # Translate --gnu-long-options to -g (short options) + --help) args="${args}-h ";; + --debug) args="${args}-x ";; + # Pass through anything else + *) [[ "${arg:0:1}" == "-" ]] || delim="\"" + args="${args}${delim}${arg}${delim} ";; + esac + done + + # Reset the positional parameters to the short options + eval set -- $args + + # Ignore illegal options as they get passed to mysql. + while getopts "hx" OPTION &> /dev/null; + do + case $OPTION in + h) + usage + exit 0 + ;; + x) + readonly DEBUG='-x' + set -x + ;; + esac + done + + # Check if the service exists and is running. + [[ "$(docker-compose ps -q drupal)" == "" ]] && (echo "Drupal service is not running."; exit 1) + + return 0 +} + +function main { + cmdline ${ARGS} + docker-compose -f "${ROOT}/docker-compose.yml" exec drupal s6-setuidgid nginx php -d memory_limit=-1 /usr/local/bin/drush ${ARGS} +} +main diff --git a/commands/etcdctl.sh b/commands/etcdctl.sh new file mode 100755 index 00000000..86069c96 --- /dev/null +++ b/commands/etcdctl.sh @@ -0,0 +1,80 @@ +#!/usr/bin/env bash +set -e + +readonly PROGNAME=$(basename $0) +readonly PROGDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +readonly ROOT="$(realpath ${PROGDIR}/..)" + +readonly ARGS="$@" + +function usage { + cat <<- EOF + usage: $PROGNAME [OPTIONS] [PARAMS] + + Executes etcdctl command inside of the etcd service container. + + OPTIONS: + -h --help Show this help. + -x --debug Debug this script. + + Additionally any options that are provided by etcdctl. + + Examples: + Display etcdctl help: + $PROGNAME help + + Put a key/value into the store: + $PROGNAME put /houdini/log/level DEBUG + + Get a value for the given key: + $PROGNAME get /houdini/log/level + + Get help for sub-command: + $PROGNAME put -h +EOF +} + +function cmdline { + local arg= + for arg + do + local delim="" + case "$arg" in + # Translate --gnu-long-options to -g (short options) + --help) args="${args}-h ";; + --debug) args="${args}-x ";; + # Pass through anything else + *) [[ "${arg:0:1}" == "-" ]] || delim="\"" + args="${args}${delim}${arg}${delim} ";; + esac + done + + # Reset the positional parameters to the short options + eval set -- $args + + # Ignore illegal options as they get passed to etcdctl. + while getopts "hx" OPTION &> /dev/null; + do + case $OPTION in + h) + usage + exit 0 + ;; + x) + readonly DEBUG='-x' + set -x + ;; + esac + done + + # Check if the service exists and is running. + [[ "$(docker-compose ps -q etcd)" == "" ]] && (echo "Etcd service is not running."; exit 1) + + return 0 +} + +function main { + cmdline ${ARGS} + docker-compose -f "${ROOT}/docker-compose.yml" exec etcd etcdctl ${ARGS} +} +main diff --git a/commands/mysql.sh b/commands/mysql.sh new file mode 100755 index 00000000..b436ffbd --- /dev/null +++ b/commands/mysql.sh @@ -0,0 +1,71 @@ +#!/usr/bin/env bash +set -e + +readonly PROGNAME=$(basename $0) +readonly PROGDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +readonly ROOT="$(realpath ${PROGDIR}/..)" + +readonly ARGS="$@" + +function usage { + cat <<- EOF + usage: $PROGNAME [OPTIONS] [database] + + Executes the mysql client inside of the database service container. + + OPTIONS: + -h --help Show this help. + -x --debug Debug this script. + + Additionally any options that are provided by the mysql client. + + Examples: + $PROGNAME -u root -p drupal_default +EOF +} + +function cmdline { + local arg= + for arg + do + local delim="" + case "$arg" in + # Translate --gnu-long-options to -g (short options) + --help) args="${args}-h ";; + --debug) args="${args}-x ";; + # Pass through anything else + *) [[ "${arg:0:1}" == "-" ]] || delim="\"" + args="${args}${delim}${arg}${delim} ";; + esac + done + + # Reset the positional parameters to the short options + eval set -- $args + + # Ignore illegal options as they get passed to mysql. + while getopts "hx" OPTION &> /dev/null; + do + case $OPTION in + h) + usage + exit 0 + ;; + x) + readonly DEBUG='-x' + set -x + ;; + esac + done + + # Check if the service exists and is running. + [[ "$(docker-compose ps -q database)" == "" ]] && (echo "Database service is not running."; exit 1) + + return 0 +} + +function main { + cmdline ${ARGS} + docker-compose -f "${ROOT}/docker-compose.yml" exec database mysql ${ARGS} +} +main + diff --git a/commands/open-in-browser.sh b/commands/open-in-browser.sh new file mode 100755 index 00000000..6b19bd35 --- /dev/null +++ b/commands/open-in-browser.sh @@ -0,0 +1,123 @@ +#!/usr/bin/env bash + +set -e + +readonly PROGNAME=$(basename $0) +readonly PROGDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +readonly ARGS="$@" + +function usage { + cat <<- EOF + usage: $PROGNAME SERVICE + + Opens the given SERVICE in the users browser. + + OPTIONS: + -h --help Show this help. + -x --debug Debug this script. + + Examples: + Opens activemq web console: + $PROGNAME activemq +EOF +} + +function cmdline { + local arg= + for arg + do + local delim="" + case "$arg" in + # Translate --gnu-long-options to -g (short options) + --help) args="${args}-h ";; + --debug) args="${args}-x ";; + # Pass through anything else + *) [[ "${arg:0:1}" == "-" ]] || delim="\"" + args="${args}${delim}${arg}${delim} ";; + esac + done + + # Reset the positional parameters to the short options + eval set -- $args + + while getopts "hx" OPTION + do + case $OPTION in + h) + usage + exit 0 + ;; + x) + readonly DEBUG='-x' + set -x + ;; + esac + done + + shift $((OPTIND-1)) + readonly SERVICE="${1}" + + # Check if the service exists and is running. + docker-compose ps ${SERVICE} &> /dev/null || ( echo "Service ${SERVICE} does not exist."; exit 1 ) + [[ "$(docker-compose ps -q ${SERVICE})" == "" ]] && (echo "Service ${SERVICE} is not running."; exit 1) + + return 0 +} + +function open { + local url="${1}" + if [[ "$OSTYPE" == "linux-gnu"* ]]; then + xdg-open "${url}" + elif [[ "$OSTYPE" == "darwin"* ]]; then + osascript -e "open location \"${URL}\"" + elif [[ "$OSTYPE" == "cygwin" ]]; then + cygstart "${url}" + else + echo "Unknown OS ${OSTYPE}" + exit 1 + fi +} + +function image { + local service="${1}" + docker-compose images ${service} | tail -1 | awk '{print $1}' +} + +function ip { + local service="${1}" + local image=$(image ${service}) + local template="{{range .NetworkSettings.Networks}}{{println .IPAddress}}{{end}}" + # Assumes the default network is listed first. + docker inspect -f "${template}" "${image}" | head -n1 +} + +function url { + local service="${1}"; shift + local port="${1}"; shift + local path="${1}"; shift + echo "http://$(ip ${service}):${port}${path}" +} + +function main { + cmdline ${ARGS} + + case "${SERVICE}" in + activemq) open "http://activemq.localhost/admin" &> /dev/null;; + alpaca) open $(url alpaca 8181 /system/console) &> /dev/null;; + blazegraph) open "http://blazegraph.localhost/bigdata" &> /dev/null;; + cantaloupe) open $(url cantaloupe 8080 /cantaloupe/) &> /dev/null;; + crayfits) open $(url crayfits 8000 /) &> /dev/null;; + fcrepo) open "http://fcrepo.localhost/fcrepo/rest" &> /dev/null;; + gemini) open $(url gemini 8000 /) &> /dev/null;; + homarus) open $(url homarus 8000 /) &> /dev/null;; + houdini) open $(url houdini 8000 /) &> /dev/null;; + hypercube) open $(url hypercube 8000 /) &> /dev/null;; + drupal) open "http://drupal.localhost" &> /dev/null;; + milliner) open $(url milliner 8000 /) &> /dev/null;; + recast) open $(url recast 8000 /) &> /dev/null;; + solr) open "http://solr.localhost/solr" &> /dev/null;; + matomo) open "http://matomo.localhost" &> /dev/null;; + *) exit 1;; + esac +} +main diff --git a/commands/shell.sh b/commands/shell.sh new file mode 100755 index 00000000..59ee29cf --- /dev/null +++ b/commands/shell.sh @@ -0,0 +1,73 @@ +#!/usr/bin/env bash +set -e + +readonly PROGNAME=$(basename $0) +readonly PROGDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +readonly ROOT="$(realpath ${PROGDIR}/..)" + +readonly ARGS="$@" + +function usage { + cat <<- EOF + usage: $PROGNAME SERVICE + + Opens an ash shell in the given SERVICE's container. + + OPTIONS: + -h --help Show this help. + -x --debug Debug this script. + + Examples: + $PROGNAME database +EOF +} + +function cmdline { + local arg= + for arg + do + local delim="" + case "$arg" in + # Translate --gnu-long-options to -g (short options) + --help) args="${args}-h ";; + --debug) args="${args}-x ";; + # Pass through anything else + *) [[ "${arg:0:1}" == "-" ]] || delim="\"" + args="${args}${delim}${arg}${delim} ";; + esac + done + + # Reset the positional parameters to the short options + eval set -- $args + + while getopts "hx" OPTION + do + case $OPTION in + h) + usage + exit 0 + ;; + x) + readonly DEBUG='-x' + set -x + ;; + esac + done + + shift $((OPTIND-1)) + readonly SERVICE="${1}" + + # Check if the service exists and is running. + [[ -z ${SERVICE} ]] && (echo "No SERVICE specified."; usage; exit 1) + docker-compose ps ${SERVICE} &> /dev/null || ( echo "Service ${SERVICE} does not exist."; exit 1 ) + [[ "$(docker-compose ps -q ${SERVICE})" == "" ]] && (echo "Service ${SERVICE} is not running."; exit 1) + + return 0 +} + +function main { + cmdline ${ARGS} + docker-compose -f "${ROOT}/docker-compose.yml" exec ${SERVICE} ash +} +main + diff --git a/composer/.dockerignore b/composer/.dockerignore new file mode 100644 index 00000000..b43bf86b --- /dev/null +++ b/composer/.dockerignore @@ -0,0 +1 @@ +README.md diff --git a/composer/Dockerfile b/composer/Dockerfile new file mode 100644 index 00000000..43242e68 --- /dev/null +++ b/composer/Dockerfile @@ -0,0 +1,24 @@ +# syntax=docker/dockerfile:experimental +FROM local/nginx:latest as composer + +# Overwrite with your own arguments or explicitly copy in +# your own composer.json / composer.lock files instead. +# https://getcomposer.org/doc/03-cli.md#create-project +ARG composer_project="drupal/recommended-project" + +WORKDIR /build + +RUN --mount=type=cache,target=/root/.composer/cache \ + composer create-project --no-install ${composer_project} /build && \ + composer require -- drush/drush && \ + composer install + +FROM local/drupal:latest + +RUN --mount=type=bind,from=composer,source=/build,target=/build \ + cp -r /build/* /var/www/drupal && \ + chown -R nginx:nginx /var/www/drupal && \ + wget -N -P /opt/downloads https://github.com/drush-ops/drush-launcher/releases/latest/download/drush.phar && \ + cp /opt/downloads/drush.phar /usr/local/bin/drush && \ + chmod a+x /usr/local/bin/drush && \ + cleanup.sh diff --git a/composer/README.md b/composer/README.md new file mode 100644 index 00000000..148b37ad --- /dev/null +++ b/composer/README.md @@ -0,0 +1,6 @@ +# Composer + +Serves as a template for those that wish to build a production installation +using a composer.json/composer.lock file from another repository. + +Copying the resulting composer install site into the drupal image. diff --git a/crayfish/.dockerignore b/crayfish/.dockerignore new file mode 100644 index 00000000..b43bf86b --- /dev/null +++ b/crayfish/.dockerignore @@ -0,0 +1 @@ +README.md diff --git a/crayfish/Dockerfile b/crayfish/Dockerfile new file mode 100644 index 00000000..0552df85 --- /dev/null +++ b/crayfish/Dockerfile @@ -0,0 +1,20 @@ +# syntax=docker/dockerfile:experimental +FROM local/nginx:latest + +ARG COMMIT=1.1.1 + +RUN --mount=id=downloads,type=cache,target=/opt/downloads \ + git-clone-cached.sh \ + --url https://github.com/Islandora/Crayfish.git \ + --commit "${COMMIT}" \ + --worktree /var/www/crayfish && \ + mkdir /var/log/islandora && \ + chown nginx:nginx /var/log/islandora && \ + chown -R nginx:nginx /var/www && \ + cleanup.sh + +COPY /rootfs / + +STOPSIGNAL SIGWINCH + +EXPOSE 8000 diff --git a/crayfish/README.md b/crayfish/README.md new file mode 100644 index 00000000..d54b9389 --- /dev/null +++ b/crayfish/README.md @@ -0,0 +1,31 @@ +# Crayfish + +Docker image for [Crayfish] version 1.1.1. + +Acts as base Docker image for Crayfish based micro-services. It is not meant to +be run on its own. + +## Dependencies + +Requires `islandora/nginx` docker image to build. Please refer to the +[Nginx Image README](../nginx/README.md) for additional information including +additional settings, volumes, ports, etc. + +## Ports + +| Port | Description | +| :--- | :---------- | +| 8000 | HTTP | + +## Settings + +> N.B. For all of the settings below images that descend from +> ``islandora/crayfish`` will apply prefix to every setting. So for example +> `JWT_ADMIN_TOKEN` would become `GEMINI_JWT_ADMIN_TOKEN` this is to allow for +> different settings on a per-service basis. + +| Environment Variable | Etcd Key | Default | Description | +| :------------------- | :--------------- | :-------- | :---------- | +| JWT_ADMIN_TOKEN | /jwt/admin/token | islandora | JWT Token | + +[Crayfish]: https://github.com/Islandora/Crayfish/tree/master diff --git a/crayfish/rootfs/etc/confd/conf.d/default.conf.toml b/crayfish/rootfs/etc/confd/conf.d/default.conf.toml new file mode 100644 index 00000000..1df8dbe5 --- /dev/null +++ b/crayfish/rootfs/etc/confd/conf.d/default.conf.toml @@ -0,0 +1,7 @@ +[template] +src = "default.conf.tmpl" +dest = "/etc/nginx/conf.d/default.conf" +uid = 100 +gid = 101 +mode = "0644" +keys = [ "/" ] diff --git a/crayfish/rootfs/etc/confd/conf.d/syn-settings.xml.toml b/crayfish/rootfs/etc/confd/conf.d/syn-settings.xml.toml new file mode 100644 index 00000000..bf5d102e --- /dev/null +++ b/crayfish/rootfs/etc/confd/conf.d/syn-settings.xml.toml @@ -0,0 +1,7 @@ +[template] +src = "syn-settings.xml.tmpl" +dest = "/var/www/crayfish/syn-settings.xml" +uid = 100 +gid = 101 +mode = "0644" +keys = [ "/jwt" ] diff --git a/crayfish/rootfs/etc/confd/templates/default.conf.tmpl b/crayfish/rootfs/etc/confd/templates/default.conf.tmpl new file mode 100644 index 00000000..b9df4e91 --- /dev/null +++ b/crayfish/rootfs/etc/confd/templates/default.conf.tmpl @@ -0,0 +1,29 @@ +# From: https://www.nginx.com/resources/wiki/start/topics/recipes/drupal/ +server { + listen 8000; + root /var/www/html; + + location / { + # try to serve file directly, fallback to index.php + try_files $uri /index.php$is_args$args; + } + + location ~ ^/index\.php(/|$) { + fastcgi_pass unix:/var/run/php-fpm7/php-fpm7.sock; + fastcgi_split_path_info ^(.+\.php)(/.*)$; + include fastcgi_params; + + fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name; + fastcgi_param DOCUMENT_ROOT $realpath_root; + # Prevents URIs that include the front controller. This will 404: + # http://domain.tld/index.php/some-path + # Remove the internal directive to allow URIs like this + internal; + } + + # return 404 for all other php files not matching the front controller + # this prevents access to other php files you don't want to be accessible. + location ~ \.php$ { + return 404; + } +} diff --git a/crayfish/rootfs/etc/confd/templates/syn-settings.xml.tmpl b/crayfish/rootfs/etc/confd/templates/syn-settings.xml.tmpl new file mode 100644 index 00000000..e33c6d64 --- /dev/null +++ b/crayfish/rootfs/etc/confd/templates/syn-settings.xml.tmpl @@ -0,0 +1,7 @@ + + + + + {{ getv "/jwt/admin/token" "islandora" }} + + diff --git a/crayfits/.dockerignore b/crayfits/.dockerignore new file mode 100644 index 00000000..b43bf86b --- /dev/null +++ b/crayfits/.dockerignore @@ -0,0 +1 @@ +README.md diff --git a/crayfits/Dockerfile b/crayfits/Dockerfile new file mode 100644 index 00000000..23645496 --- /dev/null +++ b/crayfits/Dockerfile @@ -0,0 +1,22 @@ +# syntax=docker/dockerfile:experimental +FROM local/nginx:latest + +ARG COMMIT=4e0faeb31f84e74e7cecc083b2f096d55e425fbb + +RUN --mount=type=cache,target=/root/.composer/cache \ + --mount=id=downloads,type=cache,target=/opt/downloads \ + git-clone-cached.sh \ + --url https://github.com/roblib/CrayFits.git \ + --commit "${COMMIT}" \ + --worktree /var/www/crayfits && \ + composer install -d /var/www/crayfits && \ + mkdir /var/log/islandora && \ + chown nginx:nginx /var/log/islandora && \ + chown -R nginx:nginx /var/www && \ + cleanup.sh + +COPY /rootfs / + +STOPSIGNAL SIGWINCH + +EXPOSE 8000 diff --git a/crayfits/README.md b/crayfits/README.md new file mode 100644 index 00000000..d1b770b2 --- /dev/null +++ b/crayfits/README.md @@ -0,0 +1,31 @@ +# Crayfits + +Docker image for [CrayFits] (**unreleased version**). + +Acts as base Docker image for CrayFits based micro-services. It is not meant to +be run on its own. + +## Dependencies + +Requires `islandora/nginx` docker image to build. Please refer to the +[Nginx Image README](../nginx/README.md) for additional information including +additional settings, volumes, ports, etc. + +## Ports + +| Port | Description | +| :--- | :---------- | +| 8000 | HTTP | + +## Settings + +> N.B. For all of the settings below images that descend from +> ``islandora/crayfits`` will apply prefix to every setting. So for example +> `JWT_ADMIN_TOKEN` would become `GEMINI_JWT_ADMIN_TOKEN` this is to allow for +> different settings on a per-service basis. + +| Environment Variable | Etcd Key | Default | Description | +| :---------------------- | :----------------------- | :--------------------- | :--------------------------- | +| CRAYFITS_WEBSERVICE_URI | /crayfits/webservice/uri | fits/fits/examine | The URL of the FITS servlet. | + +[CrayFits]: https://github.com/roblib/CrayFits diff --git a/crayfits/rootfs/etc/confd/conf.d/.env.local.toml b/crayfits/rootfs/etc/confd/conf.d/.env.local.toml new file mode 100644 index 00000000..6926e23c --- /dev/null +++ b/crayfits/rootfs/etc/confd/conf.d/.env.local.toml @@ -0,0 +1,7 @@ +[template] +src = ".env.local.tmpl" +dest = "/var/www/crayfits/.env.local" +uid = 100 +gid = 101 +mode = "0644" +keys = [ "/webservice" ] \ No newline at end of file diff --git a/crayfits/rootfs/etc/confd/conf.d/default.conf.toml b/crayfits/rootfs/etc/confd/conf.d/default.conf.toml new file mode 100644 index 00000000..1df8dbe5 --- /dev/null +++ b/crayfits/rootfs/etc/confd/conf.d/default.conf.toml @@ -0,0 +1,7 @@ +[template] +src = "default.conf.tmpl" +dest = "/etc/nginx/conf.d/default.conf" +uid = 100 +gid = 101 +mode = "0644" +keys = [ "/" ] diff --git a/crayfits/rootfs/etc/confd/confd.toml b/crayfits/rootfs/etc/confd/confd.toml new file mode 100644 index 00000000..20778f09 --- /dev/null +++ b/crayfits/rootfs/etc/confd/confd.toml @@ -0,0 +1,6 @@ +backend = "env" +confdir = "/etc/confd" +log-level = "debug" +interval = 600 +noop = false +prefix = "/crayfits" diff --git a/crayfits/rootfs/etc/confd/templates/.env.local.tmpl b/crayfits/rootfs/etc/confd/templates/.env.local.tmpl new file mode 100644 index 00000000..50554e82 --- /dev/null +++ b/crayfits/rootfs/etc/confd/templates/.env.local.tmpl @@ -0,0 +1 @@ +FITS_WEBSERVICE_URI={{ getv "/webservice/uri" "fits/fits/examine" }} \ No newline at end of file diff --git a/crayfits/rootfs/etc/confd/templates/default.conf.tmpl b/crayfits/rootfs/etc/confd/templates/default.conf.tmpl new file mode 100644 index 00000000..22106cfc --- /dev/null +++ b/crayfits/rootfs/etc/confd/templates/default.conf.tmpl @@ -0,0 +1,29 @@ +# From: https://www.nginx.com/resources/wiki/start/topics/recipes/drupal/ +server { + listen 8000; + root /var/www/crayfits/public; + + location / { + # try to serve file directly, fallback to index.php + try_files $uri /index.php$is_args$args; + } + + location ~ ^/index\.php(/|$) { + fastcgi_pass unix:/var/run/php-fpm7/php-fpm7.sock; + fastcgi_split_path_info ^(.+\.php)(/.*)$; + include fastcgi_params; + + fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name; + fastcgi_param DOCUMENT_ROOT $realpath_root; + # Prevents URIs that include the front controller. This will 404: + # http://domain.tld/index.php/some-path + # Remove the internal directive to allow URIs like this + internal; + } + + # return 404 for all other php files not matching the front controller + # this prevents access to other php files you don't want to be accessible. + location ~ \.php$ { + return 404; + } +} diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 00000000..caa7171d --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,232 @@ +# file: docker-compose.yml +# DO NOT USE IN PRODUCTION +# +# Development docker-compose for testing locally: +# - All users are 'admin' +# - All passwords are 'password' +# +# With the exception of the database where the user is +# 'root' rather than admin. And the database users for +# each service are named after their respective service +# to avoid conflict. +# +# The Traefik image acts as Reverse Proxy to the services, +# assuming you can map to port 80 on your machine. The +# loop back for localhost should make the following urls +# accessible in your browser: +# +# - activemq.localhost/admin +# - blazegraph.localhost/bigdata +# - drupal.localhost +# - fcrepo.localhost/fcrepo/reset +# - matomo.localhost +# +# For other images you can use the command: +# +# ./commands/open-in-browser SERVICE +version: "3.7" +networks: + external: + internal: false + default: + internal: true +volumes: + activemq-data: + blazegraph-data: + drupal-config-data: + drupal-sites-data: + cantaloupe-data: + etcd-data: + fcrepo-data: + jwt-data: + jwt-public-data: + karaf-data: + matomo-config-data: + mysql-data: + mysql-files: + solr-data: +services: + # Single node cluster. + # + # If disabled the system will fall back on Environment Variables. + # To set key/value pairs use the following: + # + # ./commands/etcdctl.sh put /drupal/site/default/name "default" + # + etcd: + image: gcr.io/etcd-development/etcd:v3.4.7 + environment: + ETCD_ADVERTISE_CLIENT_URLS: "http://0.0.0.0:2379" + ETCD_LISTEN_CLIENT_URLS: "http://0.0.0.0:2379" + volumes: + - etcd-data:/data + ports: + - 2379 + - 2380 + - 4001 + command: > + etcd + --data-dir=/data + watchtower: + image: v2tec/watchtower + volumes: + - /var/run/docker.sock:/var/run/docker.sock + command: --interval 1 --no-pull + activemq: + image: ${REPOSITORY:-local}/activemq:latest + volumes: + - activemq-data:/opt/activemq/data + labels: + # Do not expose in production. + - traefik.http.services.activemq.loadbalancer.server.port=8161 + - traefik.http.routers.activemq_http.service=activemq + - traefik.http.routers.activemq_http.entrypoints=http + alpaca: + image: ${REPOSITORY:-local}/alpaca:latest + volumes: + - karaf-data:/opt/karaf/data + depends_on: + - activemq + blazegraph: + image: ${REPOSITORY:-local}/blazegraph:latest + volumes: + - blazegraph-data:/data + networks: + default: + aliases: + - blazegraph.localhost + labels: + - traefik.http.services.blazegraph.loadbalancer.server.port=80 + - traefik.http.routers.blazegraph_http.service=blazegraph + - traefik.http.routers.blazegraph_http.entrypoints=http + cantaloupe: + image: ${REPOSITORY:-local}/cantaloupe:latest + volumes: + - cantaloupe-data:/data + networks: + default: + aliases: + - cantaloupe.localhost + labels: + - traefik.http.services.cantaloupe.loadbalancer.server.port=80 + - traefik.http.routers.cantaloupe_http.service=cantaloupe + - traefik.http.routers.cantaloupe_http.entrypoints=http + crayfits: + image: ${REPOSITORY:-local}/crayfits:latest + depends_on: + - fits + # Database is chosen as the service name rather than mariadb, + # as institutions may want to swap out back-ends later and + # database is a more sensible default. + database: + image: ${REPOSITORY:-local}/mariadb:latest + volumes: + - mysql-data:/var/lib/mysql + - mysql-files:/var/lib/mysql-files + drupal: + image: ${REPOSITORY:-local}/sandbox:latest + restart: unless-stopped + volumes: + - drupal-config-data:/var/www/drupal/config + - drupal-sites-data:/var/www/drupal/web/sites + - solr-data:/opt/solr/server/solr + - jwt-data:/opt/keys/claw/ + depends_on: + - solr + - fcrepo + - database + - activemq + networks: + default: + aliases: + - drupal.localhost + labels: + - traefik.http.services.drupal.loadbalancer.server.port=80 + - traefik.http.routers.drupal_http.service=drupal + - traefik.http.routers.drupal_http.entrypoints=http + fcrepo: + image: ${REPOSITORY:-local}/fcrepo:latest + volumes: + - fcrepo-data:/data + - jwt-data:/opt/keys/claw/ + depends_on: + - activemq + - database + networks: + default: + aliases: + - fcrepo.localhost + labels: + # Do not expose in production. + - traefik.http.services.fcrepo.loadbalancer.server.port=80 + - traefik.http.routers.fcrepo_http.service=fcrepo + - traefik.http.routers.fcrepo_http.entrypoints=http + fits: + image: ${REPOSITORY:-local}/fits + gemini: + image: ${REPOSITORY:-local}/gemini:latest + volumes: + - jwt-data:/opt/keys/claw/ + depends_on: + - database + homarus: + image: ${REPOSITORY:-local}/homarus:latest + volumes: + - jwt-data:/opt/keys/claw/ + houdini: + image: ${REPOSITORY:-local}/houdini:latest + volumes: + - jwt-data:/opt/keys/claw/ + hypercube: + image: ${REPOSITORY:-local}/hypercube:latest + volumes: + - jwt-data:/opt/keys/claw/ + matomo: + image: ${REPOSITORY:-local}/matomo + volumes: + - matomo-config-data:/opt/matomo/config + depends_on: + - database + networks: + default: + external: # Needs external access to request plugins, etc. + labels: + # Do not expose in production over http, setup https. + - traefik.http.services.matomo.loadbalancer.server.port=80 + - traefik.http.routers.matomo_http.service=matomo + - traefik.http.routers.matomo_http.entrypoints=http + milliner: + image: ${REPOSITORY:-local}/milliner:latest + volumes: + - jwt-data:/opt/keys/claw/ + recast: + image: ${REPOSITORY:-local}/recast:latest + volumes: + - jwt-data:/opt/keys/claw/ + solr: + image: ${REPOSITORY:-local}/solr:latest + volumes: + - solr-data:/opt/solr/server/solr + labels: + # Do not expose in production. + - traefik.http.services.solr.loadbalancer.server.port=8983 + - traefik.http.routers.solr_http.service=solr + - traefik.http.routers.solr_http.entrypoints=http + traefik: + image: traefik:2.2.1 + command: > + --api.insecure=true + --entryPoints.http.address=:80 + --entryPoints.https.address=:443 + --providers.docker + --providers.docker.network=external + '--providers.docker.defaultRule=Host(`{{ index .Labels "com.docker.compose.service" }}.localhost`)' + ports: + - 80:80 + - 443:443 + - 8080 + volumes: + - /var/run/docker.sock:/var/run/docker.sock + networks: + - external + - default diff --git a/drupal/.dockerignore b/drupal/.dockerignore new file mode 100644 index 00000000..b43bf86b --- /dev/null +++ b/drupal/.dockerignore @@ -0,0 +1 @@ +README.md diff --git a/drupal/Dockerfile b/drupal/Dockerfile new file mode 100644 index 00000000..47fef43f --- /dev/null +++ b/drupal/Dockerfile @@ -0,0 +1,10 @@ +# syntax=docker/dockerfile:experimental +FROM local/nginx:latest + +RUN mkdir -p /var/www/drupal && chown nginx:nginx /var/www/drupal + +WORKDIR /var/www/drupal + +COPY rootfs / + +EXPOSE 80 \ No newline at end of file diff --git a/drupal/README.md b/drupal/README.md new file mode 100644 index 00000000..74ffbf5d --- /dev/null +++ b/drupal/README.md @@ -0,0 +1,60 @@ +# Drupal + +Docker image for [Drupal]. + +Acts as base Docker image for Drupal based projects, it doesn't install Drupal +as consumers of this image are expected to provide their own composer file. +Instead it provides startup scripts that allow Drupal to be installed when the +image is first run. + +## Dependencies + +Requires `islandora/nginx` docker image to build. Please refer to the +[Nginx Image README](../nginx/README.md) for additional information including +additional settings, volumes, ports, etc. + +## Ports + +| Port | Description | +| :--- | :---------- | +| 80 | HTTP | + +## Settings + +| Environment Variable | Etcd Key | Default | Description | +| :------------------------------ | :------------------------------- | :---------------------- | :-------------------------------------------------------- | +| DRUPAL_DB_DRIVER | /drupal/db/driver | mysql | The database driver | +| DRUPAL_DB_HOST | /drupal/db/host | database | The database host | +| DRUPAL_DB_PORT | /drupal/db/port | 3306 | The database port | +| DRUPAL_DB_ROOT_PASSWORD | /drupal/db/root/password | password | The database root user (used to create the site database) | +| DRUPAL_DB_ROOT_USER | /drupal/db/root/user | root | The database root user password | +| DRUPAL_DEFAULT_ACCOUNT_EMAIL | /drupal/default/account/email | webmaster@localhost.com | The email to use for the admin account | +| DRUPAL_DEFAULT_ACCOUNT_NAME | /drupal/default/account/name | admin | The Drupal administrator user | +| DRUPAL_DEFAULT_ACCOUNT_PASSWORD | /drupal/default/account/password | password | The Drupal administrator user password | +| DRUPAL_DEFAULT_DB_NAME | /drupal/default/db/name | drupal_default | The name of the sites database | +| DRUPAL_DEFAULT_DB_PASSWORD | /drupal/default/db/password | password | The database users password | +| DRUPAL_DEFAULT_DB_USER | /drupal/default/db/user | drupal_default | The database user used by the site. | +| DRUPAL_DEFAULT_EMAIL | /drupal/default/email | webmaster@localhost.com | The Drupal administrators email | +| DRUPAL_DEFAULT_LOCALE | /drupal/default/locale | en | The Drupal sites locale | +| DRUPAL_DEFAULT_NAME | /drupal/default/name | default | The Drupal sites name | +| DRUPAL_DEFAULT_PROFILE | /drupal/default/profile | standard | The installation profile to use | + +Additional multi-sites can be defined by adding more environment variables, +following the above conventions, only the `DRUPAL_SITE_{SITE}_NAME` is required +to create an additional site: + +| Environment Variable | Etcd Key | Default | Description | +| :---------------------------------- | :----------------------------------- | :---------------------- | :-------------------------------------------- | +| DRUPAL_SITE_{SITE}_ACCOUNT_EMAIL | /drupal/site/{SITE}/account/email | webmaster@localhost.com | The email to use for the admin account | +| DRUPAL_SITE_{SITE}_ACCOUNT_NAME | /drupal/site/{SITE}/account/name | admin | The Drupal administrator user | +| DRUPAL_SITE_{SITE}_ACCOUNT_PASSWORD | /drupal/site/{SITE}/account/password | password | The Drupal administrator user password | +| DRUPAL_SITE_{SITE}_DB_NAME | /drupal/site/{SITE}/db/name | drupal_{SITE} | The name of the sites database | +| DRUPAL_SITE_{SITE}_DB_PASSWORD | /drupal/site/{SITE}/db/password | password | The database users password | +| DRUPAL_SITE_{SITE}_DB_USER | /drupal/site/{SITE}/db/user | drupal_{SITE} | The database user used by the site. | +| DRUPAL_SITE_{SITE}_EMAIL | /drupal/site/{SITE}/email | webmaster@localhost.com | The Drupal administrators email | +| DRUPAL_SITE_{SITE}_LOCALE | /drupal/site/{SITE}/locale | en | The Drupal sites locale | +| DRUPAL_SITE_{SITE}_NAME | /drupal/site/{SITE}/name | | The Drupal sites name | +| DRUPAL_SITE_{SITE}_PROFILE | /drupal/site/{SITE}/profile | standard | The installation profile to use | +| DRUPAL_SITE_{SITE}_SUBDIR | /drupal/site/{SITE}/subdir | {SITE} | The subdirectory to install the sub-site into | + +[Drupal]: https://www.drupal.org/ diff --git a/drupal/rootfs/etc/confd/conf.d/create-drupal-databases.sh.toml b/drupal/rootfs/etc/confd/conf.d/create-drupal-databases.sh.toml new file mode 100644 index 00000000..c45d00c4 --- /dev/null +++ b/drupal/rootfs/etc/confd/conf.d/create-drupal-databases.sh.toml @@ -0,0 +1,7 @@ +[template] +src = "create-drupal-databases.sh.tmpl" +dest = "/var/run/islandora/create-drupal-databases.sh" +uid = 0 +gid = 0 +mode = "0700" +keys = [ "/db" ] diff --git a/drupal/rootfs/etc/confd/conf.d/create-drupal-databases.sql.toml b/drupal/rootfs/etc/confd/conf.d/create-drupal-databases.sql.toml new file mode 100644 index 00000000..88c1d306 --- /dev/null +++ b/drupal/rootfs/etc/confd/conf.d/create-drupal-databases.sql.toml @@ -0,0 +1,7 @@ +[template] +src = "create-drupal-databases.sql.tmpl" +dest = "/var/run/islandora/create-drupal-databases.sql" +uid = 0 +gid = 0 +mode = "0600" +keys = [ "/site" ] diff --git a/drupal/rootfs/etc/confd/conf.d/drupal-install-sites.sh.toml b/drupal/rootfs/etc/confd/conf.d/drupal-install-sites.sh.toml new file mode 100644 index 00000000..3d569b18 --- /dev/null +++ b/drupal/rootfs/etc/confd/conf.d/drupal-install-sites.sh.toml @@ -0,0 +1,7 @@ +[template] +src = "drupal-install-sites.sh.tmpl" +dest = "/var/run/islandora/drupal-install-sites.sh" +uid = 0 +gid = 0 +mode = "0700" +keys = [ "/site", "/db" ] diff --git a/drupal/rootfs/etc/confd/confd.toml b/drupal/rootfs/etc/confd/confd.toml new file mode 100644 index 00000000..925d1a48 --- /dev/null +++ b/drupal/rootfs/etc/confd/confd.toml @@ -0,0 +1,6 @@ +backend = "env" +confdir = "/etc/confd" +log-level = "debug" +interval = 600 +noop = false +prefix = "/drupal" diff --git a/drupal/rootfs/etc/confd/templates/create-drupal-databases.sh.tmpl b/drupal/rootfs/etc/confd/templates/create-drupal-databases.sh.tmpl new file mode 100644 index 00000000..c5d6332b --- /dev/null +++ b/drupal/rootfs/etc/confd/templates/create-drupal-databases.sh.tmpl @@ -0,0 +1,33 @@ +#!/usr/bin/with-contenv bash + +set -e + +function main { + local driver="{{ getv "/db/driver" "mysql" }}" + local host="{{ getv "/db/host" "database" }}" + local port="{{ getv "/db/port" "3306" }}" + local user="{{ getv "/db/root/user" "root" }}" + local password="{{ getv "/db/root/password" "password" }}" + + if [[ "${driver}" == "mysql" ]]; then + echo "Waiting for connection to database." + wait-for-mysql.sh \ + --host "${host}" \ + --port "${port}" \ + --user "${user}" \ + --password "${password}" + + echo "Create databases and users if they do not exist." + mysql \ + --user="${user}" \ + --password="${password}" \ + --host="${host}" \ + --port="${port}" \ + --protocol=tcp \ + < /var/run/islandora/create-drupal-databases.sql + else + echo "Only MySQL databases are supported for now." + exit 1 + fi +} +main diff --git a/drupal/rootfs/etc/confd/templates/create-drupal-databases.sql.tmpl b/drupal/rootfs/etc/confd/templates/create-drupal-databases.sql.tmpl new file mode 100644 index 00000000..778faf3a --- /dev/null +++ b/drupal/rootfs/etc/confd/templates/create-drupal-databases.sql.tmpl @@ -0,0 +1,13 @@ +-- Create deafult sites database in mariadb or mysql. +CREATE DATABASE IF NOT EXISTS {{ getv "/default/db/name" "drupal_default" }} CHARACTER SET utf8 COLLATE utf8_general_ci; +CREATE USER IF NOT EXISTS '{{ getv "/default/db/user" "drupal_default" }}'@'%' IDENTIFIED BY '{{ getv "/default/db/password" "password" }}'; +GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, INDEX, ALTER, CREATE TEMPORARY TABLES ON {{ getv "/default/db/name" "drupal_default" }}.* to '{{ getv "/default/db/user" "drupal_default" }}'@'%' IDENTIFIED BY '{{ getv "/default/db/password" "password" }}'; +FLUSH PRIVILEGES; + +-- Create drupal databases in mariadb or mysql. +{{ range $site := lsdir "/site" }} +CREATE DATABASE IF NOT EXISTS {{ getv (printf "/site/%s/db/name" $site) (printf "drupal_%s" $site) }} CHARACTER SET utf8 COLLATE utf8_general_ci; +CREATE USER IF NOT EXISTS '{{ getv (printf "/site/%s/db/user" $site) (printf "drupal_%s" $site) }}'@'%' IDENTIFIED BY '{{ getv (printf "/site/%s/db/password" $site) "password" }}'; +GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, INDEX, ALTER, CREATE TEMPORARY TABLES ON {{ getv (printf "/site/%s/db/name" $site) (printf "drupal_%s" $site) }}.* to '{{ getv (printf "/site/%s/db/user" $site) (printf "drupal_%s" $site) }}'@'%' IDENTIFIED BY '{{ getv (printf "/site/%s/db/password" $site) "password" }}'; +FLUSH PRIVILEGES; +{{ end }} diff --git a/drupal/rootfs/etc/confd/templates/drupal-install-sites.sh.tmpl b/drupal/rootfs/etc/confd/templates/drupal-install-sites.sh.tmpl new file mode 100644 index 00000000..ea30f79b --- /dev/null +++ b/drupal/rootfs/etc/confd/templates/drupal-install-sites.sh.tmpl @@ -0,0 +1,101 @@ +#!/usr/bin/with-contenv bash + +set -e + +function main { + local site= + local profile= + local subdir= + local name= + local email= + local locale= + local account_name= + local account_password= + local account_email= + local db_driver= + local db_host= + local db_port= + local db_root_user= + local db_root_password= + local db_name= + local db_user= + local db_password= + + # Install the default site. + name="{{ getv "/default/name" "Default" }}" + profile="{{ getv "/default/profile" "standard" }}" + subdir="{{ getv "/default/subdir" "default" }}" + email="{{ getv "/default/email" "webmaster@localhost.com" }}" + local="{{ getv "/default/locale" "en" }}" + account_name="{{ getv "/default/account/name" "admin" }}" + account_password="{{ getv "/default/account/password" "password" }}" + account_email="{{ getv "/default/account/email" "webmaster@localhost.com" }}" + db_driver="{{ getv "/db/driver" "mysql" }}" + db_host="{{ getv "/db/host" "database" }}" + db_port="{{ getv "/db/port" "3306" }}" + db_root_user="{{ getv "/db/root/user" "root" }}" + db_root_password="{{ getv "/db/root/password" "password" }}" + db_name="{{ getv "/default/db/name" "drupal_default" }}" + db_user="{{ getv "/default/db/user" "drupal_default" }}" + db_password="{{ getv "/default/db/password" "password" }}" + + # Check the number of tables to determine if it has already been installed. + count=$(mysql --user="${db_root_user}" --password="${db_root_password}" --host="${db_host}" --port="${db_port}" --protocol=tcp -Ne "SELECT COUNT(DISTINCT table_name) FROM information_schema.columns WHERE table_schema = '${db_name}'") + + # Only install if it is not already installed. + if [[ $count -eq 0 ]]; then + echo "Installing Default site." + s6-setuidgid nginx drush -n si "${profile}" \ + --sites-subdir="${subdir}" \ + --site-name="${name}" \ + --site-mail="${email}" \ + --locale="${local}" \ + --account-name="${account_name}" \ + --account-pass="${account_password}" \ + --account-mail="${account_email}" \ + --db-url="${db_driver}://${db_user}:${db_password}@${db_host}:${db_port}/${db_name}" + else + echo "Default Site already is installed." + fi + + # Install all of the specified sub-sites. +{{ range $site := lsdir "/site" }} + site="{{base $site}}" + name="{{ getv (printf "/site/%s/name" $site) }}" + profile="{{ getv (printf "/site/%s/profile" $site) "standard" }}" + subdir="{{ getv (printf "/site/%s/subdir" $site) "${site}" }}" + email="{{ getv (printf "/site/%s/email" $site) "webmaster@localhost.com" }}" + local="{{ getv (printf "/site/%s/locale" $site) "en" }}" + account_name="{{ getv (printf "/site/%s/account/name" $site) "admin" }}" + account_password="{{ getv (printf "/site/%s/account/password" $site) "password" }}" + account_email="{{ getv (printf "/site/%s/account/email" $site) "webmaster@localhost.com" }}" + db_driver="{{ getv "/db/driver" "mysql" }}" + db_host="{{ getv "/db/host" "database" }}" + db_port="{{ getv "/db/port" "3306" }}" + db_root_user="{{ getv "/db/root/user" "root" }}" + db_root_password="{{ getv "/db/root/password" "password" }}" + db_name="{{ getv (printf "/site/%s/db/name" $site) "drupal_${site}" }}" + db_user="{{ getv (printf "/site/%s/db/user" $site) "drupal_${site}" }}" + db_password="{{ getv (printf "/site/%s/db/password" $site) "password" }}" + + # Check the number of tables to determine if it has already been installed. + count=$(mysql --user="${db_root_user}" --password="${db_root_password}" --host="${db_host}" --port="${db_port}" --protocol=tcp -Ne "SELECT COUNT(DISTINCT table_name) FROM information_schema.columns WHERE table_schema = '${db_name}'") + + # Only install if it is not already installed. + if [[ $count -eq 0 ]]; then + echo "Installing site: {{base $site}}" + s6-setuidgid nginx drush -n si "${profile}" \ + --sites-subdir="${subdir}" \ + --site-name="${name}" \ + --site-mail="${email}" \ + --locale="${local}" \ + --account-name="${account_name}" \ + --account-pass="${account_password}" \ + --account-mail="${account_email}" \ + --db-url="${db_driver}://${db_user}:${db_password}@${db_host}:${db_port}/${db_name}" + else + echo "Site already is installed." + fi +{{ end }} +} +main diff --git a/drupal/rootfs/etc/cont-init.d/03-drupal-setup.sh b/drupal/rootfs/etc/cont-init.d/03-drupal-setup.sh new file mode 100644 index 00000000..5c096dc1 --- /dev/null +++ b/drupal/rootfs/etc/cont-init.d/03-drupal-setup.sh @@ -0,0 +1,4 @@ +#!/usr/bin/with-contenv bash +set -e +/var/run/islandora/create-drupal-databases.sh +/var/run/islandora/drupal-install-sites.sh diff --git a/drupal/rootfs/etc/nginx/conf.d/default.conf b/drupal/rootfs/etc/nginx/conf.d/default.conf new file mode 100644 index 00000000..281eb7fd --- /dev/null +++ b/drupal/rootfs/etc/nginx/conf.d/default.conf @@ -0,0 +1,121 @@ +# From: https://www.nginx.com/resources/wiki/start/topics/recipes/drupal/ +server { + server_name drupal; + root /var/www/drupal/web; + + location = /favicon.ico { + log_not_found off; + access_log off; + } + + location = /robots.txt { + allow all; + log_not_found off; + access_log off; + } + + # Very rarely should these ever be accessed outside of your lan + location ~* \.(txt|log)$ { + allow 192.168.0.0/16; + deny all; + } + + location ~ \..*/.*\.php$ { + return 403; + } + + location ~ ^/sites/.*/private/ { + return 403; + } + + # Block access to scripts in site files directory + location ~ ^/sites/[^/]+/files/.*\.php$ { + deny all; + } + + # Allow "Well-Known URIs" as per RFC 5785 + location ~* ^/.well-known/ { + allow all; + } + + # Block access to "hidden" files and directories whose names begin with a + # period. This includes directories used by version control systems such + # as Subversion or Git to store control files. + location ~ (^|/)\. { + return 403; + } + + location / { + # try_files $uri @rewrite; # For Drupal <= 6 + try_files $uri /index.php?$query_string; # For Drupal >= 7 + } + + location @rewrite { + rewrite ^/(.*)$ /index.php?q=$1; + } + + # Don't allow direct access to PHP files in the vendor directory. + location ~ /vendor/.*\.php$ { + deny all; + return 404; + } + + # Protect files and directories from prying eyes. + location ~* \.(engine|inc|install|make|module|profile|po|sh|.*sql|theme|twig|tpl(\.php)?|xtmpl|yml)(~|\.sw[op]|\.bak|\.orig|\.save)?$|^(\.(?!well-known).*|Entries.*|Repository|Root|Tag|Template|composer\.(json|lock)|web\.config)$|^#.*#$|\.php(~|\.sw[op]|\.bak|\.orig|\.save)$ { + deny all; + return 404; + } + + # In Drupal 8, we must also match new paths where the '.php' appears in + # the middle, such as update.php/selection. The rule we use is strict, + # and only allows this pattern with the update.php front controller. + # This allows legacy path aliases in the form of + # blog/index.php/legacy-path to continue to route to Drupal nodes. If + # you do not have any paths like that, then you might prefer to use a + # laxer rule, such as: + # location ~ \.php(/|$) { + # The laxer rule will continue to work if Drupal uses this new URL + # pattern with front controllers other than update.php in a future + # release. + location ~ '\.php$|^/update.php' { + fastcgi_split_path_info ^(.+?\.php)(|/.*)$; + # Ensure the php file exists. Mitigates CVE-2019-11043 + try_files $fastcgi_script_name =404; + # Security note: If you're running a version of PHP older than the + # latest 5.3, you should have "cgi.fix_pathinfo = 0;" in php.ini. + # See http://serverfault.com/q/627903/94922 for details. + include fastcgi_params; + # Block httpoxy attacks. See https://httpoxy.org/. + fastcgi_param HTTP_PROXY ""; + fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; + fastcgi_param PATH_INFO $fastcgi_path_info; + fastcgi_param QUERY_STRING $query_string; + fastcgi_intercept_errors on; + # PHP 7 socket location. + fastcgi_pass unix:/var/run/php-fpm7/php-fpm7.sock; + } + + # Fighting with Styles? This little gem is amazing. + # location ~ ^/sites/.*/files/imagecache/ { # For Drupal <= 6 + location ~ ^/sites/.*/files/styles/ { # For Drupal >= 7 + try_files $uri @rewrite; + } + + # Handle private files through Drupal. Private file's path can come + # with a language prefix. + location ~ ^(/[a-z\-]+)?/system/files/ { # For Drupal >= 7 + try_files $uri /index.php?$query_string; + } + + location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ { + try_files $uri @rewrite; + expires max; + log_not_found off; + } + # Enforce clean URLs + # Removes index.php from urls like www.example.com/index.php/my-page --> www.example.com/my-page + # Could be done with 301 for permanent or other redirect codes. + if ($request_uri ~* "^(.*/)index\.php(.*)") { + return 307 $1$2; + } +} diff --git a/fcrepo/.dockerignore b/fcrepo/.dockerignore new file mode 100644 index 00000000..b43bf86b --- /dev/null +++ b/fcrepo/.dockerignore @@ -0,0 +1 @@ +README.md diff --git a/fcrepo/Dockerfile b/fcrepo/Dockerfile new file mode 100644 index 00000000..091d4853 --- /dev/null +++ b/fcrepo/Dockerfile @@ -0,0 +1,23 @@ +# syntax=docker/dockerfile:experimental +FROM local/tomcat:latest + +RUN --mount=id=downloads,type=cache,target=/opt/downloads \ + FCREPO_VERSION="5.1.0" && \ + install-war-into-tomcat.sh \ + --name "fcrepo" \ + --url "https://github.com/fcrepo4/fcrepo4/releases/download/fcrepo-${FCREPO_VERSION}/fcrepo-webapp-${FCREPO_VERSION}.war" \ + --key "fdcb43cfd1468a84ddb89c20e4f4c7f54476ab9a24f69beb335d26f2b58ecec5" + +RUN --mount=id=downloads,type=cache,target=/opt/downloads \ + SYN_VERSION="1.1.0" && \ + wget -N -P /opt/downloads https://github.com/Islandora-CLAW/Syn/releases/download/v${SYN_VERSION}/islandora-syn-${SYN_VERSION}-all.jar && \ + cp /opt/downloads/islandora-syn-${SYN_VERSION}-all.jar /opt/tomcat/lib && \ + cleanup.sh + +COPY rootfs / + +RUN mkdir /data && \ + chown tomcat:tomcat /data && \ + chown -R tomcat:tomcat /opt/tomcat + +VOLUME [ "/data" ] diff --git a/fcrepo/README.md b/fcrepo/README.md new file mode 100644 index 00000000..b80152fd --- /dev/null +++ b/fcrepo/README.md @@ -0,0 +1,56 @@ +# Fcrepo + +Docker image for [Fcrepo] version 5.1.0. + +Please refer to the [Fcrepo Documentation] for more in-depth information. + +As a quick example this will bring up an instance of [Fcrepo], and allow you +to view on . + +```bash +docker run --rm -ti -p 80:80 islandora/fcrepo +``` + +## Dependencies + +Requires `islandora/tomcat` docker image to build. Please refer to the +[Tomcat Image README](../tomcat/README.md) for additional information including +additional settings, volumes, ports, etc. + +## Volumes + +| Path | Description | +| :---- | :--------------------------- | +| /data | Fcrepo Object / Binary Store | + +## Settings + +| Environment Variable | Etcd Key | Default | Description | +| :----------------------------- | :------------------------------ | :-------------------------------- | :---------- | +| FCREPO_ACTIVEMQ_QUEUE | /fcrepo/activemq/queue | fedora | | +| FCREPO_ACTIVEMQ_TOPIC | /fcrepo/activemq/topic | fedora | | +| FCREPO_BINARYSTORAGE_TYPE | /fcrepo/binarystorage/type | file | | +| FCREPO_BROKER | /fcrepo/broker | tcp://activemq:61616 | | +| FCREPO_CATALINA_OPTS | /fcrepo/catalina/opts | | | +| FCREPO_DB_NAME | /fcrepo/db/name | fcrepo | | +| FCREPO_DB_PASSWORD | /fcrepo/db/password | password | | +| FCREPO_DB_USER | /fcrepo/db/user | admin | | +| FCREPO_JAVA_OPTS | /fcrepo/java/opts | | | +| FCREPO_JWT_ADMIN_TOKEN | /fcrepo/jwt/admin/token | islandora | | +| FCREPO_MODESHAPE_CONFIGURATION | /fcrepo/modeshape/configuration | classpath:/config/repository.json | | +| FCREPO_PERSISTENCE_TYPE | /fcrepo/persistence/type | file | | +| FCREPO_QUEUE | /fcrepo/queue | fedora | | +| FCREPO_S3_BUCKET | /fcrepo/s3/bucket | | | +| FCREPO_S3_PASSWORD | /fcrepo/s3/password | | | +| FCREPO_S3_USER | /fcrepo/s3/user | | | +| FCREPO_TOPIC | /fcrepo/topic | fedora | | + +## Logs + +| Path | Description | +| :------------------------------------------ | :------------ | +| /opt/tomcat/logs/cantaloupe.access.log | [Fcrepo Logs] | +| /opt/tomcat/logs/cantaloupe.application.log | [Fcrepo Logs] | + +[Fcrepo Documentation]: https://wiki.lyrasis.org/display/FF +[Fcrepo]: https://github.com/fcrepo4/fcrepo4 diff --git a/fcrepo/rootfs/etc/confd/conf.d/activemq.xml.toml b/fcrepo/rootfs/etc/confd/conf.d/activemq.xml.toml new file mode 100644 index 00000000..9b161299 --- /dev/null +++ b/fcrepo/rootfs/etc/confd/conf.d/activemq.xml.toml @@ -0,0 +1,7 @@ +[template] +src = "activemq.xml.tmpl" +dest = "/opt/tomcat/webapps/fcrepo/WEB-INF/classes/config/activemq.xml" +uid = 100 +gid = 1000 +mode = "0640" +keys = [ "/activemq" ] diff --git a/fcrepo/rootfs/etc/confd/conf.d/allowed-external-content.txt.toml b/fcrepo/rootfs/etc/confd/conf.d/allowed-external-content.txt.toml new file mode 100644 index 00000000..bf5ab47b --- /dev/null +++ b/fcrepo/rootfs/etc/confd/conf.d/allowed-external-content.txt.toml @@ -0,0 +1,7 @@ +[template] +src = "allowed-external-content.txt.tmpl" +dest = "/opt/tomcat/webapps/fcrepo/WEB-INF/classes/config/allowed-external-content.txt" +uid = 100 +gid = 1000 +mode = "0640" +keys = [ "/allow/external" ] diff --git a/fcrepo/rootfs/etc/confd/conf.d/claw.cnd.toml b/fcrepo/rootfs/etc/confd/conf.d/claw.cnd.toml new file mode 100644 index 00000000..298e52d0 --- /dev/null +++ b/fcrepo/rootfs/etc/confd/conf.d/claw.cnd.toml @@ -0,0 +1,6 @@ +[template] +src = "claw.cnd.tmpl" +dest = "/opt/tomcat/webapps/fcrepo/WEB-INF/classes/config/claw.cnd" +uid = 100 +gid = 1000 +mode = "0655" diff --git a/fcrepo/rootfs/etc/confd/conf.d/context.xml.toml b/fcrepo/rootfs/etc/confd/conf.d/context.xml.toml new file mode 100644 index 00000000..16c8f081 --- /dev/null +++ b/fcrepo/rootfs/etc/confd/conf.d/context.xml.toml @@ -0,0 +1,6 @@ +[template] +src = "context.xml.tmpl" +dest = "/opt/tomcat/conf/context.xml" +uid = 100 +gid = 1000 +mode = "0640" diff --git a/fcrepo/rootfs/etc/confd/conf.d/fcrepo-config.xml.toml b/fcrepo/rootfs/etc/confd/conf.d/fcrepo-config.xml.toml new file mode 100644 index 00000000..e994be5b --- /dev/null +++ b/fcrepo/rootfs/etc/confd/conf.d/fcrepo-config.xml.toml @@ -0,0 +1,7 @@ +[template] +src = "fcrepo-config.xml.tmpl" +dest = "/opt/tomcat/webapps/fcrepo/WEB-INF/classes/spring/fcrepo-config.xml" +uid = 100 +gid = 1000 +mode = "0640" +keys = [ "/activemq" ] diff --git a/fcrepo/rootfs/etc/confd/conf.d/repository.json.toml b/fcrepo/rootfs/etc/confd/conf.d/repository.json.toml new file mode 100644 index 00000000..0bcba8f5 --- /dev/null +++ b/fcrepo/rootfs/etc/confd/conf.d/repository.json.toml @@ -0,0 +1,7 @@ +[template] +src = "repository.json.tmpl" +dest = "/opt/tomcat/webapps/fcrepo/WEB-INF/classes/config/repository.json" +uid = 100 +gid = 1000 +mode = "0640" +keys = [ "/" ] diff --git a/fcrepo/rootfs/etc/confd/conf.d/setenv.sh.toml b/fcrepo/rootfs/etc/confd/conf.d/setenv.sh.toml new file mode 100644 index 00000000..45d63894 --- /dev/null +++ b/fcrepo/rootfs/etc/confd/conf.d/setenv.sh.toml @@ -0,0 +1,7 @@ +[template] +src = "setenv.sh.tmpl" +dest = "/opt/tomcat/bin/setenv.sh" +uid = 100 +gid = 1000 +mode = "0655" +keys = [ "/modeshape/configuration" ] diff --git a/fcrepo/rootfs/etc/confd/conf.d/syn-settings.xml.toml b/fcrepo/rootfs/etc/confd/conf.d/syn-settings.xml.toml new file mode 100644 index 00000000..58529b7e --- /dev/null +++ b/fcrepo/rootfs/etc/confd/conf.d/syn-settings.xml.toml @@ -0,0 +1,7 @@ +[template] +src = "syn-settings.xml.tmpl" +dest = "/opt/tomcat/conf/syn-settings.xml" +uid = 100 +gid = 1000 +mode = "0655" +keys = [ "/jwt/admin/token" ] diff --git a/fcrepo/rootfs/etc/confd/confd.toml b/fcrepo/rootfs/etc/confd/confd.toml new file mode 100644 index 00000000..68d47055 --- /dev/null +++ b/fcrepo/rootfs/etc/confd/confd.toml @@ -0,0 +1,6 @@ +backend = "env" +confdir = "/etc/confd" +log-level = "debug" +interval = 600 +noop = false +prefix = "/fcrepo" diff --git a/fcrepo/rootfs/etc/confd/templates/activemq.xml.tmpl b/fcrepo/rootfs/etc/confd/templates/activemq.xml.tmpl new file mode 100644 index 00000000..ae9a82dd --- /dev/null +++ b/fcrepo/rootfs/etc/confd/templates/activemq.xml.tmpl @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/fcrepo/rootfs/etc/confd/templates/allowed-external-content.txt.tmpl b/fcrepo/rootfs/etc/confd/templates/allowed-external-content.txt.tmpl new file mode 100644 index 00000000..edf7b551 --- /dev/null +++ b/fcrepo/rootfs/etc/confd/templates/allowed-external-content.txt.tmpl @@ -0,0 +1,3 @@ +http://drupal:80/ +{{ range gets "/fcrepo/allow/external/*" }}{{.Value}} +{{ end }} \ No newline at end of file diff --git a/fcrepo/rootfs/etc/confd/templates/claw.cnd.tmpl b/fcrepo/rootfs/etc/confd/templates/claw.cnd.tmpl new file mode 100644 index 00000000..404341f4 --- /dev/null +++ b/fcrepo/rootfs/etc/confd/templates/claw.cnd.tmpl @@ -0,0 +1,34 @@ +/* + * Islandora CLAW namespaces + */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/fcrepo/rootfs/etc/confd/templates/context.xml.tmpl b/fcrepo/rootfs/etc/confd/templates/context.xml.tmpl new file mode 100644 index 00000000..40ad286d --- /dev/null +++ b/fcrepo/rootfs/etc/confd/templates/context.xml.tmpl @@ -0,0 +1,8 @@ + + + + + WEB-INF/web.xml + ${catalina.base}/conf/web.xml + + diff --git a/fcrepo/rootfs/etc/confd/templates/fcrepo-config.xml.tmpl b/fcrepo/rootfs/etc/confd/templates/fcrepo-config.xml.tmpl new file mode 100644 index 00000000..4fbae2e8 --- /dev/null +++ b/fcrepo/rootfs/etc/confd/templates/fcrepo-config.xml.tmpl @@ -0,0 +1,258 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + /** = servletContainerAuthFilter,headerProvider,delegatedPrincipalProvider,webACFilter + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/fcrepo/rootfs/etc/confd/templates/repository.json.tmpl b/fcrepo/rootfs/etc/confd/templates/repository.json.tmpl new file mode 100644 index 00000000..732616b5 --- /dev/null +++ b/fcrepo/rootfs/etc/confd/templates/repository.json.tmpl @@ -0,0 +1,66 @@ +{ + "name" : "repo", + "jndiName" : "", + "workspaces" : { + "predefined" : ["default"], + "default" : "default", + "allowCreation" : true, + "cacheSize" : 10000 + }, + "storage" : { + {{ if eq (getv "/persistence/type" "file") "file" }} + "persistence": { + "type": "file", + "path" : "/data/objects" + }, + {{ end }} + {{ if eq (getv "/persistence/type" "file") "mysql" }} + "persistence": { + "type" : "db", + "connectionUrl": "jdbc:mysql://{{ getv "/db/host" "database" }}:{{ getv "/db/port" "3306" }}/{{ getv "/db/name" "fcrepo" }}?createDatabaseIfNotExist=true", + "driver" : "com.mysql.jdbc.Driver", + "username" : "{{ getv "/db/user" "admin" }}", + "password" : "{{ getv "/db/password" "password" }}" + }, + {{ end }} + {{ if eq (getv "/persistence/type" "file") "postgresql" }} + "persistence": { + "type" : "db", + "connectionUrl": "jdbc:postgresql://{{ getv "/db/host" "database" }}:{{ getv "/db/port" "5432" }}/{{ getv "/db/name" "fcrepo" }}?createDatabaseIfNotExist=true", + "driver" : "org.postgresql.Driver", + "username" : "{{ getv "/db/user" "admin" }}", + "password" : "{{ getv "/db/password" "password" }}" + }, + {{ end }} + {{ if eq (getv "/binarystorage/type" "file") "file" }} + "binaryStorage" : { + "type" : "file", + "directory" : "/data/binaries", + "minimumBinarySizeInBytes" : 4096 + } + {{ end }} + {{ if eq (getv "/binarystorage/type" "file") "s3" }} + "binaryStorage" : { + "type" : "s3", + "username" : "{{ getv "/s3/user" }}", + "password" : "{{ getv "/s3/password" }}", + "bucketName" : "{{ getv "/s3/bucket" }}" + } + {{ end }} + }, + "security" : { + "anonymous" : { + "roles" : ["readonly","readwrite","admin"], + "useOnFailedLogin" : false + }, + "providers" : [ + { "classname" : "org.fcrepo.auth.common.BypassSecurityServletAuthenticationProvider" } + ] + }, + "garbageCollection" : { + "threadPool" : "modeshape-gc", + "initialTime" : "00:00", + "intervalInHours" : 24 + }, + "node-types" : ["fedora-node-types.cnd", "file:/opt/tomcat/webapps/fcrepo/WEB-INF/classes/config/claw.cnd"] +} diff --git a/fcrepo/rootfs/etc/confd/templates/setenv.sh.tmpl b/fcrepo/rootfs/etc/confd/templates/setenv.sh.tmpl new file mode 100644 index 00000000..0f190348 --- /dev/null +++ b/fcrepo/rootfs/etc/confd/templates/setenv.sh.tmpl @@ -0,0 +1,6 @@ +#!/bin/sh +export JAVA_OPTS="{{ getv "/java/opts" "" }}" +export CATALINA_OPTS="{{ getv "/catalina/opts" "" }}" +export CATALINA_OPTS="${CATALINA_OPTS} -Dfcrepo.home=/data/home" +export CATALINA_OPTS="${CATALINA_OPTS} -Dfcrepo.velocity.runtime.log=/opt/tomcat/logs/velocity.log" +export CATALINA_OPTS="${CATALINA_OPTS} -Dfcrepo.modeshape.configuration={{ getv "/modeshape/configuration" "classpath:/config/repository.json" }} -Dfcrepo.jms.baseUrl=http://{{ index (lookupIP (getenv "HOSTNAME")) 0 }}/fcrepo/rest" diff --git a/fcrepo/rootfs/etc/confd/templates/syn-settings.xml.tmpl b/fcrepo/rootfs/etc/confd/templates/syn-settings.xml.tmpl new file mode 100644 index 00000000..db446624 --- /dev/null +++ b/fcrepo/rootfs/etc/confd/templates/syn-settings.xml.tmpl @@ -0,0 +1,6 @@ + + + + {{ getv "/jwt/admin/token" "islandora" }} + + diff --git a/fcrepo/rootfs/etc/cont-init.d/03-fcrepo-setup.sh b/fcrepo/rootfs/etc/cont-init.d/03-fcrepo-setup.sh new file mode 100644 index 00000000..fb146fd4 --- /dev/null +++ b/fcrepo/rootfs/etc/cont-init.d/03-fcrepo-setup.sh @@ -0,0 +1,5 @@ +#!/usr/bin/with-contenv bash +set -e +# Key needs to be present before startup otherwise, +# it will ignore subsequent requests even if the key has been generated. +timeout 300 bash -c 'until [[ -f /opt/keys/claw/public.key ]]; do sleep 1; done' diff --git a/fits/.dockerignore b/fits/.dockerignore new file mode 100644 index 00000000..b43bf86b --- /dev/null +++ b/fits/.dockerignore @@ -0,0 +1 @@ +README.md diff --git a/fits/Dockerfile b/fits/Dockerfile new file mode 100644 index 00000000..06c370f5 --- /dev/null +++ b/fits/Dockerfile @@ -0,0 +1,17 @@ +# syntax=docker/dockerfile:experimental +FROM local/tomcat:latest + +RUN --mount=id=downloads,type=cache,target=/opt/downloads \ + FITSSERVLET_VERSION=1.2.1 && \ + install-war-into-tomcat.sh \ + --name "fits" \ + --url "http://projects.iq.harvard.edu/files/fits/files/fits-${FITSSERVLET_VERSION}.war" \ + --key "13cfcb910092b197757e459353f0c30381febfca6baf3031ac69ff92789b200c" && \ + FITS_VERSION="1.5.0" && \ + FITS_CHECKSUM="1378a78892db103b3a00e45c510b58c70e19a1a401b3720ff4d64a51438bfe0b" && \ + mkdir /opt/fits && \ + wget -N -P /opt/downloads "https://github.com/harvard-lts/fits/releases/download/${FITS_VERSION}/fits-${FITS_VERSION}.zip" && \ + sha256sum "/opt/downloads/fits-${FITS_VERSION}.zip" | cut -f1 -d' ' | xargs test "${FITS_CHECKSUM}" == && \ + unzip /opt/downloads/fits-${FITS_VERSION}.zip -d /opt/fits + +COPY rootfs / diff --git a/fits/README.md b/fits/README.md new file mode 100644 index 00000000..71e7a970 --- /dev/null +++ b/fits/README.md @@ -0,0 +1,36 @@ +# Fits + +Docker image for [Fits] version 5.1.0. + +Please refer to the [Fits Documentation] for more in-depth information. + +As a quick example this will bring up an instance of [Fits], and allow you +to view on . + +```bash +docker run --rm -ti -p 80:80 islandora/fits +``` + +## Dependencies + +Requires `islandora/tomcat` docker image to build. Please refer to the +[Tomcat Image README](../tomcat/README.md) for additional information including +additional settings, volumes, ports, etc. + +## Settings + +| Environment Variable | Etcd Key | Default | Description | +| :--------------------------- | :---------------------------- | :------ | :------------------------------------------------------------------------------------------------------------------- | +| FITS_MAX_IN_MEMORY_FILE_SIZE | /fits/max/in/memory/file/size | 4 | Maximum size of an uploaded size kept in memory in MiB. Otherwise temporarily persisted to disk. | +| FITS_MAX_OBJECTS_IN_POOL | /fits/max/objects/in/pool | 5 | Number of objects in FITSServlet object pool. | +| FITS_MAX_REQUEST_SIZE | /fits/max/request/size | 2000 | Maximum size of HTTP Request object in MiB. Must be equal to or larger than the value for /fits/max/upload/file/size | +| FITS_MAX_UPLOAD_FILE_SIZE | /fits/max/upload/file/size | 2000 | Maximum allowable size of uploaded file in MiB. | + +## Logs + +| Path | Description | +| :-------------------------------- | :---------- | +| /opt/tomcat/logs/fits-service.log | | + +[Fits Documentation]: https://wiki.lyrasis.org/display/FF +[Fits]: https://github.com/fits4/fits4 diff --git a/fits/rootfs/etc/confd/conf.d/catalina.properties.toml b/fits/rootfs/etc/confd/conf.d/catalina.properties.toml new file mode 100644 index 00000000..cc6b2a90 --- /dev/null +++ b/fits/rootfs/etc/confd/conf.d/catalina.properties.toml @@ -0,0 +1,6 @@ +[template] +src = "catalina.properties.tmpl" +dest = "/opt/tomcat/conf/catalina.properties" +uid = 100 +gid = 1000 +mode = "0644" diff --git a/fits/rootfs/etc/confd/conf.d/fits-service.properties.toml b/fits/rootfs/etc/confd/conf.d/fits-service.properties.toml new file mode 100644 index 00000000..8a27f595 --- /dev/null +++ b/fits/rootfs/etc/confd/conf.d/fits-service.properties.toml @@ -0,0 +1,7 @@ +[template] +src = "fits-service.properties.tmpl" +dest = "/opt/tomcat/conf/fit-service.properties" +uid = 100 +gid = 1000 +mode = "0644" +keys = ["/"] diff --git a/fits/rootfs/etc/confd/confd.toml b/fits/rootfs/etc/confd/confd.toml new file mode 100644 index 00000000..331ea474 --- /dev/null +++ b/fits/rootfs/etc/confd/confd.toml @@ -0,0 +1,6 @@ +backend = "env" +confdir = "/etc/confd" +log-level = "debug" +interval = 600 +noop = false +prefix = "/fits" diff --git a/fits/rootfs/etc/confd/templates/catalina.properties.tmpl b/fits/rootfs/etc/confd/templates/catalina.properties.tmpl new file mode 100644 index 00000000..eeb706b0 --- /dev/null +++ b/fits/rootfs/etc/confd/templates/catalina.properties.tmpl @@ -0,0 +1,147 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# +# List of comma-separated packages that start with or equal this string +# will cause a security exception to be thrown when +# passed to checkPackageAccess unless the +# corresponding RuntimePermission ("accessClassInPackage."+package) has +# been granted. +package.access=sun.,org.apache.catalina.,org.apache.coyote.,org.apache.jasper.,org.apache.tomcat. +# +# List of comma-separated packages that start with or equal this string +# will cause a security exception to be thrown when +# passed to checkPackageDefinition unless the +# corresponding RuntimePermission ("defineClassInPackage."+package) has +# been granted. +# +# by default, no packages are restricted for definition, and none of +# the class loaders supplied with the JDK call checkPackageDefinition. +# +package.definition=sun.,java.,org.apache.catalina.,org.apache.coyote.,\ +org.apache.jasper.,org.apache.naming.,org.apache.tomcat. + +# +# +# List of comma-separated paths defining the contents of the "common" +# classloader. Prefixes should be used to define what is the repository type. +# Path may be relative to the CATALINA_HOME or CATALINA_BASE path or absolute. +# If left as blank,the JVM system loader will be used as Catalina's "common" +# loader. +# Examples: +# "foo": Add this folder as a class repository +# "foo/*.jar": Add all the JARs of the specified folder as class +# repositories +# "foo/bar.jar": Add bar.jar as a class repository +# +# Note: Values are enclosed in double quotes ("...") in case either the +# ${catalina.base} path or the ${catalina.home} path contains a comma. +# Because double quotes are used for quoting, the double quote character +# may not appear in a path. +common.loader="${catalina.base}/lib","${catalina.base}/lib/*.jar","${catalina.home}/lib","${catalina.home}/lib/*.jar" + +# +# List of comma-separated paths defining the contents of the "server" +# classloader. Prefixes should be used to define what is the repository type. +# Path may be relative to the CATALINA_HOME or CATALINA_BASE path or absolute. +# If left as blank, the "common" loader will be used as Catalina's "server" +# loader. +# Examples: +# "foo": Add this folder as a class repository +# "foo/*.jar": Add all the JARs of the specified folder as class +# repositories +# "foo/bar.jar": Add bar.jar as a class repository +# +# Note: Values may be enclosed in double quotes ("...") in case either the +# ${catalina.base} path or the ${catalina.home} path contains a comma. +# Because double quotes are used for quoting, the double quote character +# may not appear in a path. +server.loader= + +fits.home=/opt/fits +# +# List of comma-separated paths defining the contents of the "shared" +# classloader. Prefixes should be used to define what is the repository type. +# Path may be relative to the CATALINA_BASE path or absolute. If left as blank, +# the "common" loader will be used as Catalina's "shared" loader. +# Examples: +# "foo": Add this folder as a class repository +# "foo/*.jar": Add all the JARs of the specified folder as class +# repositories +# "foo/bar.jar": Add bar.jar as a class repository +# Please note that for single jars, e.g. bar.jar, you need the URL form +# starting with file:. +# +# Note: Values may be enclosed in double quotes ("...") in case either the +# ${catalina.base} path or the ${catalina.home} path contains a comma. +# Because double quotes are used for quoting, the double quote character +# may not appear in a path. +shared.loader=${fits.home}/lib/*.jar + +# Default list of JAR files that should not be scanned using the JarScanner +# functionality. This is typically used to scan JARs for configuration +# information. JARs that do not contain such information may be excluded from +# the scan to speed up the scanning process. This is the default list. JARs on +# this list are excluded from all scans. The list must be a comma separated list +# of JAR file names. +# The list of JARs to skip may be over-ridden at a Context level for individual +# scan types by configuring a JarScanner with a nested JarScanFilter. +# The JARs listed below include: +# - Tomcat Bootstrap JARs +# - Tomcat API JARs +# - Catalina JARs +# - Jasper JARs +# - Tomcat JARs +# - Common non-Tomcat JARs +# - Test JARs (JUnit, Cobertura and dependencies) +tomcat.util.scan.StandardJarScanFilter.jarsToSkip=\ +bootstrap.jar,commons-daemon.jar,tomcat-juli.jar,\ +annotations-api.jar,el-api.jar,jsp-api.jar,servlet-api.jar,websocket-api.jar,\ +catalina.jar,catalina-ant.jar,catalina-ha.jar,catalina-storeconfig.jar,\ +catalina-tribes.jar,\ +jasper.jar,jasper-el.jar,ecj-*.jar,\ +tomcat-api.jar,tomcat-util.jar,tomcat-util-scan.jar,tomcat-coyote.jar,\ +tomcat-dbcp.jar,tomcat-jni.jar,tomcat-websocket.jar,\ +tomcat-i18n-en.jar,tomcat-i18n-es.jar,tomcat-i18n-fr.jar,tomcat-i18n-ja.jar,\ +tomcat-juli-adapters.jar,catalina-jmx-remote.jar,catalina-ws.jar,\ +tomcat-jdbc.jar,\ +tools.jar,\ +commons-beanutils*.jar,commons-codec*.jar,commons-collections*.jar,\ +commons-dbcp*.jar,commons-digester*.jar,commons-fileupload*.jar,\ +commons-httpclient*.jar,commons-io*.jar,commons-lang*.jar,commons-logging*.jar,\ +commons-math*.jar,commons-pool*.jar,\ +jstl.jar,taglibs-standard-spec-*.jar,\ +geronimo-spec-jaxrpc*.jar,wsdl4j*.jar,\ +ant.jar,ant-junit*.jar,aspectj*.jar,jmx.jar,h2*.jar,hibernate*.jar,httpclient*.jar,\ +jmx-tools.jar,jta*.jar,log4j*.jar,mail*.jar,slf4j*.jar,\ +xercesImpl.jar,xmlParserAPIs.jar,xml-apis.jar,\ +junit.jar,junit-*.jar,ant-launcher.jar,\ +cobertura-*.jar,asm-*.jar,dom4j-*.jar,icu4j-*.jar,jaxen-*.jar,jdom-*.jar,\ +jetty-*.jar,oro-*.jar,servlet-api-*.jar,tagsoup-*.jar,xmlParserAPIs-*.jar,\ +xom-*.jar + +# Default list of JAR files that should be scanned that overrides the default +# jarsToSkip list above. This is typically used to include a specific JAR that +# has been excluded by a broad file name pattern in the jarsToSkip list. +# The list of JARs to scan may be over-ridden at a Context level for individual +# scan types by configuring a JarScanner with a nested JarScanFilter. +tomcat.util.scan.StandardJarScanFilter.jarsToScan=log4j-core*.jar,log4j-taglib*.jar,log4javascript*.jar + +# String cache configuration. +tomcat.util.buf.StringCache.byte.enabled=true +#tomcat.util.buf.StringCache.char.enabled=true +#tomcat.util.buf.StringCache.trainThreshold=500000 +#tomcat.util.buf.StringCache.cacheSize=5000 +FITS_SERVICE_PROPS=/opt/tomcat/conf/fits-service.properties diff --git a/fits/rootfs/etc/confd/templates/fits-service.properties.tmpl b/fits/rootfs/etc/confd/templates/fits-service.properties.tmpl new file mode 100644 index 00000000..6edb5e70 --- /dev/null +++ b/fits/rootfs/etc/confd/templates/fits-service.properties.tmpl @@ -0,0 +1,8 @@ +# Number of objects in FITSServlet object pool +max.objects.in.pool={{ getv "/max/objects/in/pool" "5" }} +# Maximum allowable size of uploaded file +max.upload.file.size.MB={{ getv "/max/upload/file/size" "2000" }} +# Maximum size of HTTP Request object. Must be equal to or larger than the value for max.upload.file.size.MB +max.request.size.MB={{ getv "/max/request/size" "2000" }} +# Maximum size of an uploaded size kept in memory. Otherwise temporarily persisted to disk. +max.in.memory.file.size.MB={{ getv "/max/in/memory/file/size" "4" }} diff --git a/gemini/.dockerignore b/gemini/.dockerignore new file mode 100644 index 00000000..b43bf86b --- /dev/null +++ b/gemini/.dockerignore @@ -0,0 +1 @@ +README.md diff --git a/gemini/Dockerfile b/gemini/Dockerfile new file mode 100644 index 00000000..b2fb897a --- /dev/null +++ b/gemini/Dockerfile @@ -0,0 +1,11 @@ +# syntax=docker/dockerfile:experimental +FROM local/crayfish:latest + +RUN --mount=type=cache,target=/root/.composer/cache \ + composer install -d /var/www/crayfish/Gemini && \ + ln -s /var/www/crayfish/Gemini/src /var/www/html && \ + cleanup.sh + +COPY /rootfs / + +WORKDIR /var/www/crayfish/Gemini/ diff --git a/gemini/README.md b/gemini/README.md new file mode 100644 index 00000000..38a79cff --- /dev/null +++ b/gemini/README.md @@ -0,0 +1,32 @@ +# Gemini + +Docker image for [Gemini]. + +## Dependencies + +Requires `islandora/crayfish` docker image to build. Please refer to the +[Crayfish Image README](../crayfish/README.md) for additional information including +additional settings, volumes, ports, etc. + +## Settings + +| Environment Variable | Etcd Key | Default | Description | +| :---------------------- | :----------------------- | :---------------------- | :---------------------------------------------------------- | +| GEMINI_DB_DRIVER | /gemini/db/driver | pdo_mysql | The database driver to use | +| GEMINI_DB_HOST | /gemini/db/host | database | The database host | +| GEMINI_DB_NAME | /gemini/db/name | gemini | The database name | +| GEMINI_DB_PASSWORD | /gemini/db/password | password | The database user password | +| GEMINI_DB_PORT | /gemini/db/port | 3306 | The database port | +| GEMINI_DB_ROOT_PASSWORD | /gemini/db/root/password | password | The root user password (used to create the database / user) | +| GEMINI_DB_ROOT_USER | /gemini/db/root/user | root | The root user (used to create the database / user) | +| GEMINI_DB_USER | /gemini/db/user | gemini | The user to create / use when interacting with the database | +| GEMINI_FCREPO_URL | /gemini/fcrepo/url | fcrepo/fcrepo/rest | Fcrepo Rest API URL | +| GEMINI_LOG_LEVEL | /gemini/log/level | WARNING | The log level for Gemini micro-service | + +## Logs + +| Path | Description | +| :---------------------------- | :---------- | +| /var/log/islandora/gemini.log | Gemini Log | + +[Gemini]: https://github.com/Islandora/Crayfish/tree/master/Gemini diff --git a/gemini/rootfs/etc/confd/conf.d/config.yaml.toml b/gemini/rootfs/etc/confd/conf.d/config.yaml.toml new file mode 100644 index 00000000..d6d186a0 --- /dev/null +++ b/gemini/rootfs/etc/confd/conf.d/config.yaml.toml @@ -0,0 +1,7 @@ +[template] +src = "config.yaml.tmpl" +dest = "/var/www/crayfish/Gemini/cfg/config.yaml" +uid = 100 +gid = 101 +mode = "0644" +keys = [ "/log/level", "/db", "/fcrepo" ] diff --git a/gemini/rootfs/etc/confd/conf.d/create-gemini-database.sh.toml b/gemini/rootfs/etc/confd/conf.d/create-gemini-database.sh.toml new file mode 100644 index 00000000..a98c7fed --- /dev/null +++ b/gemini/rootfs/etc/confd/conf.d/create-gemini-database.sh.toml @@ -0,0 +1,7 @@ +[template] +src = "create-gemini-database.sh.tmpl" +dest = "/var/run/islandora/create-gemini-database.sh" +uid = 0 +gid = 0 +mode = "0700" +keys = [ "/db" ] diff --git a/gemini/rootfs/etc/confd/conf.d/create-gemini-database.sql.toml b/gemini/rootfs/etc/confd/conf.d/create-gemini-database.sql.toml new file mode 100644 index 00000000..5c36f8af --- /dev/null +++ b/gemini/rootfs/etc/confd/conf.d/create-gemini-database.sql.toml @@ -0,0 +1,7 @@ +[template] +src = "create-gemini-database.sql.tmpl" +dest = "/var/run/islandora/create-gemini-database.sql" +uid = 0 +gid = 0 +mode = "0600" +keys = [ "/db" ] diff --git a/gemini/rootfs/etc/confd/confd.toml b/gemini/rootfs/etc/confd/confd.toml new file mode 100644 index 00000000..fa30a27d --- /dev/null +++ b/gemini/rootfs/etc/confd/confd.toml @@ -0,0 +1,6 @@ +backend = "env" +confdir = "/etc/confd" +log-level = "debug" +interval = 600 +noop = false +prefix = "/gemini" diff --git a/gemini/rootfs/etc/confd/templates/config.yaml.tmpl b/gemini/rootfs/etc/confd/templates/config.yaml.tmpl new file mode 100644 index 00000000..3693d4c7 --- /dev/null +++ b/gemini/rootfs/etc/confd/templates/config.yaml.tmpl @@ -0,0 +1,24 @@ +--- +debug: True +fedora_resource: + base_url: {{ getv "/fcrepo/url" "http://fcrepo/fcrepo/rest" }} +log: + # Valid log levels are: + # DEBUG, INFO, NOTICE, WARNING, ERROR, CRITICAL, ALERT, EMERGENCY, NONE + # log level none won't open logfile + level: {{ getv "/log/level" "DEBUG" }} + file: /var/log/islandora/gemini.log +syn: + # toggles JWT security for service + enable: true + # Path to the syn config file for authentication. + # example can be found here: + # https://github.com/Islandora/Syn/blob/master/conf/syn-settings.example.xml + config: /var/www/crayfish/syn-settings.xml +db.options: + driver: {{ getv "/db/driver" "pdo_mysql" }} + host: {{ getv "/db/host" "database" }} + port: {{ getv "/db/port" "3306" }} + dbname: {{ getv "/db/name" "gemini" }} + user: {{ getv "/db/user" "gemini" }} + password: {{ getv "/db/password" "password" }} diff --git a/gemini/rootfs/etc/confd/templates/create-gemini-database.sh.tmpl b/gemini/rootfs/etc/confd/templates/create-gemini-database.sh.tmpl new file mode 100644 index 00000000..3749c12e --- /dev/null +++ b/gemini/rootfs/etc/confd/templates/create-gemini-database.sh.tmpl @@ -0,0 +1,33 @@ +#!/usr/bin/with-contenv bash + +set -e + +function main { + local driver="{{ getv "/db/driver" "pdo_mysql" }}" + local host="{{ getv "/db/host" "database" }}" + local port="{{ getv "/db/port" "3306" }}" + local user="{{ getv "/db/root/user" "root" }}" + local password="{{ getv "/db/root/password" "password" }}" + + if [[ "${driver}" == "pdo_mysql" ]]; then + echo "Waiting for connection to database." + wait-for-mysql.sh \ + --host "${host}" \ + --port "${port}" \ + --user "${user}" \ + --password "${password}" + + echo "Create database / user if it does not exist." + mysql \ + --user="${user}" \ + --password="${password}" \ + --host="${host}" \ + --port="${port}" \ + --protocol=tcp \ + < /var/run/islandora/create-gemini-database.sql + else + echo "Only MySQL databases are supported for now." + exit 1 + fi +} +main diff --git a/gemini/rootfs/etc/confd/templates/create-gemini-database.sql.tmpl b/gemini/rootfs/etc/confd/templates/create-gemini-database.sql.tmpl new file mode 100644 index 00000000..87f6fce2 --- /dev/null +++ b/gemini/rootfs/etc/confd/templates/create-gemini-database.sql.tmpl @@ -0,0 +1,13 @@ +-- Create gemini database in mariadb or mysql. +CREATE DATABASE IF NOT EXISTS {{ getv "/db/name" "gemini" }} CHARACTER SET utf8 COLLATE utf8_general_ci; + +CREATE TABLE IF NOT EXISTS {{ getv "/db/name" "gemini" }}.Gemini ( + id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY, + drupal VARCHAR(2048) NOT NULL UNIQUE, + fedora VARCHAR(2048) NOT NULL UNIQUE +) ENGINE=InnoDB; + +-- Create gemini_user and grant rights. +CREATE USER IF NOT EXISTS '{{ getv "/db/user" "gemini" }}'@'%' IDENTIFIED BY '{{ getv "/db/password" "password" }}'; +GRANT ALL PRIVILEGES ON {{ getv "/db/name" "gemini" }}.* to '{{ getv "/db/user" "gemini" }}'@'%'; +FLUSH PRIVILEGES; diff --git a/gemini/rootfs/etc/cont-init.d/03-gemini-setup.sh b/gemini/rootfs/etc/cont-init.d/03-gemini-setup.sh new file mode 100644 index 00000000..2fa3ee8a --- /dev/null +++ b/gemini/rootfs/etc/cont-init.d/03-gemini-setup.sh @@ -0,0 +1,4 @@ +#!/usr/bin/with-contenv bash +set -e +/var/run/islandora/create-gemini-database.sh +php bin/console --no-interaction migrations:migrate diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 00000000..f72501a1 --- /dev/null +++ b/gradle.properties @@ -0,0 +1,20 @@ +org.gradle.parallel=true +# Will be used as a tag to denote the images release. +version=0.0.1 +# The project can be build with/without Buildkit for those on older versions of Docker earlier than '18.09' or who +# cannot use the 'overlay2' filesystem with Docker due to using an earlier kernel version than 4.0. +useBuildKit=true +# The repository path to use for all images when building, defaults to local. +# Override to push to your choosen remote repository. +repository=local +# The remote repository to use as a cache for images when building. +# Override to pull from your private remote repository. +cacheRepository=islandora +# Location and credentials for pushing images. +registryUrl=https://index.docker.io/v1 +registryUsername= +registryPassword= +# Tags to add to all images, can be overridden on a project by project basis. +tags= +# By default all images have a 'prod' environment, even if they ignore it in the build, although some also have 'dev'. +environments=prod diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 00000000..490fda85 Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000..a4b44297 --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-6.3-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew new file mode 100755 index 00000000..2fe81a7d --- /dev/null +++ b/gradlew @@ -0,0 +1,183 @@ +#!/usr/bin/env sh + +# +# Copyright 2015 the original author or authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin or MSYS, switch paths to Windows format before running java +if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=`expr $i + 1` + done + case $i in + 0) set -- ;; + 1) set -- "$args0" ;; + 2) set -- "$args0" "$args1" ;; + 3) set -- "$args0" "$args1" "$args2" ;; + 4) set -- "$args0" "$args1" "$args2" "$args3" ;; + 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=`save "$@"` + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 00000000..62bd9b9c --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,103 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windows variants + +if not "%OS%" == "Windows_NT" goto win9xME_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/homarus/.dockerignore b/homarus/.dockerignore new file mode 100644 index 00000000..b43bf86b --- /dev/null +++ b/homarus/.dockerignore @@ -0,0 +1 @@ +README.md diff --git a/homarus/Dockerfile b/homarus/Dockerfile new file mode 100644 index 00000000..a0e54691 --- /dev/null +++ b/homarus/Dockerfile @@ -0,0 +1,20 @@ +# syntax=docker/dockerfile:experimental +FROM local/crayfish:latest + +RUN --mount=type=cache,target=/var/cache/apk \ + --mount=type=cache,target=/etc/cache/apk \ + apk-install.sh \ + ffmpeg \ + && \ + cleanup.sh + +RUN --mount=type=cache,target=/root/.composer/cache \ + composer install -d /var/www/crayfish/Homarus && \ + ln -s /var/www/crayfish/Homarus/src /var/www/html && \ + cleanup.sh + +COPY /rootfs / + +RUN chown -R nginx:nginx /var/www + +WORKDIR /var/www/crayfish/Homarus/ diff --git a/homarus/README.md b/homarus/README.md new file mode 100644 index 00000000..8d38ca37 --- /dev/null +++ b/homarus/README.md @@ -0,0 +1,23 @@ +# Homarus + +Docker image for [Homarus]. + +## Dependencies + +Requires `islandora/crayfish` docker image to build. Please refer to the +[Crayfish Image README](../crayfish/README.md) for additional information including +additional settings, volumes, ports, etc. + +## Settings + +| Environment Variable | Etcd Key | Default | Description | +| :------------------- | :----------------- | :------ | :-------------------------------------- | +| HOMARUS_LOG_LEVEL | /homarus/log/level | WARNING | The log level for Homarus micro-service | + +## Logs + +| Path | Description | +| :----------------------------- | :---------- | +| /var/log/islandora/homarus.log | Homarus Log | + +[Homarus]: https://github.com/Islandora/Crayfish/tree/master/Homarus diff --git a/homarus/rootfs/etc/confd/conf.d/config.yaml.toml b/homarus/rootfs/etc/confd/conf.d/config.yaml.toml new file mode 100644 index 00000000..73251e38 --- /dev/null +++ b/homarus/rootfs/etc/confd/conf.d/config.yaml.toml @@ -0,0 +1,7 @@ +[template] +src = "config.yaml.tmpl" +dest = "/var/www/crayfish/Homarus/cfg/config.yaml" +uid = 100 +gid = 101 +mode = "0644" +keys = [ "/log/level" ] diff --git a/homarus/rootfs/etc/confd/confd.toml b/homarus/rootfs/etc/confd/confd.toml new file mode 100644 index 00000000..a1478f64 --- /dev/null +++ b/homarus/rootfs/etc/confd/confd.toml @@ -0,0 +1,6 @@ +backend = "env" +confdir = "/etc/confd" +log-level = "debug" +interval = 600 +noop = false +prefix = "/homarus" diff --git a/homarus/rootfs/etc/confd/templates/config.yaml.tmpl b/homarus/rootfs/etc/confd/templates/config.yaml.tmpl new file mode 100644 index 00000000..09261879 --- /dev/null +++ b/homarus/rootfs/etc/confd/templates/config.yaml.tmpl @@ -0,0 +1,41 @@ +--- +homarus: + # path to the ffmpeg executable + executable: ffmpeg + mime_types: + valid: + - video/mp4 + - video/x-msvideo + - video/ogg + - audio/x-wav + - audio/mpeg + - audio/aac + - image/jpeg + - image/png + default: video/mp4 + mime_to_format: + valid: + - video/mp4_mp4 + - video/x-msvideo_avi + - video/ogg_ogg + - audio/x-wav_wav + - audio/mpeg_mp3 + - audio/aac_m4a + - image/jpeg_image2pipe + - image/png_image2pipe + default: mp4 + +log: + # Valid log levels are: + # DEBUG, INFO, NOTICE, WARNING, ERROR, CRITICAL, ALERT, EMERGENCY, NONE + # log level none won't open logfile + level: {{ getv "/log/level" "WARNING" }} + file: /var/log/islandora/homarus.log + +syn: + # toggles JWT security for service + enable: True + # Path to the syn config file for authentication. + # example can be found here: + # https://github.com/Islandora/Syn/blob/master/conf/syn-settings.example$ + config: /var/www/crayfish/syn-settings.xml diff --git a/houdini/.dockerignore b/houdini/.dockerignore new file mode 100644 index 00000000..b43bf86b --- /dev/null +++ b/houdini/.dockerignore @@ -0,0 +1 @@ +README.md diff --git a/houdini/Dockerfile b/houdini/Dockerfile new file mode 100644 index 00000000..2f9d8681 --- /dev/null +++ b/houdini/Dockerfile @@ -0,0 +1,21 @@ +# syntax=docker/dockerfile:experimental +FROM local/imagemagick:latest as imagemagick + +FROM local/crayfish:latest + +RUN --mount=type=cache,target=/var/cache/apk \ + --mount=type=cache,target=/etc/cache/apk \ + --mount=type=bind,from=imagemagick,source=/home/builder/packages/x86_64,target=/packages \ + --mount=type=bind,from=imagemagick,source=/etc/apk/keys,target=/etc/apk/keys \ + --mount=type=cache,target=/root/.composer/cache \ + apk add /packages/imagemagick-*.apk && \ + composer install -d /var/www/crayfish/Houdini && \ + php /var/www/crayfish/Houdini/bin/console cache:clear && \ + ln -s /var/www/crayfish/Houdini/public /var/www/html && \ + cleanup.sh + +COPY /rootfs / + +RUN chown -R nginx:nginx /var/www + +WORKDIR /var/www/crayfish/Houdini/ diff --git a/houdini/README.md b/houdini/README.md new file mode 100644 index 00000000..a345ecb8 --- /dev/null +++ b/houdini/README.md @@ -0,0 +1,23 @@ +# Houdini + +Docker image for [Houdini]. + +## Dependencies + +Requires `islandora/crayfish` docker image to build. Please refer to the +[Crayfish Image README](../crayfish/README.md) for additional information including +additional settings, volumes, ports, etc. + +## Settings + +| Environment Variable | Etcd Key | Default | Description | +| :------------------- | :----------------- | :------ | :-------------------------------------- | +| HOUDINI_LOG_LEVEL | /houdini/log/level | WARNING | The log level for Houdini micro-service | + +## Logs + +| Path | Description | +| :----------------------------- | :---------- | +| /var/log/islandora/houdini.log | Houdini Log | + +[Houdini]: https://github.com/Islandora/Crayfish/tree/master/Houdini diff --git a/houdini/rootfs/etc/confd/conf.d/monolog.yaml.toml b/houdini/rootfs/etc/confd/conf.d/monolog.yaml.toml new file mode 100644 index 00000000..3ceebd7d --- /dev/null +++ b/houdini/rootfs/etc/confd/conf.d/monolog.yaml.toml @@ -0,0 +1,7 @@ +[template] +src = "monolog.yaml.tmpl" +dest = "/var/www/crayfish/Houdini/config/packages/monolog.yaml" +uid = 100 +gid = 101 +mode = "0644" +keys = [ "/log/level" ] diff --git a/houdini/rootfs/etc/confd/confd.toml b/houdini/rootfs/etc/confd/confd.toml new file mode 100644 index 00000000..b23e63e9 --- /dev/null +++ b/houdini/rootfs/etc/confd/confd.toml @@ -0,0 +1,6 @@ +backend = "env" +confdir = "/etc/confd" +log-level = "debug" +interval = 600 +noop = false +prefix = "/houdini" diff --git a/houdini/rootfs/etc/confd/templates/monolog.yaml.tmpl b/houdini/rootfs/etc/confd/templates/monolog.yaml.tmpl new file mode 100644 index 00000000..1de34b03 --- /dev/null +++ b/houdini/rootfs/etc/confd/templates/monolog.yaml.tmpl @@ -0,0 +1,7 @@ +monolog: + handlers: + houdini: + type: rotating_file + path: /var/log/islandora/houdini.log + level: {{ getv "/log/level" "WARNING" }} + max_files: 1 diff --git a/houdini/rootfs/var/www/crayfish/Houdini/config/packages/crayfish_commons.yaml b/houdini/rootfs/var/www/crayfish/Houdini/config/packages/crayfish_commons.yaml new file mode 100644 index 00000000..67e492b1 --- /dev/null +++ b/houdini/rootfs/var/www/crayfish/Houdini/config/packages/crayfish_commons.yaml @@ -0,0 +1,3 @@ +crayfish_commons: + syn_config: /var/www/crayfish/syn-settings.xml + syn_enabled: True diff --git a/houdini/rootfs/var/www/crayfish/Houdini/config/services.yaml b/houdini/rootfs/var/www/crayfish/Houdini/config/services.yaml new file mode 100644 index 00000000..12eb951d --- /dev/null +++ b/houdini/rootfs/var/www/crayfish/Houdini/config/services.yaml @@ -0,0 +1,33 @@ +parameters: + app.executable: convert + app.formats.valid: + - image/jpeg + - image/png + - image/tiff + - image/jp2 + app.formats.default: image/jpeg + +services: + # default configuration for services in *this* file + _defaults: + autowire: true # Automatically injects dependencies in your services. + autoconfigure: true # Automatically registers your services as commands, event subscribers, etc. + + # makes classes in src/ available to be used as services + # this creates a service per class whose id is the fully-qualified class name + App\Islandora\Houdini\: + resource: '../src/*' + exclude: '../src/{DependencyInjection,Entity,Migrations,Tests,Kernel.php}' + + # controllers are imported separately to make sure services can be injected + # as action arguments even if you don't extend any base controller class + App\Islandora\Houdini\Controller\HoudiniController: + public: false + bind: + $formats: '%app.formats.valid%' + $default_format: '%app.formats.default%' + $executable: '%app.executable%' + tags: ['controller.service_arguments'] + + # add more service definitions when explicit configuration is needed + # please note that last definitions always *replace* previous ones diff --git a/hypercube/.dockerignore b/hypercube/.dockerignore new file mode 100644 index 00000000..b43bf86b --- /dev/null +++ b/hypercube/.dockerignore @@ -0,0 +1 @@ +README.md diff --git a/hypercube/Dockerfile b/hypercube/Dockerfile new file mode 100644 index 00000000..76c737e6 --- /dev/null +++ b/hypercube/Dockerfile @@ -0,0 +1,25 @@ +# syntax=docker/dockerfile:experimental +FROM local/crayfish:latest + +RUN --mount=type=cache,target=/var/cache/apk \ + --mount=type=cache,target=/etc/cache/apk \ + --mount=type=cache,target=/root/.composer/cache \ + apk-install.sh \ + poppler-utils \ + tesseract-ocr \ + tesseract-ocr-data-fra \ + tesseract-ocr-data-spa \ + tesseract-ocr-data-ita \ + tesseract-ocr-data-por \ + tesseract-ocr-data-hin \ + tesseract-ocr-data-deu \ + tesseract-ocr-data-jpn \ + tesseract-ocr-data-rus \ + && \ + composer install -d /var/www/crayfish/Hypercube && \ + ln -s /var/www/crayfish/Hypercube/src /var/www/html && \ + cleanup.sh + +COPY /rootfs / + +WORKDIR /var/www/crayfish/Hypercube/ diff --git a/hypercube/README.md b/hypercube/README.md new file mode 100644 index 00000000..54ef6778 --- /dev/null +++ b/hypercube/README.md @@ -0,0 +1,24 @@ +# Hypercube + +Docker image for [Hypercube]. + +## Dependencies + +Requires `islandora/crayfish` docker image to build. Please refer to the +[Crayfish Image README](../crayfish/README.md) for additional information including +additional settings, volumes, ports, etc. + +## Settings + +| Environment Variable | Etcd Key | Default | Description | +| :------------------- | :-------------------- | :---------------------- | :---------------------------------------- | +| HYPERCUBE_FCREPO_URL | /hypercube/fcrepo/url | fcrepo/fcrepo/rest | Fcrepo Rest API URL | +| HYPERCUBE_LOG_LEVEL | /hypercube/log/level | WARNING | The log level for Hypercube micro-service | + +## Logs + +| Path | Description | +| :------------------------------- | :------------ | +| /var/log/islandora/hypercube.log | Hypercube Log | + +[Hypercube]: https://github.com/Islandora/Crayfish/tree/master/Hypercube diff --git a/hypercube/rootfs/etc/confd/conf.d/config.yaml.toml b/hypercube/rootfs/etc/confd/conf.d/config.yaml.toml new file mode 100644 index 00000000..82bc8a80 --- /dev/null +++ b/hypercube/rootfs/etc/confd/conf.d/config.yaml.toml @@ -0,0 +1,7 @@ +[template] +src = "config.yaml.tmpl" +dest = "/var/www/crayfish/Hypercube/cfg/config.yaml" +uid = 100 +gid = 101 +mode = "0644" +keys = [ "/log/level", "/fcrepo/url" ] diff --git a/hypercube/rootfs/etc/confd/confd.toml b/hypercube/rootfs/etc/confd/confd.toml new file mode 100644 index 00000000..54a65ee1 --- /dev/null +++ b/hypercube/rootfs/etc/confd/confd.toml @@ -0,0 +1,6 @@ +backend = "env" +confdir = "/etc/confd" +log-level = "debug" +interval = 600 +noop = false +prefix = "/hypercube" diff --git a/hypercube/rootfs/etc/confd/templates/config.yaml.tmpl b/hypercube/rootfs/etc/confd/templates/config.yaml.tmpl new file mode 100644 index 00000000..d88a913b --- /dev/null +++ b/hypercube/rootfs/etc/confd/templates/config.yaml.tmpl @@ -0,0 +1,20 @@ +--- +hypercube: + # path to the convert executable + tesseract_executable: tesseract + pdftotext_executable: pdftotext +fedora_resource: + base_url: {{ getv "/fcrepo/url" "fcrepo/fcrepo/rest" }} +log: + # Valid log levels are: + # DEBUG, INFO, NOTICE, WARNING, ERROR, CRITICAL, ALERT, EMERGENCY, NONE + # log level none won't open logfile + level: {{ getv "/log/level" "WARNING" }} + file: /var/log/islandora/hypercube.log +syn: + # toggles JWT security for service + enable: true + # Path to the syn config file for authentication. + # example can be found here: + # https://github.com/Islandora/Syn/blob/master/conf/syn-settings.example.xml + config: /var/www/crayfish/syn-settings.xml diff --git a/imagemagick/.dockerignore b/imagemagick/.dockerignore new file mode 100644 index 00000000..b43bf86b --- /dev/null +++ b/imagemagick/.dockerignore @@ -0,0 +1 @@ +README.md diff --git a/imagemagick/Dockerfile b/imagemagick/Dockerfile new file mode 100644 index 00000000..fb551073 --- /dev/null +++ b/imagemagick/Dockerfile @@ -0,0 +1,45 @@ +# syntax=docker/dockerfile:experimental +FROM local/abuild:latest + +RUN --mount=type=cache,target=/var/cache/apk \ + --mount=type=cache,target=/etc/cache/apk \ + apk --update add \ + libheif-dev \ + libwebp-dev \ + chrpath \ + fftw-dev \ + fontconfig-dev \ + freetype-dev \ + ghostscript-dev \ + ghostscript-fonts \ + graphviz \ + lcms2-dev \ + libjpeg-turbo-dev \ + libpng-dev \ + librsvg-dev \ + libtool \ + libwmf-dev \ + libx11-dev \ + libxext-dev \ + libxml2-dev \ + openexr-dev \ + openjpeg-dev \ + pango-dev \ + perl-dev \ + tiff-dev \ + zlib-dev + +COPY /build /build + +WORKDIR /build + +RUN chown -R builder /build + +ARG PACKAGER="Nigel Banks " + +USER builder + +RUN export PACKAGER="${PACKAGER}" && \ + abuild-keygen -ain && \ + abuild-apk update && \ + abuild diff --git a/imagemagick/README.md b/imagemagick/README.md new file mode 100644 index 00000000..4ed14157 --- /dev/null +++ b/imagemagick/README.md @@ -0,0 +1,25 @@ +# Imagemagick + +Docker image for `imagemagick` package. + +It is not meant to be deployed as a service, but rather as base to import our +custom imagemagick build into containers like `islandora/houdini`. + +Consumers are expected to follow this pattern: + +```dockerfile +FROM islandora/imagemagick:latest as imagemagick + +FROM some_image:latest + +RUN --mount=type=bind,from=imagemagick,source=/home/builder/packages/x86_64,target=/packages \ + --mount=type=bind,from=imagemagick,source=/etc/apk/keys,target=/etc/apk/keys \ + apk add /packages/imagemagick-*.apk && \ + ... other build steps ... && \ + cleanup.sh +``` + +## Dependencies + +Requires `islandora/abuild` docker image to build. Please refer to the +[ABuild Image README](../abuild/README.md) for additional information. diff --git a/imagemagick/build/APKBUILD b/imagemagick/build/APKBUILD new file mode 100644 index 00000000..99c1e70a --- /dev/null +++ b/imagemagick/build/APKBUILD @@ -0,0 +1,200 @@ +# Adapted from: https://git.alpinelinux.org/aports/commit/?id=f0a480dcf122a955d24fffe94517875a4e32061e +# Contributor: Nigel Banks +# Contributor: Łukasz Jendrysik +# Contributor: Carlo Landmeter +# Maintainer: Natanael Copa +pkgname=imagemagick +_pkgname=ImageMagick +pkgver=7.0.10.10 +pkgrel=0 +_pkgver=${pkgver%.*}-${pkgver##*.} +_abiver=7 +pkgdesc="Collection of tools and libraries for many image formats" +url="https://www.imagemagick.org/" +arch="all" +license="ImageMagick" +options="libtool" +makedepends=" + chrpath + fftw-dev + fontconfig-dev + freetype-dev + ghostscript-dev + lcms2-dev + libheif-dev + libjpeg-turbo-dev + libpng-dev + libtool + libwebp-dev + libwmf-dev + libx11-dev + libxext-dev + libxml2-dev + openexr-dev + openjpeg-dev + pango-dev + perl-dev + tiff-dev + zlib-dev" + +case "$CARCH" in + s390x) ;; + mips*) options="!check" ;; + *) makedepends="$makedepends librsvg-dev" ;; +esac + +checkdepends="freetype fontconfig ghostscript ghostscript-fonts lcms2 graphviz" +subpackages=" + $pkgname-doc + $pkgname-static + $pkgname-dev + $pkgname-c++:_cxx + $pkgname-libs + $pkgname-perlmagick:_perlmagick + $pkgname-perlmagick-doc:_perlmagick_doc + " +source="$_pkgname-$_pkgver.tar.gz::https://github.com/ImageMagick/ImageMagick/archive/$_pkgver.tar.gz + disable-avaraging-tests.patch" +builddir="$srcdir/$_pkgname-$_pkgver" + +# secfixes: +# 7.0.9.7-r0: +# - CVE-2019-19952 +# 7.0.8.62-r0: +# - CVE-2019-17547 +# 7.0.8.56-r0: +# - CVE-2019-17541 +# - CVE-2019-17540 +# - CVE-2019-14981 +# - CVE-2019-13454 +# 7.0.8.53-r0: +# - CVE-2019-13391 +# - CVE-2019-13311 +# - CVE-2019-13310 +# - CVE-2019-13309 +# - CVE-2019-13308 +# - CVE-2019-13307 +# - CVE-2019-13306 +# - CVE-2019-13305 +# - CVE-2019-13304 +# - CVE-2019-13303 +# - CVE-2019-13302 +# - CVE-2019-13301 +# - CVE-2019-13300 +# - CVE-2019-13299 +# - CVE-2019-13298 +# - CVE-2019-13297 +# - CVE-2019-13296 +# - CVE-2019-13295 +# - CVE-2019-13137 +# - CVE-2019-13136 +# - CVE-2019-13135 +# - CVE-2019-13134 +# - CVE-2019-13133 +# 7.0.8.44-r0: +# - CVE-2019-19949 +# - CVE-2019-19948 +# - CVE-2019-16713 +# - CVE-2019-16712 +# - CVE-2019-16711 +# - CVE-2019-15141 +# - CVE-2019-15140 +# - CVE-2019-15139 +# - CVE-2019-14980 +# - CVE-2019-11598 +# - CVE-2019-11597 +# - CVE-2019-11472 +# 7.0.8.38-r0: +# - CVE-2019-9956 +# - CVE-2019-16710 +# - CVE-2019-16709 +# - CVE-2019-16708 +# - CVE-2019-10650 +# - CVE-2019-10649 + +build() { + case "$CARCH" in + s390x) ;; + *) _conf_args="--with-rsvg" ;; + esac + + # fix doc dir, Gentoo bug 91911 + sed -i -e \ + 's:DOCUMENTATION_PATH="$DATA_DIR/doc/$DOCUMENTATION_RELATIVE_PATH":DOCUMENTATION_PATH="/usr/share/doc/imagemagick":g' \ + configure + ./configure -C \ + --build=$CBUILD \ + --host=$CHOST \ + --prefix=/usr \ + --sysconfdir=/etc \ + --mandir=/usr/share/man \ + --infodir=/usr/share/info \ + --enable-static \ + --disable-openmp \ + --with-threads \ + --with-x \ + --with-tiff \ + --with-png \ + --with-webp \ + --with-gslib \ + --with-gs-font-dir=/usr/share/fonts/Type1 \ + --with-heic \ + --with-modules \ + --with-xml \ + --with-perl \ + --with-perl-options="PREFIX=/usr INSTALLDIRS=vendor" \ + --with-dps=no \ + --with-fpx=no \ + --with-gslib=no \ + --with-gvc=no \ + --with-rsvg=no \ + $_conf_args + make -j $(nproc) +} + +check() { + # Test disabled to reduce build time, manually check if you are modifing this package script. + # make check -j $(nproc) + return 0 +} + +package() { + make -j1 DESTDIR="$pkgdir" install + if ! [ -e "$pkgdir"/usr/lib/libMagickCore-$_abiver.Q16HDRI.so ]; then + error "Has ABI verision changed? (current is $_abiver)" + return 1 + fi + + # we cannot let abuild delete the *.la files due to we need *.la + # for the modules + rm "$pkgdir"/usr/lib/*.la + + find "$pkgdir" \( -name '.packlist' -o -name 'perllocal.pod' \ + -o -name '*.bs' \) -delete +} + +_cxx() { + pkgdesc="ImageMagick Magick++ library (C++ bindings)" + mkdir -p "$subpkgdir"/usr/lib + mv "$pkgdir"/usr/lib/libMagick++*.so.* "$subpkgdir"/usr/lib/ +} + +_perlmagick() { + pkgdesc="PerlMagick Perl Modules for ImageMagick" + mkdir -p "$subpkgdir"/usr/lib + mv "$pkgdir"/usr/lib/perl5 "$subpkgdir"/usr/lib/ + # Strip all the rpath that include /home + scanelf --recursive --rpath "$subpkgdir" | awk '/home/{print $3;}' | xargs chrpath -d +# chrpath -d "$subpkgdir"/usr/lib/perl5/vendor_perl/auto/Image/Magick/Q16HDRI/Q16HDRI.so +# chrpath -d "$subpkgdir"/usr/lib/perl5/vendor_perl/auto/Image/Magick/Magick.so +} + +_perlmagick_doc() { + pkgdesc="PerlMagick Perl Module Documentation for ImageMagick" + mkdir -p "$subpkgdir" + cd "$builddir"/PerlMagick + make -j1 DESTDIR="$subpkgdir" doc_vendor_install +} + +sha512sums="2c9e0f0f172572473078651d11ee1a173ec8a0965310c04c9e96f2bfa1249362fb775f23681d5d866ec6b8847125a001814ddd91dda44ae613602127819b2894 ImageMagick-7.0.10-10.tar.gz +58afb2da075a6208b6a990ff297b3a827d260687c3355198a8b4d987e1596c0b0cd78aff6f0be0e1896e537fbe44a3d467473183f5f149664ea6e6fb3d3291a9 disable-avaraging-tests.patch" \ No newline at end of file diff --git a/imagemagick/build/disable-avaraging-tests.patch b/imagemagick/build/disable-avaraging-tests.patch new file mode 100644 index 00000000..8e715f81 --- /dev/null +++ b/imagemagick/build/disable-avaraging-tests.patch @@ -0,0 +1,26 @@ +The avaraging tests seems to be flaky due to rounding errors. Test fails on +x86 and s390x + +https://github.com/ImageMagick/ImageMagick/issues/1576#issuecomment-494595404 + +diff --git a/Magick++/tests/tests.tap b/Magick++/tests/tests.tap +index b5c15ff..bb83980 100755 +--- a/Magick++/tests/tests.tap ++++ b/Magick++/tests/tests.tap +@@ -8,14 +8,14 @@ + # + subdir=Magick++/tests + . ./common.shi +-echo "1..13" ++echo "1..12" + + SRCDIR=${top_srcdir}/${subdir}/ + export SRCDIR + + cd ${subdir} || exit 1 + +-for mytest in appendImages attributes averageImages coalesceImages coderInfo color colorHistogram exceptions geometry montageImages morphImages readWriteBlob readWriteImages ++for mytest in appendImages attributes coalesceImages coderInfo color colorHistogram exceptions geometry montageImages morphImages readWriteBlob readWriteImages + do + ./${mytest} && echo "ok" || echo "not ok" + done diff --git a/java/.dockerignore b/java/.dockerignore new file mode 100644 index 00000000..b43bf86b --- /dev/null +++ b/java/.dockerignore @@ -0,0 +1 @@ +README.md diff --git a/java/Dockerfile b/java/Dockerfile new file mode 100644 index 00000000..d7423098 --- /dev/null +++ b/java/Dockerfile @@ -0,0 +1,15 @@ +# syntax=docker/dockerfile:experimental +FROM local/base:latest + +# Install packages and tools required by all downstream images. +RUN --mount=type=cache,target=/var/cache/apk \ + --mount=type=cache,target=/etc/cache/apk \ + apk-install.sh \ + openjdk8 \ + maven \ + && \ + cleanup.sh + +ENV JAVA_HOME=/usr/lib/jvm/default-jvm + +COPY rootfs / diff --git a/java/README.md b/java/README.md new file mode 100644 index 00000000..0816133a --- /dev/null +++ b/java/README.md @@ -0,0 +1,15 @@ +# Java + +Docker image for [Java] OpenJDK version 8. + +Please refer to the [Java Documentation] for more in-depth information. + +Acts as base Docker image for all Java based services. + +## Dependencies + +Requires `islandora/base` docker image to build. Please refer to the +[Base Image README](../base/README.md) for additional information. + +[Java Documentation]: https://docs.oracle.com/en/java/ +[Java]: https://www.java.com/ diff --git a/java/rootfs/usr/local/bin/install-apache-service.sh b/java/rootfs/usr/local/bin/install-apache-service.sh new file mode 100755 index 00000000..6c692766 --- /dev/null +++ b/java/rootfs/usr/local/bin/install-apache-service.sh @@ -0,0 +1,127 @@ +#!/usr/bin/env bash + +# Exit non-zero if any command fails. +set -e + +readonly PROGNAME=$(basename $0) +readonly ARGS="$@" + +readonly DOWNLOAD_CACHE_DIRECTORY=/opt/downloads + +function usage() { + cat <<- EOF + usage: $PROGNAME options [FILE]... + + Installs the given apache service in /opt. Creates a user/group for the + service and ensuring that all files are owned by that user/group. + + Additional parameters are files to be removed from the installation to save + on space. Things like "examples", and "docs". + + OPTIONS: + -n --name The name of the services to install (used to create user/group and install directory). + -v --version Version of apache service to install. + -k --key GPG Key used to verify the downloaded file. + -m --mirror The URL where the package is downloaded from. + -f --file The name of the file to download. + -h --help Show this help. + -x --debug Debug this script. + + Examples: + Install ActiveMQ: + $PROGNAME \\ + --name "activemq" \\ + --version "5.14.5" \\ + --key "62ED4DF0BACB8793" \\ + --mirror "https://archive.apache.org/dist/activemq/5.14.5" \\ + --file "apache-activemq-5.14.5-bin.tar.gz" \\ + examples webapps-demo docs +EOF +} + +function cmdline() { + local arg= + for arg + do + local delim="" + case "$arg" in + # Translate --gnu-long-options to -g (short options) + --name) args="${args}-n ";; + --version) args="${args}-v ";; + --key) args="${args}-k ";; + --mirror) args="${args}-m ";; + --file) args="${args}-f ";; + --help) args="${args}-h ";; + --debug) args="${args}-x ";; + # Pass through anything else + *) [[ "${arg:0:1}" == "-" ]] || delim="\"" + args="${args}${delim}${arg}${delim} ";; + esac + done + + # Reset the positional parameters to the short options + eval set -- $args + + while getopts "n:v:k:m:f:hx" OPTION + do + case $OPTION in + n) + readonly NAME=${OPTARG} + ;; + v) + readonly VERSION=${OPTARG} + ;; + k) + readonly KEY=${OPTARG} + ;; + m) + readonly MIRROR=${OPTARG} + ;; + f) + readonly FILE=${OPTARG} + ;; + h) + usage + exit 0 + ;; + x) + readonly DEBUG='-x' + set -x + ;; + esac + done + + if [[ -z $NAME || -z $VERSION || -z $KEY || -z $MIRROR || -z $FILE ]]; then + echo "Missing one or more required options: --name --version --key --mirror --file" + exit 1 + fi + + # All remaning parameters are files to be removed from the installation. + shift $((OPTIND-1)) + readonly REMOVE=("$@") + + return 0 +} + +function main { + cmdline ${ARGS} + local install_directory=/opt/${NAME} + local user=${NAME} + local group=${NAME} + # Expects that the RUN uses ${DOWNLOAD_CACHE_DIRECTORY} as a cache + # https://github.com/moby/buildkit/blob/master/frontend/dockerfile/docs/experimental.md#run---mounttypecache + wget -N -P ${DOWNLOAD_CACHE_DIRECTORY} ${MIRROR}/${FILE} + wget -N -P ${DOWNLOAD_CACHE_DIRECTORY} ${MIRROR}/${FILE}.asc + gpg --keyserver hkp://keys.gnupg.net:80 --recv-key ${KEY} + gpg --verify ${DOWNLOAD_CACHE_DIRECTORY}/${FILE}.asc ${DOWNLOAD_CACHE_DIRECTORY}/${FILE} + mkdir ${install_directory} + addgroup ${group} && \ + adduser --system --disabled-password --no-create-home --ingroup ${group} --shell /sbin/nologin --home ${install_directory} ${user} + chown ${user}:${group} ${install_directory} + s6-setuidgid ${user} tar -xzf /opt/downloads/${FILE} -C ${install_directory} --strip-components 1 + for i in "${REMOVE[@]}"; do + rm -fr "${install_directory}/${i}" + done + cleanup.sh +} +main diff --git a/karaf/.dockerignore b/karaf/.dockerignore new file mode 100644 index 00000000..42061c01 --- /dev/null +++ b/karaf/.dockerignore @@ -0,0 +1 @@ +README.md \ No newline at end of file diff --git a/karaf/Dockerfile b/karaf/Dockerfile new file mode 100644 index 00000000..6aefbf81 --- /dev/null +++ b/karaf/Dockerfile @@ -0,0 +1,23 @@ +# syntax=docker/dockerfile:experimental +FROM local/java:latest + +RUN --mount=id=downloads,type=cache,target=/opt/downloads \ + KARAF_VERSION="4.0.8" && \ + install-apache-service.sh \ + --name karaf \ + --version "${KARAF_VERSION}" \ + --key "BFF2EE42C8282E76" \ + --mirror "https://archive.apache.org/dist/karaf/${KARAF_VERSION}" \ + --file "apache-karaf-${KARAF_VERSION}.tar.gz" \ + demos \ + && \ + sed -i 's@http://repo1@https://repo1@' /opt/karaf/etc/org.ops4j.pax.url.mvn.cfg && \ + chown -R karaf:karaf /opt/karaf && \ + rm -rf /opt/karaf/instances/* && \ + cleanup.sh + +WORKDIR /opt/karaf + +EXPOSE 8101 1099 44444 8181 + +COPY rootfs / diff --git a/karaf/README.md b/karaf/README.md new file mode 100644 index 00000000..509bf575 --- /dev/null +++ b/karaf/README.md @@ -0,0 +1,72 @@ +# Karaf + +Docker image for [Karaf] version 4.0.8 + +Please refer to the [Karaf Documentation] for more in-depth information. + +As a quick example this will bring up an instance of karaf, and allow you to +log view the [WebConsole] on as the user `admin` with +the password `password`. + +```bash +docker run --rm -ti \ + -p 8181:8181 \ + -e "KARAF_ADMIN_NAME=admin" \ + -e "KARAF_ADMIN_PASSWORD=password" \ + islandora/karaf +``` + +## Dependencies + +Requires `islandora/karaf` docker image to build. + +## Ports + +| Port | Description | +| :---- | :----------- | +| 8101 | [SSH] | +| 1099 | [RMI] | +| 44444 | [JMX] | +| 8181 | [WebConsole] | + +## Volumes + +| Path | Description | +| :-------------- | :-------------------------- | +| /opt/karaf/data | [Karaf Directory Structure] | + +## Settings + +| Environment Variable | Etcd Key | Default | Description | +| :------------------- | :-------------------- | :------- | :------------------ | +| KARAF_ADMIN_NAME | /karaf/admin/name | admin | Admin user name | +| KARAF_ADMIN_PASSWORD | /karaf/admin/password | password | Admin user password | + +Additional users/groups/etc can be defined by adding more environment variables, +following the above conventions: + +| Environment Variable | Etcd Key | Description | +| :------------------------- | :-------------------------- | :------------------------------- | +| KARAF_USER_{USER}_NAME | /karaf/user/{USER}/name | See [Security]: users.properties | +| KARAF_USER_{USER}_PASSWORD | /karaf/user/{USER}/password | See [Security]: users.properties | +| KARAF_USER_{USER}_ROLES | /karaf/user/{USER}/roles | See [Security]: users.properties | +| KARAF_GROUP_{GROUP}_NAME | /karaf/group/{GROUP}/name | See [Security]: users.properties | +| KARAF_GROUP_{GROUP}_ROLES | /karaf/group/{GROUP}/roles | See [Security]: users.properties | + +*N.B. These do not have defaults.* + +## Logs + +| Path | Description | +| :---------------------------- | :---------- | +| /opt/karaf/data/log/karaf.log | [Karaf Log] | + +[JMX]: https://karaf.apache.org/manual/latest/#_monitoring_and_management_using_jmx +[Karaf Directory Structure]: https://karaf.apache.org/manual/latest/#_directory_structure +[Karaf Documentation]: https://islandora.github.io/documentation/ +[Karaf Log]: https://karaf.apache.org/manual/latest/#_log +[Karaf]: https://github.com/Islandora/karaf +[RMI]: https://karaf.apache.org/manual/latest/monitoring +[Security]: https://karaf.apache.org/manual/latest/security +[SSH]: https://karaf.apache.org/manual/latest/remote +[WebConsole]: https://karaf.apache.org/manual/latest/webconsole diff --git a/karaf/rootfs/etc/confd/conf.d/users.properties.toml b/karaf/rootfs/etc/confd/conf.d/users.properties.toml new file mode 100644 index 00000000..267cd2a2 --- /dev/null +++ b/karaf/rootfs/etc/confd/conf.d/users.properties.toml @@ -0,0 +1,7 @@ +[template] +src = "users.properties.tmpl" +dest = "/opt/karaf/etc/users.properties" +uid = 100 +gid = 1000 +mode = "0640" +keys = [ "/karaf" ] diff --git a/karaf/rootfs/etc/confd/templates/users.properties.tmpl b/karaf/rootfs/etc/confd/templates/users.properties.tmpl new file mode 100644 index 00000000..a97612e9 --- /dev/null +++ b/karaf/rootfs/etc/confd/templates/users.properties.tmpl @@ -0,0 +1,18 @@ +# +# This file contains the users, groups, and roles. +# Each line has to be of the format: +# +# USER=PASSWORD,ROLE1,ROLE2,... +# USER=PASSWORD,_g_:GROUP,... +# _g_\:GROUP=ROLE1,ROLE2,... +# +# All users, groups, and roles entered in this file are available after Karaf startup +# and modifiable via the JAAS command group. These users reside in a JAAS domain +# with the name "karaf". +# +{{ getv "/karaf/admin/name" "admin" }} = {{ getv "/karaf/admin/password" "password" }}, _g_:admingroup +_g_\:admingroup = group,admin,manager,viewer,systembundles +{{ range $dir := lsdir "/karaf/user" }}{{ getv (printf "/karaf/user/%s/name" $dir) }} = {{ getv (printf "/karaf/user/%s/password" $dir) }} {{ getv (printf "/karaf/user/%s/roles" $dir) }} +{{ end }} +{{ range $dir := lsdir "/karaf/group" }}{{ getv (printf "/karaf/group/%s/name" $dir) }} = {{ getv (printf "/karaf/group/%s/roles" $dir) }} +{{ end }} diff --git a/karaf/rootfs/etc/cont-init.d/04-karaf-startup.sh b/karaf/rootfs/etc/cont-init.d/04-karaf-startup.sh new file mode 100644 index 00000000..a09a8c3c --- /dev/null +++ b/karaf/rootfs/etc/cont-init.d/04-karaf-startup.sh @@ -0,0 +1,4 @@ +#!/usr/bin/with-contenv bash +set -e +# On startup if we exit with sigterm the pid file is left behind sometimes. +rm /opt/karaf/instances/instance.properties &> /dev/null || true \ No newline at end of file diff --git a/karaf/rootfs/etc/services.d/karaf/finish b/karaf/rootfs/etc/services.d/karaf/finish new file mode 100644 index 00000000..f8984dd3 --- /dev/null +++ b/karaf/rootfs/etc/services.d/karaf/finish @@ -0,0 +1,4 @@ +#!/usr/bin/execlineb -S1 +# -*- mode: sh -*- +# vi: set ft=sh : +s6-svscanctl -t /var/run/s6/services diff --git a/karaf/rootfs/etc/services.d/karaf/run b/karaf/rootfs/etc/services.d/karaf/run new file mode 100644 index 00000000..d1607dc7 --- /dev/null +++ b/karaf/rootfs/etc/services.d/karaf/run @@ -0,0 +1,6 @@ +#!/usr/bin/execlineb -P +# -*- mode: sh -*- +# vi: set ft=sh : +with-contenv +s6-setuidgid karaf +/opt/karaf/bin/karaf server diff --git a/mariadb/.dockerignore b/mariadb/.dockerignore new file mode 100644 index 00000000..b43bf86b --- /dev/null +++ b/mariadb/.dockerignore @@ -0,0 +1 @@ +README.md diff --git a/mariadb/Dockerfile b/mariadb/Dockerfile new file mode 100644 index 00000000..fffb5ed5 --- /dev/null +++ b/mariadb/Dockerfile @@ -0,0 +1,19 @@ +# syntax=docker/dockerfile:experimental +FROM local/base:latest + +RUN --mount=type=cache,target=/var/cache/apk \ + --mount=type=cache,target=/etc/cache/apk \ + apk-install.sh \ + mariadb \ + mysql-client \ + && \ + mkdir -p /var/lib/mysql-files && \ + chown -R mysql:mysql /var/lib/mysql && \ + chown -R mysql:mysql /var/lib/mysql-files && \ + cleanup.sh + +EXPOSE 3306 + +VOLUME [ "/var/lib/mysql", "/var/lib/mysql-files" ] + +COPY rootfs / diff --git a/mariadb/README.md b/mariadb/README.md new file mode 100644 index 00000000..d510eea7 --- /dev/null +++ b/mariadb/README.md @@ -0,0 +1,46 @@ +# MariaDB + +Docker image for [MariaDB] version 10.4.12 + +Please refer to the [MariaDB Documentation] for more in-depth information. + +As a quick example this will bring up an instance of MariaDB, and allow you to +log in with client as the user `root` with the password `password`. + +```bash +docker run --rm -d -name mariadb islandora/mariadb +docker exec -ti mariadb mysql -u root --password='password' +``` + +## Dependencies + +Requires `islandora/base` docker image to build. Please refer to the +[Base Image README](../base/README.md) for additional information. + +## Ports + +| Port | Description | +| :--- | :---------------- | +| 3306 | MySQL Client Port | + +## Volumes + +| Path | Description | +| :------------------- | :--------------------------------------------- | +| /var/lib/mysql | Database files | +| /var/lib/mysql-files | Location to import databases via CSV/SQL files | + +## Settings + +| Environment Variable | Etcd Key | Default | Description | +| :------------------- | :------------------- | :------- | :------------------------------------- | +| MYSQL_ROOT_PASSWORD | /mysql/root/password | password | The password for the root user account | + +## Logs + +| Path | Description | +| :----- | :------------ | +| STDOUT | [MariaDB Log] | + +[MariaDB Documentation]: https://mariadb.org/documentation/ +[MariaDB]: https://mariadb.org/ diff --git a/mariadb/rootfs/etc/confd/conf.d/mariadb-server.cnf.toml b/mariadb/rootfs/etc/confd/conf.d/mariadb-server.cnf.toml new file mode 100644 index 00000000..537f353e --- /dev/null +++ b/mariadb/rootfs/etc/confd/conf.d/mariadb-server.cnf.toml @@ -0,0 +1,5 @@ +[template] +src = "mariadb-server.cnf.tmpl" +dest = "/etc/my.cnf.d/mariadb-server.cnf" +mode="0644" +keys = [ "/root" ] diff --git a/mariadb/rootfs/etc/confd/conf.d/my.cnf.toml b/mariadb/rootfs/etc/confd/conf.d/my.cnf.toml new file mode 100644 index 00000000..d74e5e43 --- /dev/null +++ b/mariadb/rootfs/etc/confd/conf.d/my.cnf.toml @@ -0,0 +1,5 @@ +[template] +src = "my.cnf.tmpl" +dest = "/etc/my.cnf" +mode="0644" +keys = ["/root" ] diff --git a/mariadb/rootfs/etc/confd/conf.d/set-root-user-password.sql.toml b/mariadb/rootfs/etc/confd/conf.d/set-root-user-password.sql.toml new file mode 100644 index 00000000..e4d261f7 --- /dev/null +++ b/mariadb/rootfs/etc/confd/conf.d/set-root-user-password.sql.toml @@ -0,0 +1,7 @@ +[template] +src = "set-root-user-password.sql.tmpl" +dest = "/var/run/islandora/set-root-user-password.sql" +uid = 0 +gid = 0 +mode = "0700" +keys = [ "/root/password" ] diff --git a/mariadb/rootfs/etc/confd/confd.toml b/mariadb/rootfs/etc/confd/confd.toml new file mode 100644 index 00000000..a5717209 --- /dev/null +++ b/mariadb/rootfs/etc/confd/confd.toml @@ -0,0 +1,6 @@ +backend = "env" +confdir = "/etc/confd" +log-level = "debug" +interval = 600 +noop = false +prefix = "/mysql" diff --git a/mariadb/rootfs/etc/confd/templates/mariadb-server.cnf.tmpl b/mariadb/rootfs/etc/confd/templates/mariadb-server.cnf.tmpl new file mode 100644 index 00000000..cbcad522 --- /dev/null +++ b/mariadb/rootfs/etc/confd/templates/mariadb-server.cnf.tmpl @@ -0,0 +1,42 @@ +# +# These groups are read by MariaDB server. +# Use it for options that only the server (but not clients) should see + +# this is read by the standalone daemon and embedded servers +[server] + +# this is only for the mysqld standalone daemon +[mysqld] +# skip-networking + +# Galera-related settings +[galera] +# Mandatory settings +#wsrep_on=ON +#wsrep_provider= +#wsrep_cluster_address= +#binlog_format=row +#default_storage_engine=InnoDB +#innodb_autoinc_lock_mode=2 +# +# Allow server to accept connections on all interfaces. +# +#bind-address=0.0.0.0 +# +# Optional setting +#wsrep_slave_threads=1 +#innodb_flush_log_at_trx_commit=0 + +# this is only for embedded server +[embedded] + +# This group is only read by MariaDB servers, not by MySQL. +# If you use the same .cnf file for MySQL and MariaDB, +# you can put MariaDB-only options here +[mariadb] + +# This group is only read by MariaDB-10.3 servers. +# If you use the same .cnf file for MariaDB of different versions, +# use this group for options that older servers don't understand +[mariadb-10.3] + diff --git a/mariadb/rootfs/etc/confd/templates/my.cnf.tmpl b/mariadb/rootfs/etc/confd/templates/my.cnf.tmpl new file mode 100644 index 00000000..cec4bd05 --- /dev/null +++ b/mariadb/rootfs/etc/confd/templates/my.cnf.tmpl @@ -0,0 +1,12 @@ +# This group is read both both by the client and the server +# use it for options that affect everything +[client-server] + +# This group is read by the server +[mysqld] + +# Disabling symbolic-links is recommended to prevent assorted security risks +symbolic-links=0 + +# include all files from the config directory +!includedir /etc/my.cnf.d diff --git a/mariadb/rootfs/etc/confd/templates/set-root-user-password.sql.tmpl b/mariadb/rootfs/etc/confd/templates/set-root-user-password.sql.tmpl new file mode 100644 index 00000000..51c1b823 --- /dev/null +++ b/mariadb/rootfs/etc/confd/templates/set-root-user-password.sql.tmpl @@ -0,0 +1,5 @@ +CREATE USER IF NOT EXISTS 'root'@'%'; +SET PASSWORD FOR 'root'@'localhost' = PASSWORD('{{ getv "/root/password" "password" }}'); +SET PASSWORD FOR 'root'@'%' = PASSWORD('{{ getv "/root/password" "password" }}'); +GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' WITH GRANT OPTION; +FLUSH PRIVILEGES; diff --git a/mariadb/rootfs/etc/cont-init.d/03-mysql-setup.sh b/mariadb/rootfs/etc/cont-init.d/03-mysql-setup.sh new file mode 100755 index 00000000..e9613451 --- /dev/null +++ b/mariadb/rootfs/etc/cont-init.d/03-mysql-setup.sh @@ -0,0 +1,32 @@ +#!/usr/bin/with-contenv bash + +set -e + +# Make run directory if it does not exist. +mkdir /run/mysqld &> /dev/null || true +chown mysql:mysql /run/mysqld + +# Create the database if it does not exist. +if [[ ! -d "/var/lib/mysql/mysql" ]]; then + s6-setuidgid mysql mysql_install_db --basedir=/usr --datadir=/var/lib/mysql --skip-test-db --user mysql +fi + +# Startup the database so we can change the root users password. +s6-setuidgid mysql mysqld --skip-networking & +MYSQLD_PID=$! + +# Wait for it to startup. +until mysql --no-defaults --protocol=socket --user=root -e "SELECT 1" &> /dev/null; +do +sleep 1 +done + +# Change the root users password. +echo "Changing the root users password." +mysql --no-defaults --protocol=socket --user=root < /var/run/islandora/set-root-user-password.sql + +# Stop the database. +kill -s TERM ${MYSQLD_PID} + +# Allow database to stop. +wait diff --git a/mariadb/rootfs/etc/services.d/mysqld/finish b/mariadb/rootfs/etc/services.d/mysqld/finish new file mode 100644 index 00000000..32f06197 --- /dev/null +++ b/mariadb/rootfs/etc/services.d/mysqld/finish @@ -0,0 +1,4 @@ +#!/usr/bin/execlineb -S0 +# -*- mode: sh -*- +# vi: set ft=sh: +s6-svscanctl -t /var/run/s6/services diff --git a/mariadb/rootfs/etc/services.d/mysqld/run b/mariadb/rootfs/etc/services.d/mysqld/run new file mode 100644 index 00000000..0547bbee --- /dev/null +++ b/mariadb/rootfs/etc/services.d/mysqld/run @@ -0,0 +1,5 @@ +#!/usr/bin/execlineb -P +# -*- mode: sh -*- +# vi: set ft=sh: +s6-setuidgid mysql +mysqld --user mysql diff --git a/matomo/.dockerignore b/matomo/.dockerignore new file mode 100644 index 00000000..b43bf86b --- /dev/null +++ b/matomo/.dockerignore @@ -0,0 +1 @@ +README.md diff --git a/matomo/Dockerfile b/matomo/Dockerfile new file mode 100644 index 00000000..1f9ce442 --- /dev/null +++ b/matomo/Dockerfile @@ -0,0 +1,21 @@ +# syntax=docker/dockerfile:experimental +FROM local/nginx:latest + +RUN --mount=id=downloads,type=cache,target=/opt/downloads \ + MATOMO_VERSION=3.13.5 && \ + MATOMO_FILE=matomo-${MATOMO_VERSION}.tar.gz && \ + wget -N -P /opt/downloads https://builds.matomo.org/${MATOMO_FILE} && \ + wget -N -P /opt/downloads https://builds.matomo.org/${MATOMO_FILE}.asc && \ + gpg --keyserver ha.pool.sks-keyservers.net --recv-keys 814E346FA01A20DBB04B6807B5DBD5925590A237 && \ + gpg --verify /opt/downloads/${MATOMO_FILE}.asc /opt/downloads/${MATOMO_FILE} && \ + tar -xzf /opt/downloads/${MATOMO_FILE} -C /opt && \ + chown -R nginx:nginx /opt/matomo && \ + cleanup.sh + +WORKDIR /opt/matomo + +VOLUME [ "/opt/matomo/config" ] + +COPY rootfs / + +EXPOSE 8000 diff --git a/matomo/README.md b/matomo/README.md new file mode 100644 index 00000000..4b331668 --- /dev/null +++ b/matomo/README.md @@ -0,0 +1,31 @@ +# Matomo + +Docker image for [Crayfish] version 1.1.1. + +Acts as base Docker image for Crayfish based micro-services. It is not meant to +be run on its own. + +## Dependencies + +Requires `islandora/nginx` docker image to build. Please refer to the +[Nginx Image README](../nginx/README.md) for additional information including +additional settings, volumes, ports, etc. + +## Ports + +| Port | Description | +| :--- | :---------- | +| 8000 | HTTP | + +## Settings + +> N.B. For all of the settings below images that descend from +> ``islandora/crayfish`` will apply prefix to every setting. So for example +> `JWT_ADMIN_TOKEN` would become `GEMINI_JWT_ADMIN_TOKEN` this is to allow for +> different settings on a per-service basis. + +| Environment Variable | Etcd Key | Default | Description | +| :------------------- | :--------------- | :-------- | :---------- | +| JWT_ADMIN_TOKEN | /jwt/admin/token | islandora | JWT Token | + +[Crayfish]: https://github.com/Islandora/Crayfish/tree/master diff --git a/matomo/rootfs/etc/confd/conf.d/create-matomo-database.sh.toml b/matomo/rootfs/etc/confd/conf.d/create-matomo-database.sh.toml new file mode 100644 index 00000000..d7511c40 --- /dev/null +++ b/matomo/rootfs/etc/confd/conf.d/create-matomo-database.sh.toml @@ -0,0 +1,7 @@ +[template] +src = "create-matomo-database.sh.tmpl" +dest = "/var/run/islandora/create-matomo-database.sh" +uid = 0 +gid = 0 +mode = "0700" +keys = [ "/db" ] diff --git a/matomo/rootfs/etc/confd/conf.d/create-matomo-database.sql.toml b/matomo/rootfs/etc/confd/conf.d/create-matomo-database.sql.toml new file mode 100644 index 00000000..37a87919 --- /dev/null +++ b/matomo/rootfs/etc/confd/conf.d/create-matomo-database.sql.toml @@ -0,0 +1,7 @@ +[template] +src = "create-matomo-database.sql.tmpl" +dest = "/var/run/islandora/create-matomo-database.sql" +uid = 0 +gid = 0 +mode = "0600" +keys = [ "/db" ] diff --git a/matomo/rootfs/etc/confd/conf.d/default.conf.toml b/matomo/rootfs/etc/confd/conf.d/default.conf.toml new file mode 100644 index 00000000..1df8dbe5 --- /dev/null +++ b/matomo/rootfs/etc/confd/conf.d/default.conf.toml @@ -0,0 +1,7 @@ +[template] +src = "default.conf.tmpl" +dest = "/etc/nginx/conf.d/default.conf" +uid = 100 +gid = 101 +mode = "0644" +keys = [ "/" ] diff --git a/matomo/rootfs/etc/confd/confd.toml b/matomo/rootfs/etc/confd/confd.toml new file mode 100644 index 00000000..eda2d410 --- /dev/null +++ b/matomo/rootfs/etc/confd/confd.toml @@ -0,0 +1,6 @@ +backend = "env" +confdir = "/etc/confd" +log-level = "debug" +interval = 600 +noop = false +prefix = "/matomo" diff --git a/matomo/rootfs/etc/confd/templates/create-matomo-database.sh.tmpl b/matomo/rootfs/etc/confd/templates/create-matomo-database.sh.tmpl new file mode 100644 index 00000000..3be46856 --- /dev/null +++ b/matomo/rootfs/etc/confd/templates/create-matomo-database.sh.tmpl @@ -0,0 +1,33 @@ +#!/usr/bin/with-contenv bash + +set -e + +function main { + local driver="{{ getv "/db/driver" "pdo_mysql" }}" + local host="{{ getv "/db/host" "database" }}" + local port="{{ getv "/db/port" "3306" }}" + local user="{{ getv "/db/root/user" "root" }}" + local password="{{ getv "/db/root/password" "password" }}" + + if [[ "${driver}" == "pdo_mysql" ]]; then + echo "Waiting for connection to database." + wait-for-mysql.sh \ + --host "${host}" \ + --port "${port}" \ + --user "${user}" \ + --password "${password}" + + echo "Create database / user if it does not exist." + mysql \ + --user="${user}" \ + --password="${password}" \ + --host="${host}" \ + --port="${port}" \ + --protocol=tcp \ + < /var/run/islandora/create-matomo-database.sql + else + echo "Only MySQL databases are supported for now." + exit 1 + fi +} +main diff --git a/matomo/rootfs/etc/confd/templates/create-matomo-database.sql.tmpl b/matomo/rootfs/etc/confd/templates/create-matomo-database.sql.tmpl new file mode 100644 index 00000000..981ac7d2 --- /dev/null +++ b/matomo/rootfs/etc/confd/templates/create-matomo-database.sql.tmpl @@ -0,0 +1,7 @@ +-- Create matomo database in mariadb or mysql. +CREATE DATABASE IF NOT EXISTS {{ getv "/db/name" "matomo" }} CHARACTER SET utf8 COLLATE utf8_general_ci; + +-- Create matomo_user and grant rights. +CREATE USER IF NOT EXISTS '{{ getv "/db/user" "matomo" }}'@'%' IDENTIFIED BY '{{ getv "/db/password" "password" }}'; +GRANT ALL PRIVILEGES ON {{ getv "/db/name" "matomo" }}.* to '{{ getv "/db/user" "matomo" }}'@'%'; +FLUSH PRIVILEGES; diff --git a/matomo/rootfs/etc/confd/templates/default.conf.tmpl b/matomo/rootfs/etc/confd/templates/default.conf.tmpl new file mode 100644 index 00000000..f7a9fc11 --- /dev/null +++ b/matomo/rootfs/etc/confd/templates/default.conf.tmpl @@ -0,0 +1,64 @@ +server { + listen 80; + + add_header Referrer-Policy origin; # make sure outgoing links don't show the URL to the Matomo instance + root /opt/matomo; + index index.php; + try_files $uri $uri/ =404; + + ## only allow accessing the following php files + location ~ ^/(index|matomo|piwik|js/index|plugins/HeatmapSessionRecording/configs).php { + # regex to split $uri to $fastcgi_script_name and $fastcgi_path + fastcgi_split_path_info ^(.+\.php)(/.+)$; + + # Check that the PHP script exists before passing it + try_files $fastcgi_script_name =404; + + include fastcgi_params; + fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; + fastcgi_param PATH_INFO $fastcgi_path_info; + fastcgi_param HTTP_PROXY ""; # prohibit httpoxy: https://httpoxy.org/ + fastcgi_pass unix:/var/run/php-fpm7/php-fpm7.sock; + } + + ## deny access to all other .php files + location ~* ^.+\.php$ { + deny all; + + return 403; + } + + ## disable all access to the following directories + location ~ /(config|tmp|core|lang) { + deny all; + return 403; # replace with 404 to not show these directories exist + } + location ~ /\.ht { + deny all; + return 403; + } + + location ~ js/container_.*_preview\.js$ { + expires off; + add_header Cache-Control 'private, no-cache, no-store'; + } + + location ~ \.(gif|ico|jpg|png|svg|js|css|htm|html|mp3|mp4|wav|ogg|avi|ttf|eot|woff|woff2|json)$ { + allow all; + ## Cache images,CSS,JS and webfonts for an hour + ## Increasing the duration may improve the load-time, but may cause old files to show after an Matomo upgrade + expires 1h; + add_header Pragma public; + add_header Cache-Control "public"; + } + + location ~ /(libs|vendor|plugins|misc/user) { + deny all; + return 403; + } + + ## properly display textfiles in root directory + location ~/(.*\.md|LEGALNOTICE|LICENSE) { + default_type text/plain; + } +} diff --git a/matomo/rootfs/etc/cont-init.d/03-matomo-setup.sh b/matomo/rootfs/etc/cont-init.d/03-matomo-setup.sh new file mode 100644 index 00000000..38490cf0 --- /dev/null +++ b/matomo/rootfs/etc/cont-init.d/03-matomo-setup.sh @@ -0,0 +1,3 @@ +#!/usr/bin/with-contenv bash +set -e +/var/run/islandora/create-matomo-database.sh \ No newline at end of file diff --git a/milliner/.dockerignore b/milliner/.dockerignore new file mode 100644 index 00000000..b43bf86b --- /dev/null +++ b/milliner/.dockerignore @@ -0,0 +1 @@ +README.md diff --git a/milliner/Dockerfile b/milliner/Dockerfile new file mode 100644 index 00000000..50369c33 --- /dev/null +++ b/milliner/Dockerfile @@ -0,0 +1,13 @@ +# syntax=docker/dockerfile:experimental +FROM local/crayfish:latest + +RUN --mount=type=cache,target=/root/.composer/cache \ + composer install -d /var/www/crayfish/Milliner && \ + ln -s /var/www/crayfish/Milliner/src /var/www/html && \ + cleanup.sh + +COPY /rootfs / + +RUN chown -R nginx:nginx /var/www + +WORKDIR /var/www/crayfish/Milliner/ diff --git a/milliner/README.md b/milliner/README.md new file mode 100644 index 00000000..47bc31cc --- /dev/null +++ b/milliner/README.md @@ -0,0 +1,26 @@ +# Milliner + +Docker image for [Milliner]. + +## Dependencies + +Requires `islandora/crayfish` docker image to build. Please refer to the +[Crayfish Image README](../crayfish/README.md) for additional information including +additional settings, volumes, ports, etc. + +## Settings + +| Environment Variable | Etcd Key | Default | Description | +| :------------------- | :------------------- | :---------------------- | :--------------------------------------- | +| MILLINER_DRUPAL_URL | /milliner/drupal/url | drupal:80 | Drupal URL | +| MILLINER_FCREPO_URL | /milliner/fcrepo/url | fcrepo/fcrepo/rest | Fcrepo Rest API URL | +| MILLINER_GEMINI_URL | /milliner/gemini/url | gemini:8000 | Gemini URL | +| MILLINER_LOG_LEVEL | /milliner/log/level | WARNING | The log level for Milliner micro-service | + +## Logs + +| Path | Description | +| :------------------------------ | :----------- | +| /var/log/islandora/milliner.log | Milliner Log | + +[Milliner]: https://github.com/Islandora/Crayfish/tree/master/Milliner diff --git a/milliner/rootfs/etc/confd/conf.d/config.yaml.toml b/milliner/rootfs/etc/confd/conf.d/config.yaml.toml new file mode 100644 index 00000000..27b906b8 --- /dev/null +++ b/milliner/rootfs/etc/confd/conf.d/config.yaml.toml @@ -0,0 +1,7 @@ +[template] +src = "config.yaml.tmpl" +dest = "/var/www/crayfish/Milliner/cfg/config.yaml" +uid = 100 +gid = 101 +mode = "0644" +keys = [ "/log/level", "/fcrepo", "/drupal", "/gemini" ] diff --git a/milliner/rootfs/etc/confd/confd.toml b/milliner/rootfs/etc/confd/confd.toml new file mode 100644 index 00000000..65d2057c --- /dev/null +++ b/milliner/rootfs/etc/confd/confd.toml @@ -0,0 +1,6 @@ +backend = "env" +confdir = "/etc/confd" +log-level = "debug" +interval = 600 +noop = false +prefix = "/milliner" diff --git a/milliner/rootfs/etc/confd/templates/config.yaml.tmpl b/milliner/rootfs/etc/confd/templates/config.yaml.tmpl new file mode 100644 index 00000000..5d2e4e39 --- /dev/null +++ b/milliner/rootfs/etc/confd/templates/config.yaml.tmpl @@ -0,0 +1,28 @@ +--- + +fedora_base_url: {{ getv "/fcrepo/url" "http://fcrepo:8080/fcrepo/rest" }} +# if drupal_base_url contains a path, be sure to include trailing slash +# or relative paths will not resolve correctly. +drupal_base_url: {{ getv "/drupal/url" "http://drupal:80" }} +gemini_base_url: {{ getv "/gemini/url" "http://gemini:8000" }} + +modified_date_predicate: http://schema.org/dateModified + +strip_format_jsonld: true + +debug: true + +log: + # Valid log levels are: + # DEBUG, INFO, NOTICE, WARNING, ERROR, CRITICAL, ALERT, EMERGENCY, NONE + # log level none won't open logfile + level: {{ getv "/log/level" "DEBUG" }} + file: /var/log/islandora/milliner.log + +syn: + # toggles JWT security for service + enable: false + # Path to the syn config file for authentication. + # example can be found here: + # https://github.com/Islandora/Syn/blob/master/conf/syn-settings.example.xml + config: /var/www/crayfish/syn-settings.xml diff --git a/nginx/.dockerignore b/nginx/.dockerignore new file mode 100644 index 00000000..b43bf86b --- /dev/null +++ b/nginx/.dockerignore @@ -0,0 +1 @@ +README.md diff --git a/nginx/Dockerfile b/nginx/Dockerfile new file mode 100644 index 00000000..02586fde --- /dev/null +++ b/nginx/Dockerfile @@ -0,0 +1,26 @@ +# syntax=docker/dockerfile:experimental +FROM local/base:latest + +RUN --mount=type=cache,target=/var/cache/apk \ + --mount=type=cache,target=/etc/cache/apk \ + apk-install.sh \ + composer \ + nginx \ + php7-ctype \ + php7-curl \ + php7-dom \ + php7-fpm \ + php7-gd \ + php7-opcache \ + php7-pdo \ + php7-pdo_mysql \ + php7-pdo_pgsql \ + php7-session \ + php7-simplexml \ + php7-tokenizer \ + php7-xml \ + php7-xmlwriter \ + && \ + cleanup.sh + +COPY rootfs / diff --git a/nginx/README.md b/nginx/README.md new file mode 100644 index 00000000..8881898f --- /dev/null +++ b/nginx/README.md @@ -0,0 +1,57 @@ +# Nginx + +Docker image for [Nginx] version 1.16.1 and [FPM] version 7.3.17. + +Please refer to the [Nginx Documentation] and [FPM Documentation] for more +in-depth information. + +Acts as base Docker image for all PHP based services, such as Crayfish, Docker +etc. It can be used on it's own as well. + +## Dependencies + +Requires `islandora/base` docker image to build. Please refer to the +[Base Image README](../base/README.md) for additional information. + +## Settings + +> N.B. For all of the settings below images that descend from +> ``islandora/nginx`` will apply prefix to every setting. So for example +> `JWT_ADMIN_TOKEN` would become `GEMINI_JWT_ADMIN_TOKEN` this is to allow for +> different settings on a per-service basis. + +### Nginx Settings + +| Environment Variable | Etcd Key | Default | Description | +| :------------------------- | :-------------------------- | :------ | :------------------------------------------------------------------------------------ | +| NGINX_CLIENT_MAX_BODY_SIZE | /nginx/client/max/body/size | 1m | Specifies the maximum accepted body size of a client request | +| NGINX_ERROR_LOG_LEVEL | /nginx/error/log/level | warn | Log Level of Error log | +| NGINX_KEEPALIVE_TIMEOUT | /nginx/keepalive/timeout | 65 | Timeout for keep-alive connections | +| NGINX_WORKER_CONNECTIONS | /nginx/worker/connections | 1024 | The maximum number of simultaneous connections that can be opened by a worker process | +| NGINX_WORKER_PROCESSES | /nginx/worker/processes | auto | Set number of worker processes automatically based on number of CPU cores | + +### PHP Settings + +| Environment Variable | Etcd Key | Default | Description | +| :------------------------- | :-------------------------- | :------ | :---------------------------------------------------------------- | +| PHP_DEFAULT_SOCKET_TIMEOUT | /php/default/socket/timeout | 60 | Default timeout for socket based streams (seconds) | +| PHP_MAX_EXECUTION_TIME | /php/max/execution/time | 30 | Maximum execution time of each script, in seconds | +| PHP_MAX_INPUT_TIME | /php/max/input/time | 60 | Maximum amount of time each script may spend parsing request data | +| PHP_MEMORY_LIMIT | /php/memory/limit | 128M | Maximum amount of memory a script may consume | +| PHP_POST_MAX_SIZE | /php/post/max/size | 8M | Maximum size of POST data that PHP will accept | +| PHP_MAX_FILE_UPLOADS | /php/max/file/uploads | 20 | Maximum number of files that can be uploaded via a single request | +| PHP_UPLOAD_MAX_FILESIZE | /php/upload/max/filesize | 2M | Maximum allowed size for uploaded files | + +## Logs + +| Path | Description | +| :-------------- | :-------------- | +| /var/log/nginx/ | [Nginx Logging] | +| /var/log/php7/ | [FPM Logging] | + +[FPM Documentation]: https://www.php.net/manual/en/install.fpm.configuration.php +[FPM Logging]: https://www.php.net/manual/en/install.fpm.configuration.php +[FPM]: https://www.php.net/manual/en/install.fpm.php +[Nginx Documentation]: https://nginx.org/en/docs/ +[Nginx Logging]: https://docs.nginx.com/nginx/admin-guide/monitoring/logging/ +[Nginx]: https://www.nginx.com/ diff --git a/nginx/rootfs/etc/confd/conf.d/nginx.conf.toml b/nginx/rootfs/etc/confd/conf.d/nginx.conf.toml new file mode 100644 index 00000000..70161db0 --- /dev/null +++ b/nginx/rootfs/etc/confd/conf.d/nginx.conf.toml @@ -0,0 +1,7 @@ +[template] +src = "nginx.conf.tmpl" +dest = "/etc/nginx/nginx.conf" +uid = 0 +gid = 0 +mode = "0644" +keys = [ "/nginx" ] diff --git a/nginx/rootfs/etc/confd/conf.d/php-fpm.conf.toml b/nginx/rootfs/etc/confd/conf.d/php-fpm.conf.toml new file mode 100644 index 00000000..b78e4cfa --- /dev/null +++ b/nginx/rootfs/etc/confd/conf.d/php-fpm.conf.toml @@ -0,0 +1,7 @@ +[template] +src = "php-fpm.conf.tmpl" +dest = "/etc/php7/php-fpm.conf" +uid = 0 +gid = 0 +mode = "0644" +keys = [ "/php" ] diff --git a/nginx/rootfs/etc/confd/conf.d/php.ini.toml b/nginx/rootfs/etc/confd/conf.d/php.ini.toml new file mode 100644 index 00000000..0b0bb90c --- /dev/null +++ b/nginx/rootfs/etc/confd/conf.d/php.ini.toml @@ -0,0 +1,7 @@ +[template] +src = "php.ini.tmpl" +dest = "/etc/php7/php.ini" +uid = 0 +gid = 0 +mode = "0644" +keys = [ "/php" ] diff --git a/nginx/rootfs/etc/confd/conf.d/www.conf.toml b/nginx/rootfs/etc/confd/conf.d/www.conf.toml new file mode 100644 index 00000000..60b953ea --- /dev/null +++ b/nginx/rootfs/etc/confd/conf.d/www.conf.toml @@ -0,0 +1,7 @@ +[template] +src = "www.conf.tmpl" +dest = "/etc/php7/php-fpm.d/www.conf" +uid = 0 +gid = 0 +mode = "0644" +keys = [ "/php" ] diff --git a/nginx/rootfs/etc/confd/templates/nginx.conf.tmpl b/nginx/rootfs/etc/confd/templates/nginx.conf.tmpl new file mode 100644 index 00000000..105042d6 --- /dev/null +++ b/nginx/rootfs/etc/confd/templates/nginx.conf.tmpl @@ -0,0 +1,85 @@ +user nginx; + +# Set number of worker processes automatically based on number of CPU cores. +worker_processes {{ getv "/nginx/worker/processes" "auto" }}; + +# Enables the use of JIT for regular expressions to speed-up their processing. +pcre_jit on; + +# Configures default error logger. +error_log /var/log/nginx/error.log {{ getv "/nginx/error/log/level" "warn" }}; + +# Includes files with directives to load dynamic modules. +include /etc/nginx/modules/*.conf; + + +events { + # The maximum number of simultaneous connections that can be opened by + # a worker process. + worker_connections {{ getv "/nginx/worker/connections" "1024" }}; +} + +http { + # Includes mapping of file name extensions to MIME types of responses + # and defines the default type. + include /etc/nginx/mime.types; + default_type application/octet-stream; + + # Name servers used to resolve names of upstream servers into addresses. + # It's also needed when using tcpsocket and udpsocket in Lua modules. + #resolver 208.67.222.222 208.67.220.220; + + # Don't tell nginx version to clients. + server_tokens off; + + # Specifies the maximum accepted body size of a client request, as + # indicated by the request header Content-Length. If the stated content + # length is greater than this size, then the client receives the HTTP + # error code 413. Set to 0 to disable. + client_max_body_size {{ getv "/nginx/client/max/body/size" "0" }}; + + # Timeout for keep-alive connections. Server will close connections after + # this time. + keepalive_timeout {{ getv "/nginx/keepalive/timeout" "65" }}; + + # Sendfile copies data between one FD and other from within the kernel, + # which is more efficient than read() + write(). + sendfile on; + + # Don't buffer data-sends (disable Nagle algorithm). + # Good for sending frequent small bursts of data in real time. + tcp_nodelay on; + + # Causes nginx to attempt to send its HTTP response head in one packet, + # instead of using partial frames. + #tcp_nopush on; + + # Path of the file with Diffie-Hellman parameters for EDH ciphers. + #ssl_dhparam /etc/ssl/nginx/dh2048.pem; + + # Specifies that our cipher suits should be preferred over client ciphers. + ssl_prefer_server_ciphers on; + + # Enables a shared SSL cache with size that can hold around 8000 sessions. + ssl_session_cache shared:SSL:2m; + + # Enable gzipping of responses. + #gzip on; + + # Set the Vary HTTP header as defined in the RFC 2616. + gzip_vary on; + + # Enable checking the existence of precompressed files. + #gzip_static on; + + # Specifies the main log format. + log_format main '$remote_addr - $remote_user [$time_local] "$request" ' + '$status $body_bytes_sent "$http_referer" ' + '"$http_user_agent" "$http_x_forwarded_for"'; + + # Sets the path, format, and configuration for a buffered log write. + access_log /var/log/nginx/access.log main; + + # Includes virtual hosts configs. + include /etc/nginx/conf.d/*.conf; +} diff --git a/nginx/rootfs/etc/confd/templates/php-fpm.conf.tmpl b/nginx/rootfs/etc/confd/templates/php-fpm.conf.tmpl new file mode 100644 index 00000000..834fd9bd --- /dev/null +++ b/nginx/rootfs/etc/confd/templates/php-fpm.conf.tmpl @@ -0,0 +1,136 @@ +;;;;;;;;;;;;;;;;;;;;; +; FPM Configuration ; +;;;;;;;;;;;;;;;;;;;;; + +; All relative paths in this configuration file are relative to PHP's install +; prefix (/usr). This prefix can be dynamically changed by using the +; '-p' argument from the command line. + +;;;;;;;;;;;;;;;;;; +; Global Options ; +;;;;;;;;;;;;;;;;;; + +[global] +; Pid file +; Note: the default prefix is /var +; Default Value: none +pid = run/php-fpm7.pid + +; Error log file +; If it's set to "syslog", log is sent to syslogd instead of being written +; into a local file. +; Note: the default prefix is /var +; Default Value: log/php7/error.log +;error_log = log/php7/error.log + +; syslog_facility is used to specify what type of program is logging the +; message. This lets syslogd specify that messages from different facilities +; will be handled differently. +; See syslog(3) for possible values (ex daemon equiv LOG_DAEMON) +; Default Value: daemon +;syslog.facility = daemon + +; syslog_ident is prepended to every message. If you have multiple FPM +; instances running on the same server, you can change the default value +; which must suit common needs. +; Default Value: php-fpm7 +;syslog.ident = php-fpm7 + +; Log level +; Possible Values: alert, error, warning, notice, debug +; Default Value: notice +;log_level = notice + +; Log limit on number of characters in the single line (log entry). If the +; line is over the limit, it is wrapped on multiple lines. The limit is for +; all logged characters including message prefix and suffix if present. However +; the new line character does not count into it as it is present only when +; logging to a file descriptor. It means the new line character is not present +; when logging to syslog. +; Default Value: 1024 +;log_limit = 4096 + +; Log buffering specifies if the log line is buffered which means that the +; line is written in a single write operation. If the value is false, then the +; data is written directly into the file descriptor. It is an experimental +; option that can potentionaly improve logging performance and memory usage +; for some heavy logging scenarios. This option is ignored if logging to syslog +; as it has to be always buffered. +; Default value: yes +;log_buffering = no + +; If this number of child processes exit with SIGSEGV or SIGBUS within the time +; interval set by emergency_restart_interval then FPM will restart. A value +; of '0' means 'Off'. +; Default Value: 0 +;emergency_restart_threshold = 0 + +; Interval of time used by emergency_restart_interval to determine when +; a graceful restart will be initiated. This can be useful to work around +; accidental corruptions in an accelerator's shared memory. +; Available Units: s(econds), m(inutes), h(ours), or d(ays) +; Default Unit: seconds +; Default Value: 0 +;emergency_restart_interval = 0 + +; Time limit for child processes to wait for a reaction on signals from master. +; Available units: s(econds), m(inutes), h(ours), or d(ays) +; Default Unit: seconds +; Default Value: 0 +;process_control_timeout = 0 + +; The maximum number of processes FPM will fork. This has been designed to control +; the global number of processes when using dynamic PM within a lot of pools. +; Use it with caution. +; Note: A value of 0 indicates no limit +; Default Value: 0 +; process.max = 128 + +; Specify the nice(2) priority to apply to the master process (only if set) +; The value can vary from -19 (highest priority) to 20 (lowest priority) +; Note: - It will only work if the FPM master process is launched as root +; - The pool process will inherit the master process priority +; unless specified otherwise +; Default Value: no set +; process.priority = -19 + +; Send FPM to background. Set to 'no' to keep FPM in foreground for debugging. +; Default Value: yes +daemonize = no + +; Set open file descriptor rlimit for the master process. +; Default Value: system defined value +;rlimit_files = 1024 + +; Set max core size rlimit for the master process. +; Possible Values: 'unlimited' or an integer greater or equal to 0 +; Default Value: system defined value +;rlimit_core = 0 + +; Specify the event mechanism FPM will use. The following is available: +; - select (any POSIX os) +; - poll (any POSIX os) +; - epoll (linux >= 2.5.44) +; - kqueue (FreeBSD >= 4.1, OpenBSD >= 2.9, NetBSD >= 2.0) +; - /dev/poll (Solaris >= 7) +; - port (Solaris >= 10) +; Default Value: not set (auto detection) +;events.mechanism = epoll + +; When FPM is built with systemd integration, specify the interval, +; in seconds, between health report notification to systemd. +; Set to 0 to disable. +; Available Units: s(econds), m(inutes), h(ours) +; Default Unit: seconds +; Default value: 10 +;systemd_interval = 10 + +;;;;;;;;;;;;;;;;;;;; +; Pool Definitions ; +;;;;;;;;;;;;;;;;;;;; + +; Multiple pools of child processes may be started with different listening +; ports and different management options. The name of the pool will be +; used in logs and stats. There is no limitation on the number of pools which +; FPM can handle. Your system will tell you anyway :) +include=/etc/php7/php-fpm.d/*.conf diff --git a/nginx/rootfs/etc/confd/templates/php.ini.tmpl b/nginx/rootfs/etc/confd/templates/php.ini.tmpl new file mode 100644 index 00000000..8327548b --- /dev/null +++ b/nginx/rootfs/etc/confd/templates/php.ini.tmpl @@ -0,0 +1,1939 @@ +[PHP] + +;;;;;;;;;;;;;;;;;;; +; About php.ini ; +;;;;;;;;;;;;;;;;;;; +; PHP's initialization file, generally called php.ini, is responsible for +; configuring many of the aspects of PHP's behavior. + +; PHP attempts to find and load this configuration from a number of locations. +; The following is a summary of its search order: +; 1. SAPI module specific location. +; 2. The PHPRC environment variable. (As of PHP 5.2.0) +; 3. A number of predefined registry keys on Windows (As of PHP 5.2.0) +; 4. Current working directory (except CLI) +; 5. The web server's directory (for SAPI modules), or directory of PHP +; (otherwise in Windows) +; 6. The directory from the --with-config-file-path compile time option, or the +; Windows directory (usually C:\windows) +; See the PHP docs for more specific information. +; http://php.net/configuration.file + +; The syntax of the file is extremely simple. Whitespace and lines +; beginning with a semicolon are silently ignored (as you probably guessed). +; Section headers (e.g. [Foo]) are also silently ignored, even though +; they might mean something in the future. + +; Directives following the section heading [PATH=/www/mysite] only +; apply to PHP files in the /www/mysite directory. Directives +; following the section heading [HOST=www.example.com] only apply to +; PHP files served from www.example.com. Directives set in these +; special sections cannot be overridden by user-defined INI files or +; at runtime. Currently, [PATH=] and [HOST=] sections only work under +; CGI/FastCGI. +; http://php.net/ini.sections + +; Directives are specified using the following syntax: +; directive = value +; Directive names are *case sensitive* - foo=bar is different from FOO=bar. +; Directives are variables used to configure PHP or PHP extensions. +; There is no name validation. If PHP can't find an expected +; directive because it is not set or is mistyped, a default value will be used. + +; The value can be a string, a number, a PHP constant (e.g. E_ALL or M_PI), one +; of the INI constants (On, Off, True, False, Yes, No and None) or an expression +; (e.g. E_ALL & ~E_NOTICE), a quoted string ("bar"), or a reference to a +; previously set variable or directive (e.g. ${foo}) + +; Expressions in the INI file are limited to bitwise operators and parentheses: +; | bitwise OR +; ^ bitwise XOR +; & bitwise AND +; ~ bitwise NOT +; ! boolean NOT + +; Boolean flags can be turned on using the values 1, On, True or Yes. +; They can be turned off using the values 0, Off, False or No. + +; An empty string can be denoted by simply not writing anything after the equal +; sign, or by using the None keyword: + +; foo = ; sets foo to an empty string +; foo = None ; sets foo to an empty string +; foo = "None" ; sets foo to the string 'None' + +; If you use constants in your value, and these constants belong to a +; dynamically loaded extension (either a PHP extension or a Zend extension), +; you may only use these constants *after* the line that loads the extension. + +;;;;;;;;;;;;;;;;;;; +; About this file ; +;;;;;;;;;;;;;;;;;;; +; PHP comes packaged with two INI files. One that is recommended to be used +; in production environments and one that is recommended to be used in +; development environments. + +; php.ini-production contains settings which hold security, performance and +; best practices at its core. But please be aware, these settings may break +; compatibility with older or less security conscience applications. We +; recommending using the production ini in production and testing environments. + +; php.ini-development is very similar to its production variant, except it is +; much more verbose when it comes to errors. We recommend using the +; development version only in development environments, as errors shown to +; application users can inadvertently leak otherwise secure information. + +; This is the php.ini-production INI file. + +;;;;;;;;;;;;;;;;;;; +; Quick Reference ; +;;;;;;;;;;;;;;;;;;; +; The following are all the settings which are different in either the production +; or development versions of the INIs with respect to PHP's default behavior. +; Please see the actual settings later in the document for more details as to why +; we recommend these changes in PHP's behavior. + +; display_errors +; Default Value: On +; Development Value: On +; Production Value: Off + +; display_startup_errors +; Default Value: Off +; Development Value: On +; Production Value: Off + +; error_reporting +; Default Value: E_ALL & ~E_NOTICE & ~E_STRICT & ~E_DEPRECATED +; Development Value: E_ALL +; Production Value: E_ALL & ~E_DEPRECATED & ~E_STRICT + +; html_errors +; Default Value: On +; Development Value: On +; Production value: On + +; log_errors +; Default Value: Off +; Development Value: On +; Production Value: On + +; max_input_time +; Default Value: -1 (Unlimited) +; Development Value: 60 (60 seconds) +; Production Value: 60 (60 seconds) + +; output_buffering +; Default Value: Off +; Development Value: 4096 +; Production Value: 4096 + +; register_argc_argv +; Default Value: On +; Development Value: Off +; Production Value: Off + +; request_order +; Default Value: None +; Development Value: "GP" +; Production Value: "GP" + +; session.gc_divisor +; Default Value: 100 +; Development Value: 1000 +; Production Value: 1000 + +; session.sid_bits_per_character +; Default Value: 4 +; Development Value: 5 +; Production Value: 5 + +; short_open_tag +; Default Value: On +; Development Value: Off +; Production Value: Off + +; variables_order +; Default Value: "EGPCS" +; Development Value: "GPCS" +; Production Value: "GPCS" + +;;;;;;;;;;;;;;;;;;;; +; php.ini Options ; +;;;;;;;;;;;;;;;;;;;; +; Name for user-defined php.ini (.htaccess) files. Default is ".user.ini" +;user_ini.filename = ".user.ini" + +; To disable this feature set this option to an empty value +;user_ini.filename = + +; TTL for user-defined php.ini files (time-to-live) in seconds. Default is 300 seconds (5 minutes) +;user_ini.cache_ttl = 300 + +;;;;;;;;;;;;;;;;;;;; +; Language Options ; +;;;;;;;;;;;;;;;;;;;; + +; Enable the PHP scripting language engine under Apache. +; http://php.net/engine +engine = On + +; This directive determines whether or not PHP will recognize code between +; tags as PHP source which should be processed as such. It is +; generally recommended that should be used and that this feature +; should be disabled, as enabling it may result in issues when generating XML +; documents, however this remains supported for backward compatibility reasons. +; Note that this directive does not control the would work. +; http://php.net/syntax-highlighting +;highlight.string = #DD0000 +;highlight.comment = #FF9900 +;highlight.keyword = #007700 +;highlight.default = #0000BB +;highlight.html = #000000 + +; If enabled, the request will be allowed to complete even if the user aborts +; the request. Consider enabling it if executing long requests, which may end up +; being interrupted by the user or a browser timing out. PHP's default behavior +; is to disable this feature. +; http://php.net/ignore-user-abort +;ignore_user_abort = On + +; Determines the size of the realpath cache to be used by PHP. This value should +; be increased on systems where PHP opens many files to reflect the quantity of +; the file operations performed. +; Note: if open_basedir is set, the cache is disabled +; http://php.net/realpath-cache-size +;realpath_cache_size = 4096k + +; Duration of time, in seconds for which to cache realpath information for a given +; file or directory. For systems with rarely changing files, consider increasing this +; value. +; http://php.net/realpath-cache-ttl +;realpath_cache_ttl = 120 + +; Enables or disables the circular reference collector. +; http://php.net/zend.enable-gc +zend.enable_gc = On + +; If enabled, scripts may be written in encodings that are incompatible with +; the scanner. CP936, Big5, CP949 and Shift_JIS are the examples of such +; encodings. To use this feature, mbstring extension must be enabled. +; Default: Off +;zend.multibyte = Off + +; Allows to set the default encoding for the scripts. This value will be used +; unless "declare(encoding=...)" directive appears at the top of the script. +; Only affects if zend.multibyte is set. +; Default: "" +;zend.script_encoding = + +;;;;;;;;;;;;;;;;; +; Miscellaneous ; +;;;;;;;;;;;;;;;;; + +; Decides whether PHP may expose the fact that it is installed on the server +; (e.g. by adding its signature to the Web server header). It is no security +; threat in any way, but it makes it possible to determine whether you use PHP +; on your server or not. +; http://php.net/expose-php +expose_php = On + +;;;;;;;;;;;;;;;;;;; +; Resource Limits ; +;;;;;;;;;;;;;;;;;;; + +; Maximum execution time of each script, in seconds +; http://php.net/max-execution-time +; Note: This directive is hardcoded to 0 for the CLI SAPI +max_execution_time = {{ getv "/php/max/execution/time" "30" }} + +; Maximum amount of time each script may spend parsing request data. It's a good +; idea to limit this time on productions servers in order to eliminate unexpectedly +; long running scripts. +; Note: This directive is hardcoded to -1 for the CLI SAPI +; Default Value: -1 (Unlimited) +; Development Value: 60 (60 seconds) +; Production Value: 60 (60 seconds) +; http://php.net/max-input-time +max_input_time = {{ getv "/php/max/input/time" "60" }} + +; Maximum input variable nesting level +; http://php.net/max-input-nesting-level +;max_input_nesting_level = 64 + +; How many GET/POST/COOKIE input variables may be accepted +;max_input_vars = 1000 + +; Maximum amount of memory a script may consume (128MB) +; http://php.net/memory-limit +memory_limit = {{ getv "/php/memory/limit" "256M" }} + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; Error handling and logging ; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +; This directive informs PHP of which errors, warnings and notices you would like +; it to take action for. The recommended way of setting values for this +; directive is through the use of the error level constants and bitwise +; operators. The error level constants are below here for convenience as well as +; some common settings and their meanings. +; By default, PHP is set to take action on all errors, notices and warnings EXCEPT +; those related to E_NOTICE and E_STRICT, which together cover best practices and +; recommended coding standards in PHP. For performance reasons, this is the +; recommend error reporting setting. Your production server shouldn't be wasting +; resources complaining about best practices and coding standards. That's what +; development servers and development settings are for. +; Note: The php.ini-development file has this setting as E_ALL. This +; means it pretty much reports everything which is exactly what you want during +; development and early testing. +; +; Error Level Constants: +; E_ALL - All errors and warnings (includes E_STRICT as of PHP 5.4.0) +; E_ERROR - fatal run-time errors +; E_RECOVERABLE_ERROR - almost fatal run-time errors +; E_WARNING - run-time warnings (non-fatal errors) +; E_PARSE - compile-time parse errors +; E_NOTICE - run-time notices (these are warnings which often result +; from a bug in your code, but it's possible that it was +; intentional (e.g., using an uninitialized variable and +; relying on the fact it is automatically initialized to an +; empty string) +; E_STRICT - run-time notices, enable to have PHP suggest changes +; to your code which will ensure the best interoperability +; and forward compatibility of your code +; E_CORE_ERROR - fatal errors that occur during PHP's initial startup +; E_CORE_WARNING - warnings (non-fatal errors) that occur during PHP's +; initial startup +; E_COMPILE_ERROR - fatal compile-time errors +; E_COMPILE_WARNING - compile-time warnings (non-fatal errors) +; E_USER_ERROR - user-generated error message +; E_USER_WARNING - user-generated warning message +; E_USER_NOTICE - user-generated notice message +; E_DEPRECATED - warn about code that will not work in future versions +; of PHP +; E_USER_DEPRECATED - user-generated deprecation warnings +; +; Common Values: +; E_ALL (Show all errors, warnings and notices including coding standards.) +; E_ALL & ~E_NOTICE (Show all errors, except for notices) +; E_ALL & ~E_NOTICE & ~E_STRICT (Show all errors, except for notices and coding standards warnings.) +; E_COMPILE_ERROR|E_RECOVERABLE_ERROR|E_ERROR|E_CORE_ERROR (Show only errors) +; Default Value: E_ALL & ~E_NOTICE & ~E_STRICT & ~E_DEPRECATED +; Development Value: E_ALL +; Production Value: E_ALL & ~E_DEPRECATED & ~E_STRICT +; http://php.net/error-reporting +error_reporting = E_ALL & ~E_DEPRECATED & ~E_STRICT + +; This directive controls whether or not and where PHP will output errors, +; notices and warnings too. Error output is very useful during development, but +; it could be very dangerous in production environments. Depending on the code +; which is triggering the error, sensitive information could potentially leak +; out of your application such as database usernames and passwords or worse. +; For production environments, we recommend logging errors rather than +; sending them to STDOUT. +; Possible Values: +; Off = Do not display any errors +; stderr = Display errors to STDERR (affects only CGI/CLI binaries!) +; On or stdout = Display errors to STDOUT +; Default Value: On +; Development Value: On +; Production Value: Off +; http://php.net/display-errors +display_errors = Off + +; The display of errors which occur during PHP's startup sequence are handled +; separately from display_errors. PHP's default behavior is to suppress those +; errors from clients. Turning the display of startup errors on can be useful in +; debugging configuration problems. We strongly recommend you +; set this to 'off' for production servers. +; Default Value: Off +; Development Value: On +; Production Value: Off +; http://php.net/display-startup-errors +display_startup_errors = Off + +; Besides displaying errors, PHP can also log errors to locations such as a +; server-specific log, STDERR, or a location specified by the error_log +; directive found below. While errors should not be displayed on productions +; servers they should still be monitored and logging is a great way to do that. +; Default Value: Off +; Development Value: On +; Production Value: On +; http://php.net/log-errors +log_errors = On + +; Set maximum length of log_errors. In error_log information about the source is +; added. The default is 1024 and 0 allows to not apply any maximum length at all. +; http://php.net/log-errors-max-len +log_errors_max_len = 1024 + +; Do not log repeated messages. Repeated errors must occur in same file on same +; line unless ignore_repeated_source is set true. +; http://php.net/ignore-repeated-errors +ignore_repeated_errors = Off + +; Ignore source of message when ignoring repeated messages. When this setting +; is On you will not log errors with repeated messages from different files or +; source lines. +; http://php.net/ignore-repeated-source +ignore_repeated_source = Off + +; If this parameter is set to Off, then memory leaks will not be shown (on +; stdout or in the log). This has only effect in a debug compile, and if +; error reporting includes E_WARNING in the allowed list +; http://php.net/report-memleaks +report_memleaks = On + +; This setting is on by default. +;report_zend_debug = 0 + +; Store the last error/warning message in $php_errormsg (boolean). Setting this value +; to On can assist in debugging and is appropriate for development servers. It should +; however be disabled on production servers. +; This directive is DEPRECATED. +; Default Value: Off +; Development Value: Off +; Production Value: Off +; http://php.net/track-errors +;track_errors = Off + +; Turn off normal error reporting and emit XML-RPC error XML +; http://php.net/xmlrpc-errors +;xmlrpc_errors = 0 + +; An XML-RPC faultCode +;xmlrpc_error_number = 0 + +; When PHP displays or logs an error, it has the capability of formatting the +; error message as HTML for easier reading. This directive controls whether +; the error message is formatted as HTML or not. +; Note: This directive is hardcoded to Off for the CLI SAPI +; Default Value: On +; Development Value: On +; Production value: On +; http://php.net/html-errors +html_errors = On + +; If html_errors is set to On *and* docref_root is not empty, then PHP +; produces clickable error messages that direct to a page describing the error +; or function causing the error in detail. +; You can download a copy of the PHP manual from http://php.net/docs +; and change docref_root to the base URL of your local copy including the +; leading '/'. You must also specify the file extension being used including +; the dot. PHP's default behavior is to leave these settings empty, in which +; case no links to documentation are generated. +; Note: Never use this feature for production boxes. +; http://php.net/docref-root +; Examples +;docref_root = "/phpmanual/" + +; http://php.net/docref-ext +;docref_ext = .html + +; String to output before an error message. PHP's default behavior is to leave +; this setting blank. +; http://php.net/error-prepend-string +; Example: +;error_prepend_string = "" + +; String to output after an error message. PHP's default behavior is to leave +; this setting blank. +; http://php.net/error-append-string +; Example: +;error_append_string = "" + +; Log errors to specified file. PHP's default behavior is to leave this value +; empty. +; http://php.net/error-log +; Example: +;error_log = php_errors.log +; Log errors to syslog (Event Log on Windows). +;error_log = syslog + +; The syslog ident is a string which is prepended to every message logged +; to syslog. Only used when error_log is set to syslog. +;syslog.ident = php + +; The syslog facility is used to specify what type of program is logging +; the message. Only used when error_log is set to syslog. +;syslog.facility = user + +; Set this to disable filtering control characters (the default). +; Some loggers only accept NVT-ASCII, others accept anything that's not +; control characters. If your logger accepts everything, then no filtering +; is needed at all. +; Allowed values are: +; ascii (all printable ASCII characters and NL) +; no-ctrl (all characters except control characters) +; all (all characters) +; raw (like "all", but messages are not split at newlines) +; http://php.net/syslog.filter +;syslog.filter = ascii + +;windows.show_crt_warning +; Default value: 0 +; Development value: 0 +; Production value: 0 + +;;;;;;;;;;;;;;;;; +; Data Handling ; +;;;;;;;;;;;;;;;;; + +; The separator used in PHP generated URLs to separate arguments. +; PHP's default setting is "&". +; http://php.net/arg-separator.output +; Example: +;arg_separator.output = "&" + +; List of separator(s) used by PHP to parse input URLs into variables. +; PHP's default setting is "&". +; NOTE: Every character in this directive is considered as separator! +; http://php.net/arg-separator.input +; Example: +;arg_separator.input = ";&" + +; This directive determines which super global arrays are registered when PHP +; starts up. G,P,C,E & S are abbreviations for the following respective super +; globals: GET, POST, COOKIE, ENV and SERVER. There is a performance penalty +; paid for the registration of these arrays and because ENV is not as commonly +; used as the others, ENV is not recommended on productions servers. You +; can still get access to the environment variables through getenv() should you +; need to. +; Default Value: "EGPCS" +; Development Value: "GPCS" +; Production Value: "GPCS"; +; http://php.net/variables-order +variables_order = "GPCS" + +; This directive determines which super global data (G,P & C) should be +; registered into the super global array REQUEST. If so, it also determines +; the order in which that data is registered. The values for this directive +; are specified in the same manner as the variables_order directive, +; EXCEPT one. Leaving this value empty will cause PHP to use the value set +; in the variables_order directive. It does not mean it will leave the super +; globals array REQUEST empty. +; Default Value: None +; Development Value: "GP" +; Production Value: "GP" +; http://php.net/request-order +request_order = "GP" + +; This directive determines whether PHP registers $argv & $argc each time it +; runs. $argv contains an array of all the arguments passed to PHP when a script +; is invoked. $argc contains an integer representing the number of arguments +; that were passed when the script was invoked. These arrays are extremely +; useful when running scripts from the command line. When this directive is +; enabled, registering these variables consumes CPU cycles and memory each time +; a script is executed. For performance reasons, this feature should be disabled +; on production servers. +; Note: This directive is hardcoded to On for the CLI SAPI +; Default Value: On +; Development Value: Off +; Production Value: Off +; http://php.net/register-argc-argv +register_argc_argv = Off + +; When enabled, the ENV, REQUEST and SERVER variables are created when they're +; first used (Just In Time) instead of when the script starts. If these +; variables are not used within a script, having this directive on will result +; in a performance gain. The PHP directive register_argc_argv must be disabled +; for this directive to have any affect. +; http://php.net/auto-globals-jit +auto_globals_jit = On + +; Whether PHP will read the POST data. +; This option is enabled by default. +; Most likely, you won't want to disable this option globally. It causes $_POST +; and $_FILES to always be empty; the only way you will be able to read the +; POST data will be through the php://input stream wrapper. This can be useful +; to proxy requests or to process the POST data in a memory efficient fashion. +; http://php.net/enable-post-data-reading +;enable_post_data_reading = Off + +; Maximum size of POST data that PHP will accept. +; Its value may be 0 to disable the limit. It is ignored if POST data reading +; is disabled through enable_post_data_reading. +; http://php.net/post-max-size +post_max_size = {{ getv "/php/post/max/size" "0" }} + +; Automatically add files before PHP document. +; http://php.net/auto-prepend-file +auto_prepend_file = + +; Automatically add files after PHP document. +; http://php.net/auto-append-file +auto_append_file = + +; By default, PHP will output a media type using the Content-Type header. To +; disable this, simply set it to be empty. +; +; PHP's built-in default media type is set to text/html. +; http://php.net/default-mimetype +default_mimetype = "text/html" + +; PHP's default character set is set to UTF-8. +; http://php.net/default-charset +default_charset = "UTF-8" + +; PHP internal character encoding is set to empty. +; If empty, default_charset is used. +; http://php.net/internal-encoding +;internal_encoding = + +; PHP input character encoding is set to empty. +; If empty, default_charset is used. +; http://php.net/input-encoding +;input_encoding = + +; PHP output character encoding is set to empty. +; If empty, default_charset is used. +; See also output_buffer. +; http://php.net/output-encoding +;output_encoding = + +;;;;;;;;;;;;;;;;;;;;;;;;; +; Paths and Directories ; +;;;;;;;;;;;;;;;;;;;;;;;;; + +; UNIX: "/path1:/path2" +include_path = ".:/usr/share/php7" +; +; Windows: "\path1;\path2" +;include_path = ".;c:\php\includes" +; +; PHP's default setting for include_path is ".;/path/to/php/pear" +; http://php.net/include-path + +; The root of the PHP pages, used only if nonempty. +; if PHP was not compiled with FORCE_REDIRECT, you SHOULD set doc_root +; if you are running php as a CGI under any web server (other than IIS) +; see documentation for security issues. The alternate is to use the +; cgi.force_redirect configuration below +; http://php.net/doc-root +doc_root = + +; The directory under which PHP opens the script using /~username used only +; if nonempty. +; http://php.net/user-dir +user_dir = + +; Directory in which the loadable extensions (modules) reside. +; http://php.net/extension-dir +;extension_dir = "./" +; On windows: +;extension_dir = "ext" + +; Directory where the temporary files should be placed. +; Defaults to the system default (see sys_get_temp_dir) +;sys_temp_dir = "/tmp" + +; Whether or not to enable the dl() function. The dl() function does NOT work +; properly in multithreaded servers, such as IIS or Zeus, and is automatically +; disabled on them. +; http://php.net/enable-dl +enable_dl = Off + +; cgi.force_redirect is necessary to provide security running PHP as a CGI under +; most web servers. Left undefined, PHP turns this on by default. You can +; turn it off here AT YOUR OWN RISK +; **You CAN safely turn this off for IIS, in fact, you MUST.** +; http://php.net/cgi.force-redirect +;cgi.force_redirect = 1 + +; if cgi.nph is enabled it will force cgi to always sent Status: 200 with +; every request. PHP's default behavior is to disable this feature. +;cgi.nph = 1 + +; if cgi.force_redirect is turned on, and you are not running under Apache or Netscape +; (iPlanet) web servers, you MAY need to set an environment variable name that PHP +; will look for to know it is OK to continue execution. Setting this variable MAY +; cause security issues, KNOW WHAT YOU ARE DOING FIRST. +; http://php.net/cgi.redirect-status-env +;cgi.redirect_status_env = + +; cgi.fix_pathinfo provides *real* PATH_INFO/PATH_TRANSLATED support for CGI. PHP's +; previous behaviour was to set PATH_TRANSLATED to SCRIPT_FILENAME, and to not grok +; what PATH_INFO is. For more information on PATH_INFO, see the cgi specs. Setting +; this to 1 will cause PHP CGI to fix its paths to conform to the spec. A setting +; of zero causes PHP to behave as before. Default is 1. You should fix your scripts +; to use SCRIPT_FILENAME rather than PATH_TRANSLATED. +; http://php.net/cgi.fix-pathinfo +;cgi.fix_pathinfo=1 + +; if cgi.discard_path is enabled, the PHP CGI binary can safely be placed outside +; of the web tree and people will not be able to circumvent .htaccess security. +;cgi.discard_path=1 + +; FastCGI under IIS supports the ability to impersonate +; security tokens of the calling client. This allows IIS to define the +; security context that the request runs under. mod_fastcgi under Apache +; does not currently support this feature (03/17/2002) +; Set to 1 if running under IIS. Default is zero. +; http://php.net/fastcgi.impersonate +;fastcgi.impersonate = 1 + +; Disable logging through FastCGI connection. PHP's default behavior is to enable +; this feature. +;fastcgi.logging = 0 + +; cgi.rfc2616_headers configuration option tells PHP what type of headers to +; use when sending HTTP response code. If set to 0, PHP sends Status: header that +; is supported by Apache. When this option is set to 1, PHP will send +; RFC2616 compliant header. +; Default is zero. +; http://php.net/cgi.rfc2616-headers +;cgi.rfc2616_headers = 0 + +; cgi.check_shebang_line controls whether CGI PHP checks for line starting with #! +; (shebang) at the top of the running script. This line might be needed if the +; script support running both as stand-alone script and via PHP CGI<. PHP in CGI +; mode skips this line and ignores its content if this directive is turned on. +; http://php.net/cgi.check-shebang-line +;cgi.check_shebang_line=1 + +;;;;;;;;;;;;;;;; +; File Uploads ; +;;;;;;;;;;;;;;;; + +; Whether to allow HTTP file uploads. +; http://php.net/file-uploads +file_uploads = On + +; Temporary directory for HTTP uploaded files (will use system default if not +; specified). +; http://php.net/upload-tmp-dir +;upload_tmp_dir = + +; Maximum allowed size for uploaded files. +; http://php.net/upload-max-filesize +upload_max_filesize = {{ getv "/php/upload/max/filesize" "128M" }} + +; Maximum number of files that can be uploaded via a single request +max_file_uploads = {{ getv "/php/max/file/uploads" "20" }} + +;;;;;;;;;;;;;;;;;; +; Fopen wrappers ; +;;;;;;;;;;;;;;;;;; + +; Whether to allow the treatment of URLs (like http:// or ftp://) as files. +; http://php.net/allow-url-fopen +allow_url_fopen = On + +; Whether to allow include/require to open URLs (like http:// or ftp://) as files. +; http://php.net/allow-url-include +allow_url_include = Off + +; Define the anonymous ftp password (your email address). PHP's default setting +; for this is empty. +; http://php.net/from +;from="john@doe.com" + +; Define the User-Agent string. PHP's default setting for this is empty. +; http://php.net/user-agent +;user_agent="PHP" + +; Default timeout for socket based streams (seconds) +; http://php.net/default-socket-timeout +default_socket_timeout = {{ getv "/php/default/socket/timeout" "60" }} + +; If your scripts have to deal with files from Macintosh systems, +; or you are running on a Mac and need to deal with files from +; unix or win32 systems, setting this flag will cause PHP to +; automatically detect the EOL character in those files so that +; fgets() and file() will work regardless of the source of the file. +; http://php.net/auto-detect-line-endings +;auto_detect_line_endings = Off + +;;;;;;;;;;;;;;;;;;;;;; +; Dynamic Extensions ; +;;;;;;;;;;;;;;;;;;;;;; + +; If you wish to have an extension loaded automatically, use the following +; syntax: +; +; extension=modulename +; +; For example: +; +; extension=mysqli +; +; When the extension library to load is not located in the default extension +; directory, You may specify an absolute path to the library file: +; +; extension=/path/to/extension/mysqli.so +; +; Note : The syntax used in previous PHP versions ('extension=.so' and +; 'extension='php_.dll') is supported for legacy reasons and may be +; deprecated in a future PHP major version. So, when it is possible, please +; move to the new ('extension=) syntax. +; +; Notes for Windows environments : +; +; - Many DLL files are located in the extensions/ (PHP 4) or ext/ (PHP 5+) +; extension folders as well as the separate PECL DLL download (PHP 5+). +; Be sure to appropriately set the extension_dir directive. +; +;extension=bz2 +;extension=curl +;extension=fileinfo +;extension=gd2 +;extension=gettext +;extension=gmp +;extension=intl +;extension=imap +;extension=interbase +;extension=ldap +;extension=mbstring +;extension=exif ; Must be after mbstring as it depends on it +;extension=mysqli +;extension=oci8_12c ; Use with Oracle Database 12c Instant Client +;extension=odbc +;extension=openssl +;extension=pdo_firebird +;extension=pdo_mysql +;extension=pdo_oci +;extension=pdo_odbc +;extension=pdo_pgsql +;extension=pdo_sqlite +;extension=pgsql +;extension=shmop + +; The MIBS data available in the PHP distribution must be installed. +; See http://www.php.net/manual/en/snmp.installation.php +;extension=snmp + +;extension=soap +;extension=sockets +;extension=sodium +;extension=sqlite3 +;extension=tidy +;extension=xmlrpc +;extension=xsl + +;;;;;;;;;;;;;;;;;;; +; Module Settings ; +;;;;;;;;;;;;;;;;;;; + +[CLI Server] +; Whether the CLI web server uses ANSI color coding in its terminal output. +cli_server.color = On + +[Date] +; Defines the default timezone used by the date functions +; http://php.net/date.timezone +;date.timezone = + +; http://php.net/date.default-latitude +;date.default_latitude = 31.7667 + +; http://php.net/date.default-longitude +;date.default_longitude = 35.2333 + +; http://php.net/date.sunrise-zenith +;date.sunrise_zenith = 90.583333 + +; http://php.net/date.sunset-zenith +;date.sunset_zenith = 90.583333 + +[filter] +; http://php.net/filter.default +;filter.default = unsafe_raw + +; http://php.net/filter.default-flags +;filter.default_flags = + +[iconv] +; Use of this INI entry is deprecated, use global input_encoding instead. +; If empty, default_charset or input_encoding or iconv.input_encoding is used. +; The precedence is: default_charset < input_encoding < iconv.input_encoding +;iconv.input_encoding = + +; Use of this INI entry is deprecated, use global internal_encoding instead. +; If empty, default_charset or internal_encoding or iconv.internal_encoding is used. +; The precedence is: default_charset < internal_encoding < iconv.internal_encoding +;iconv.internal_encoding = + +; Use of this INI entry is deprecated, use global output_encoding instead. +; If empty, default_charset or output_encoding or iconv.output_encoding is used. +; The precedence is: default_charset < output_encoding < iconv.output_encoding +; To use an output encoding conversion, iconv's output handler must be set +; otherwise output encoding conversion cannot be performed. +;iconv.output_encoding = + +[imap] +; rsh/ssh logins are disabled by default. Use this INI entry if you want to +; enable them. Note that the IMAP library does not filter mailbox names before +; passing them to rsh/ssh command, thus passing untrusted data to this function +; with rsh/ssh enabled is insecure. +;imap.enable_insecure_rsh=0 + +[intl] +;intl.default_locale = +; This directive allows you to produce PHP errors when some error +; happens within intl functions. The value is the level of the error produced. +; Default is 0, which does not produce any errors. +;intl.error_level = E_WARNING +;intl.use_exceptions = 0 + +[sqlite3] +; Directory pointing to SQLite3 extensions +; http://php.net/sqlite3.extension-dir +;sqlite3.extension_dir = + +; SQLite defensive mode flag (only available from SQLite 3.26+) +; When the defensive flag is enabled, language features that allow ordinary +; SQL to deliberately corrupt the database file are disabled. This forbids +; writing directly to the schema, shadow tables (eg. FTS data tables), or +; the sqlite_dbpage virtual table. +; https://www.sqlite.org/c3ref/c_dbconfig_defensive.html +; (for older SQLite versions, this flag has no use) +;sqlite3.defensive = 1 + +[Pcre] +; PCRE library backtracking limit. +; http://php.net/pcre.backtrack-limit +;pcre.backtrack_limit=100000 + +; PCRE library recursion limit. +; Please note that if you set this value to a high number you may consume all +; the available process stack and eventually crash PHP (due to reaching the +; stack size limit imposed by the Operating System). +; http://php.net/pcre.recursion-limit +;pcre.recursion_limit=100000 + +; Enables or disables JIT compilation of patterns. This requires the PCRE +; library to be compiled with JIT support. +;pcre.jit=1 + +[Pdo] +; Whether to pool ODBC connections. Can be one of "strict", "relaxed" or "off" +; http://php.net/pdo-odbc.connection-pooling +;pdo_odbc.connection_pooling=strict + +;pdo_odbc.db2_instance_name + +[Pdo_mysql] +; Default socket name for local MySQL connects. If empty, uses the built-in +; MySQL defaults. +pdo_mysql.default_socket= + +[Phar] +; http://php.net/phar.readonly +;phar.readonly = On + +; http://php.net/phar.require-hash +;phar.require_hash = On + +;phar.cache_list = + +[mail function] +; For Win32 only. +; http://php.net/smtp +SMTP = localhost +; http://php.net/smtp-port +smtp_port = 25 + +; For Win32 only. +; http://php.net/sendmail-from +;sendmail_from = me@example.com + +; For Unix only. You may supply arguments as well (default: "sendmail -t -i"). +; http://php.net/sendmail-path +;sendmail_path = + +; Force the addition of the specified parameters to be passed as extra parameters +; to the sendmail binary. These parameters will always replace the value of +; the 5th parameter to mail(). +;mail.force_extra_parameters = + +; Add X-PHP-Originating-Script: that will include uid of the script followed by the filename +mail.add_x_header = Off + +; The path to a log file that will log all mail() calls. Log entries include +; the full path of the script, line number, To address and headers. +;mail.log = +; Log mail to syslog (Event Log on Windows). +;mail.log = syslog + +[ODBC] +; http://php.net/odbc.default-db +;odbc.default_db = Not yet implemented + +; http://php.net/odbc.default-user +;odbc.default_user = Not yet implemented + +; http://php.net/odbc.default-pw +;odbc.default_pw = Not yet implemented + +; Controls the ODBC cursor model. +; Default: SQL_CURSOR_STATIC (default). +;odbc.default_cursortype + +; Allow or prevent persistent links. +; http://php.net/odbc.allow-persistent +odbc.allow_persistent = On + +; Check that a connection is still valid before reuse. +; http://php.net/odbc.check-persistent +odbc.check_persistent = On + +; Maximum number of persistent links. -1 means no limit. +; http://php.net/odbc.max-persistent +odbc.max_persistent = -1 + +; Maximum number of links (persistent + non-persistent). -1 means no limit. +; http://php.net/odbc.max-links +odbc.max_links = -1 + +; Handling of LONG fields. Returns number of bytes to variables. 0 means +; passthru. +; http://php.net/odbc.defaultlrl +odbc.defaultlrl = 4096 + +; Handling of binary data. 0 means passthru, 1 return as is, 2 convert to char. +; See the documentation on odbc_binmode and odbc_longreadlen for an explanation +; of odbc.defaultlrl and odbc.defaultbinmode +; http://php.net/odbc.defaultbinmode +odbc.defaultbinmode = 1 + +[Interbase] +; Allow or prevent persistent links. +ibase.allow_persistent = 1 + +; Maximum number of persistent links. -1 means no limit. +ibase.max_persistent = -1 + +; Maximum number of links (persistent + non-persistent). -1 means no limit. +ibase.max_links = -1 + +; Default database name for ibase_connect(). +;ibase.default_db = + +; Default username for ibase_connect(). +;ibase.default_user = + +; Default password for ibase_connect(). +;ibase.default_password = + +; Default charset for ibase_connect(). +;ibase.default_charset = + +; Default timestamp format. +ibase.timestampformat = "%Y-%m-%d %H:%M:%S" + +; Default date format. +ibase.dateformat = "%Y-%m-%d" + +; Default time format. +ibase.timeformat = "%H:%M:%S" + +[MySQLi] + +; Maximum number of persistent links. -1 means no limit. +; http://php.net/mysqli.max-persistent +mysqli.max_persistent = -1 + +; Allow accessing, from PHP's perspective, local files with LOAD DATA statements +; http://php.net/mysqli.allow_local_infile +;mysqli.allow_local_infile = On + +; Allow or prevent persistent links. +; http://php.net/mysqli.allow-persistent +mysqli.allow_persistent = On + +; Maximum number of links. -1 means no limit. +; http://php.net/mysqli.max-links +mysqli.max_links = -1 + +; Default port number for mysqli_connect(). If unset, mysqli_connect() will use +; the $MYSQL_TCP_PORT or the mysql-tcp entry in /etc/services or the +; compile-time value defined MYSQL_PORT (in that order). Win32 will only look +; at MYSQL_PORT. +; http://php.net/mysqli.default-port +mysqli.default_port = 3306 + +; Default socket name for local MySQL connects. If empty, uses the built-in +; MySQL defaults. +; http://php.net/mysqli.default-socket +mysqli.default_socket = + +; Default host for mysql_connect() (doesn't apply in safe mode). +; http://php.net/mysqli.default-host +mysqli.default_host = + +; Default user for mysql_connect() (doesn't apply in safe mode). +; http://php.net/mysqli.default-user +mysqli.default_user = + +; Default password for mysqli_connect() (doesn't apply in safe mode). +; Note that this is generally a *bad* idea to store passwords in this file. +; *Any* user with PHP access can run 'echo get_cfg_var("mysqli.default_pw") +; and reveal this password! And of course, any users with read access to this +; file will be able to reveal the password as well. +; http://php.net/mysqli.default-pw +mysqli.default_pw = + +; Allow or prevent reconnect +mysqli.reconnect = Off + +[mysqlnd] +; Enable / Disable collection of general statistics by mysqlnd which can be +; used to tune and monitor MySQL operations. +mysqlnd.collect_statistics = On + +; Enable / Disable collection of memory usage statistics by mysqlnd which can be +; used to tune and monitor MySQL operations. +mysqlnd.collect_memory_statistics = Off + +; Records communication from all extensions using mysqlnd to the specified log +; file. +; http://php.net/mysqlnd.debug +;mysqlnd.debug = + +; Defines which queries will be logged. +;mysqlnd.log_mask = 0 + +; Default size of the mysqlnd memory pool, which is used by result sets. +;mysqlnd.mempool_default_size = 16000 + +; Size of a pre-allocated buffer used when sending commands to MySQL in bytes. +;mysqlnd.net_cmd_buffer_size = 2048 + +; Size of a pre-allocated buffer used for reading data sent by the server in +; bytes. +;mysqlnd.net_read_buffer_size = 32768 + +; Timeout for network requests in seconds. +;mysqlnd.net_read_timeout = 31536000 + +; SHA-256 Authentication Plugin related. File with the MySQL server public RSA +; key. +;mysqlnd.sha256_server_public_key = + +[OCI8] + +; Connection: Enables privileged connections using external +; credentials (OCI_SYSOPER, OCI_SYSDBA) +; http://php.net/oci8.privileged-connect +;oci8.privileged_connect = Off + +; Connection: The maximum number of persistent OCI8 connections per +; process. Using -1 means no limit. +; http://php.net/oci8.max-persistent +;oci8.max_persistent = -1 + +; Connection: The maximum number of seconds a process is allowed to +; maintain an idle persistent connection. Using -1 means idle +; persistent connections will be maintained forever. +; http://php.net/oci8.persistent-timeout +;oci8.persistent_timeout = -1 + +; Connection: The number of seconds that must pass before issuing a +; ping during oci_pconnect() to check the connection validity. When +; set to 0, each oci_pconnect() will cause a ping. Using -1 disables +; pings completely. +; http://php.net/oci8.ping-interval +;oci8.ping_interval = 60 + +; Connection: Set this to a user chosen connection class to be used +; for all pooled server requests with Oracle 11g Database Resident +; Connection Pooling (DRCP). To use DRCP, this value should be set to +; the same string for all web servers running the same application, +; the database pool must be configured, and the connection string must +; specify to use a pooled server. +;oci8.connection_class = + +; High Availability: Using On lets PHP receive Fast Application +; Notification (FAN) events generated when a database node fails. The +; database must also be configured to post FAN events. +;oci8.events = Off + +; Tuning: This option enables statement caching, and specifies how +; many statements to cache. Using 0 disables statement caching. +; http://php.net/oci8.statement-cache-size +;oci8.statement_cache_size = 20 + +; Tuning: Enables statement prefetching and sets the default number of +; rows that will be fetched automatically after statement execution. +; http://php.net/oci8.default-prefetch +;oci8.default_prefetch = 100 + +; Compatibility. Using On means oci_close() will not close +; oci_connect() and oci_new_connect() connections. +; http://php.net/oci8.old-oci-close-semantics +;oci8.old_oci_close_semantics = Off + +[PostgreSQL] +; Allow or prevent persistent links. +; http://php.net/pgsql.allow-persistent +pgsql.allow_persistent = On + +; Detect broken persistent links always with pg_pconnect(). +; Auto reset feature requires a little overheads. +; http://php.net/pgsql.auto-reset-persistent +pgsql.auto_reset_persistent = Off + +; Maximum number of persistent links. -1 means no limit. +; http://php.net/pgsql.max-persistent +pgsql.max_persistent = -1 + +; Maximum number of links (persistent+non persistent). -1 means no limit. +; http://php.net/pgsql.max-links +pgsql.max_links = -1 + +; Ignore PostgreSQL backends Notice message or not. +; Notice message logging require a little overheads. +; http://php.net/pgsql.ignore-notice +pgsql.ignore_notice = 0 + +; Log PostgreSQL backends Notice message or not. +; Unless pgsql.ignore_notice=0, module cannot log notice message. +; http://php.net/pgsql.log-notice +pgsql.log_notice = 0 + +[bcmath] +; Number of decimal digits for all bcmath functions. +; http://php.net/bcmath.scale +bcmath.scale = 0 + +[browscap] +; http://php.net/browscap +;browscap = extra/browscap.ini + +[Session] +; Handler used to store/retrieve data. +; http://php.net/session.save-handler +session.save_handler = files + +; Argument passed to save_handler. In the case of files, this is the path +; where data files are stored. Note: Windows users have to change this +; variable in order to use PHP's session functions. +; +; The path can be defined as: +; +; session.save_path = "N;/path" +; +; where N is an integer. Instead of storing all the session files in +; /path, what this will do is use subdirectories N-levels deep, and +; store the session data in those directories. This is useful if +; your OS has problems with many files in one directory, and is +; a more efficient layout for servers that handle many sessions. +; +; NOTE 1: PHP will not create this directory structure automatically. +; You can use the script in the ext/session dir for that purpose. +; NOTE 2: See the section on garbage collection below if you choose to +; use subdirectories for session storage +; +; The file storage module creates files using mode 600 by default. +; You can change that by using +; +; session.save_path = "N;MODE;/path" +; +; where MODE is the octal representation of the mode. Note that this +; does not overwrite the process's umask. +; http://php.net/session.save-path +;session.save_path = "/tmp" + +; Whether to use strict session mode. +; Strict session mode does not accept an uninitialized session ID, and +; regenerates the session ID if the browser sends an uninitialized session ID. +; Strict mode protects applications from session fixation via a session adoption +; vulnerability. It is disabled by default for maximum compatibility, but +; enabling it is encouraged. +; https://wiki.php.net/rfc/strict_sessions +session.use_strict_mode = 0 + +; Whether to use cookies. +; http://php.net/session.use-cookies +session.use_cookies = 1 + +; http://php.net/session.cookie-secure +;session.cookie_secure = + +; This option forces PHP to fetch and use a cookie for storing and maintaining +; the session id. We encourage this operation as it's very helpful in combating +; session hijacking when not specifying and managing your own session id. It is +; not the be-all and end-all of session hijacking defense, but it's a good start. +; http://php.net/session.use-only-cookies +session.use_only_cookies = 1 + +; Name of the session (used as cookie name). +; http://php.net/session.name +session.name = PHPSESSID + +; Initialize session on request startup. +; http://php.net/session.auto-start +session.auto_start = 0 + +; Lifetime in seconds of cookie or, if 0, until browser is restarted. +; http://php.net/session.cookie-lifetime +session.cookie_lifetime = 0 + +; The path for which the cookie is valid. +; http://php.net/session.cookie-path +session.cookie_path = / + +; The domain for which the cookie is valid. +; http://php.net/session.cookie-domain +session.cookie_domain = + +; Whether or not to add the httpOnly flag to the cookie, which makes it +; inaccessible to browser scripting languages such as JavaScript. +; http://php.net/session.cookie-httponly +session.cookie_httponly = + +; Add SameSite attribute to cookie to help mitigate Cross-Site Request Forgery (CSRF/XSRF) +; Current valid values are "Strict", "Lax" or "None". When using "None", +; make sure to include the quotes, as `none` is interpreted like `false` in ini files. +; https://tools.ietf.org/html/draft-west-first-party-cookies-07 +session.cookie_samesite = + +; Handler used to serialize data. php is the standard serializer of PHP. +; http://php.net/session.serialize-handler +session.serialize_handler = php + +; Defines the probability that the 'garbage collection' process is started on every +; session initialization. The probability is calculated by using gc_probability/gc_divisor, +; e.g. 1/100 means there is a 1% chance that the GC process starts on each request. +; Default Value: 1 +; Development Value: 1 +; Production Value: 1 +; http://php.net/session.gc-probability +session.gc_probability = 1 + +; Defines the probability that the 'garbage collection' process is started on every +; session initialization. The probability is calculated by using gc_probability/gc_divisor, +; e.g. 1/100 means there is a 1% chance that the GC process starts on each request. +; For high volume production servers, using a value of 1000 is a more efficient approach. +; Default Value: 100 +; Development Value: 1000 +; Production Value: 1000 +; http://php.net/session.gc-divisor +session.gc_divisor = 1000 + +; After this number of seconds, stored data will be seen as 'garbage' and +; cleaned up by the garbage collection process. +; http://php.net/session.gc-maxlifetime +session.gc_maxlifetime = 1440 + +; NOTE: If you are using the subdirectory option for storing session files +; (see session.save_path above), then garbage collection does *not* +; happen automatically. You will need to do your own garbage +; collection through a shell script, cron entry, or some other method. +; For example, the following script is the equivalent of setting +; session.gc_maxlifetime to 1440 (1440 seconds = 24 minutes): +; find /path/to/sessions -cmin +24 -type f | xargs rm + +; Check HTTP Referer to invalidate externally stored URLs containing ids. +; HTTP_REFERER has to contain this substring for the session to be +; considered as valid. +; http://php.net/session.referer-check +session.referer_check = + +; Set to {nocache,private,public,} to determine HTTP caching aspects +; or leave this empty to avoid sending anti-caching headers. +; http://php.net/session.cache-limiter +session.cache_limiter = nocache + +; Document expires after n minutes. +; http://php.net/session.cache-expire +session.cache_expire = 180 + +; trans sid support is disabled by default. +; Use of trans sid may risk your users' security. +; Use this option with caution. +; - User may send URL contains active session ID +; to other person via. email/irc/etc. +; - URL that contains active session ID may be stored +; in publicly accessible computer. +; - User may access your site with the same session ID +; always using URL stored in browser's history or bookmarks. +; http://php.net/session.use-trans-sid +session.use_trans_sid = 0 + +; Set session ID character length. This value could be between 22 to 256. +; Shorter length than default is supported only for compatibility reason. +; Users should use 32 or more chars. +; http://php.net/session.sid-length +; Default Value: 32 +; Development Value: 26 +; Production Value: 26 +session.sid_length = 26 + +; The URL rewriter will look for URLs in a defined set of HTML tags. +;
is special; if you include them here, the rewriter will +; add a hidden field with the info which is otherwise appended +; to URLs. tag's action attribute URL will not be modified +; unless it is specified. +; Note that all valid entries require a "=", even if no value follows. +; Default Value: "a=href,area=href,frame=src,form=" +; Development Value: "a=href,area=href,frame=src,form=" +; Production Value: "a=href,area=href,frame=src,form=" +; http://php.net/url-rewriter.tags +session.trans_sid_tags = "a=href,area=href,frame=src,form=" + +; URL rewriter does not rewrite absolute URLs by default. +; To enable rewrites for absolute paths, target hosts must be specified +; at RUNTIME. i.e. use ini_set() +; tags is special. PHP will check action attribute's URL regardless +; of session.trans_sid_tags setting. +; If no host is defined, HTTP_HOST will be used for allowed host. +; Example value: php.net,www.php.net,wiki.php.net +; Use "," for multiple hosts. No spaces are allowed. +; Default Value: "" +; Development Value: "" +; Production Value: "" +;session.trans_sid_hosts="" + +; Define how many bits are stored in each character when converting +; the binary hash data to something readable. +; Possible values: +; 4 (4 bits: 0-9, a-f) +; 5 (5 bits: 0-9, a-v) +; 6 (6 bits: 0-9, a-z, A-Z, "-", ",") +; Default Value: 4 +; Development Value: 5 +; Production Value: 5 +; http://php.net/session.hash-bits-per-character +session.sid_bits_per_character = 5 + +; Enable upload progress tracking in $_SESSION +; Default Value: On +; Development Value: On +; Production Value: On +; http://php.net/session.upload-progress.enabled +;session.upload_progress.enabled = On + +; Cleanup the progress information as soon as all POST data has been read +; (i.e. upload completed). +; Default Value: On +; Development Value: On +; Production Value: On +; http://php.net/session.upload-progress.cleanup +;session.upload_progress.cleanup = On + +; A prefix used for the upload progress key in $_SESSION +; Default Value: "upload_progress_" +; Development Value: "upload_progress_" +; Production Value: "upload_progress_" +; http://php.net/session.upload-progress.prefix +;session.upload_progress.prefix = "upload_progress_" + +; The index name (concatenated with the prefix) in $_SESSION +; containing the upload progress information +; Default Value: "PHP_SESSION_UPLOAD_PROGRESS" +; Development Value: "PHP_SESSION_UPLOAD_PROGRESS" +; Production Value: "PHP_SESSION_UPLOAD_PROGRESS" +; http://php.net/session.upload-progress.name +;session.upload_progress.name = "PHP_SESSION_UPLOAD_PROGRESS" + +; How frequently the upload progress should be updated. +; Given either in percentages (per-file), or in bytes +; Default Value: "1%" +; Development Value: "1%" +; Production Value: "1%" +; http://php.net/session.upload-progress.freq +;session.upload_progress.freq = "1%" + +; The minimum delay between updates, in seconds +; Default Value: 1 +; Development Value: 1 +; Production Value: 1 +; http://php.net/session.upload-progress.min-freq +;session.upload_progress.min_freq = "1" + +; Only write session data when session data is changed. Enabled by default. +; http://php.net/session.lazy-write +;session.lazy_write = On + +[Assertion] +; Switch whether to compile assertions at all (to have no overhead at run-time) +; -1: Do not compile at all +; 0: Jump over assertion at run-time +; 1: Execute assertions +; Changing from or to a negative value is only possible in php.ini! (For turning assertions on and off at run-time, see assert.active, when zend.assertions = 1) +; Default Value: 1 +; Development Value: 1 +; Production Value: -1 +; http://php.net/zend.assertions +zend.assertions = -1 + +; Assert(expr); active by default. +; http://php.net/assert.active +;assert.active = On + +; Throw an AssertionError on failed assertions +; http://php.net/assert.exception +;assert.exception = On + +; Issue a PHP warning for each failed assertion. (Overridden by assert.exception if active) +; http://php.net/assert.warning +;assert.warning = On + +; Don't bail out by default. +; http://php.net/assert.bail +;assert.bail = Off + +; User-function to be called if an assertion fails. +; http://php.net/assert.callback +;assert.callback = 0 + +; Eval the expression with current error_reporting(). Set to true if you want +; error_reporting(0) around the eval(). +; http://php.net/assert.quiet-eval +;assert.quiet_eval = 0 + +[COM] +; path to a file containing GUIDs, IIDs or filenames of files with TypeLibs +; http://php.net/com.typelib-file +;com.typelib_file = + +; allow Distributed-COM calls +; http://php.net/com.allow-dcom +;com.allow_dcom = true + +; autoregister constants of a component's typlib on com_load() +; http://php.net/com.autoregister-typelib +;com.autoregister_typelib = true + +; register constants casesensitive +; http://php.net/com.autoregister-casesensitive +;com.autoregister_casesensitive = false + +; show warnings on duplicate constant registrations +; http://php.net/com.autoregister-verbose +;com.autoregister_verbose = true + +; The default character set code-page to use when passing strings to and from COM objects. +; Default: system ANSI code page +;com.code_page= + +[mbstring] +; language for internal character representation. +; This affects mb_send_mail() and mbstring.detect_order. +; http://php.net/mbstring.language +;mbstring.language = Japanese + +; Use of this INI entry is deprecated, use global internal_encoding instead. +; internal/script encoding. +; Some encoding cannot work as internal encoding. (e.g. SJIS, BIG5, ISO-2022-*) +; If empty, default_charset or internal_encoding or iconv.internal_encoding is used. +; The precedence is: default_charset < internal_encoding < iconv.internal_encoding +;mbstring.internal_encoding = + +; Use of this INI entry is deprecated, use global input_encoding instead. +; http input encoding. +; mbstring.encoding_translation = On is needed to use this setting. +; If empty, default_charset or input_encoding or mbstring.input is used. +; The precedence is: default_charset < input_encoding < mbsting.http_input +; http://php.net/mbstring.http-input +;mbstring.http_input = + +; Use of this INI entry is deprecated, use global output_encoding instead. +; http output encoding. +; mb_output_handler must be registered as output buffer to function. +; If empty, default_charset or output_encoding or mbstring.http_output is used. +; The precedence is: default_charset < output_encoding < mbstring.http_output +; To use an output encoding conversion, mbstring's output handler must be set +; otherwise output encoding conversion cannot be performed. +; http://php.net/mbstring.http-output +;mbstring.http_output = + +; enable automatic encoding translation according to +; mbstring.internal_encoding setting. Input chars are +; converted to internal encoding by setting this to On. +; Note: Do _not_ use automatic encoding translation for +; portable libs/applications. +; http://php.net/mbstring.encoding-translation +;mbstring.encoding_translation = Off + +; automatic encoding detection order. +; "auto" detect order is changed according to mbstring.language +; http://php.net/mbstring.detect-order +;mbstring.detect_order = auto + +; substitute_character used when character cannot be converted +; one from another +; http://php.net/mbstring.substitute-character +;mbstring.substitute_character = none + +; overload(replace) single byte functions by mbstring functions. +; mail(), ereg(), etc are overloaded by mb_send_mail(), mb_ereg(), +; etc. Possible values are 0,1,2,4 or combination of them. +; For example, 7 for overload everything. +; 0: No overload +; 1: Overload mail() function +; 2: Overload str*() functions +; 4: Overload ereg*() functions +; http://php.net/mbstring.func-overload +;mbstring.func_overload = 0 + +; enable strict encoding detection. +; Default: Off +;mbstring.strict_detection = On + +; This directive specifies the regex pattern of content types for which mb_output_handler() +; is activated. +; Default: mbstring.http_output_conv_mimetype=^(text/|application/xhtml\+xml) +;mbstring.http_output_conv_mimetype= + +; This directive specifies maximum stack depth for mbstring regular expressions. It is similar +; to the pcre.recursion_limit for PCRE. +; Default: 100000 +;mbstring.regex_stack_limit=100000 + +[gd] +; Tell the jpeg decode to ignore warnings and try to create +; a gd image. The warning will then be displayed as notices +; disabled by default +; http://php.net/gd.jpeg-ignore-warning +;gd.jpeg_ignore_warning = 1 + +[exif] +; Exif UNICODE user comments are handled as UCS-2BE/UCS-2LE and JIS as JIS. +; With mbstring support this will automatically be converted into the encoding +; given by corresponding encode setting. When empty mbstring.internal_encoding +; is used. For the decode settings you can distinguish between motorola and +; intel byte order. A decode setting cannot be empty. +; http://php.net/exif.encode-unicode +;exif.encode_unicode = ISO-8859-15 + +; http://php.net/exif.decode-unicode-motorola +;exif.decode_unicode_motorola = UCS-2BE + +; http://php.net/exif.decode-unicode-intel +;exif.decode_unicode_intel = UCS-2LE + +; http://php.net/exif.encode-jis +;exif.encode_jis = + +; http://php.net/exif.decode-jis-motorola +;exif.decode_jis_motorola = JIS + +; http://php.net/exif.decode-jis-intel +;exif.decode_jis_intel = JIS + +[Tidy] +; The path to a default tidy configuration file to use when using tidy +; http://php.net/tidy.default-config +;tidy.default_config = /usr/local/lib/php/default.tcfg + +; Should tidy clean and repair output automatically? +; WARNING: Do not use this option if you are generating non-html content +; such as dynamic images +; http://php.net/tidy.clean-output +tidy.clean_output = Off + +[soap] +; Enables or disables WSDL caching feature. +; http://php.net/soap.wsdl-cache-enabled +soap.wsdl_cache_enabled=1 + +; Sets the directory name where SOAP extension will put cache files. +; http://php.net/soap.wsdl-cache-dir +soap.wsdl_cache_dir="/tmp" + +; (time to live) Sets the number of second while cached file will be used +; instead of original one. +; http://php.net/soap.wsdl-cache-ttl +soap.wsdl_cache_ttl=86400 + +; Sets the size of the cache limit. (Max. number of WSDL files to cache) +soap.wsdl_cache_limit = 5 + +[sysvshm] +; A default size of the shared memory segment +;sysvshm.init_mem = 10000 + +[ldap] +; Sets the maximum number of open links or -1 for unlimited. +ldap.max_links = -1 + +[dba] +;dba.default_handler= + +[opcache] +; Determines if Zend OPCache is enabled +;opcache.enable=1 + +; Determines if Zend OPCache is enabled for the CLI version of PHP +;opcache.enable_cli=0 + +; The OPcache shared memory storage size. +;opcache.memory_consumption=128 + +; The amount of memory for interned strings in Mbytes. +;opcache.interned_strings_buffer=8 + +; The maximum number of keys (scripts) in the OPcache hash table. +; Only numbers between 200 and 1000000 are allowed. +;opcache.max_accelerated_files=10000 + +; The maximum percentage of "wasted" memory until a restart is scheduled. +;opcache.max_wasted_percentage=5 + +; When this directive is enabled, the OPcache appends the current working +; directory to the script key, thus eliminating possible collisions between +; files with the same name (basename). Disabling the directive improves +; performance, but may break existing applications. +;opcache.use_cwd=1 + +; When disabled, you must reset the OPcache manually or restart the +; webserver for changes to the filesystem to take effect. +;opcache.validate_timestamps=1 + +; How often (in seconds) to check file timestamps for changes to the shared +; memory storage allocation. ("1" means validate once per second, but only +; once per request. "0" means always validate) +;opcache.revalidate_freq=2 + +; Enables or disables file search in include_path optimization +;opcache.revalidate_path=0 + +; If disabled, all PHPDoc comments are dropped from the code to reduce the +; size of the optimized code. +;opcache.save_comments=1 + +; Allow file existence override (file_exists, etc.) performance feature. +;opcache.enable_file_override=0 + +; A bitmask, where each bit enables or disables the appropriate OPcache +; passes +;opcache.optimization_level=0x7FFFBFFF + +;opcache.dups_fix=0 + +; The location of the OPcache blacklist file (wildcards allowed). +; Each OPcache blacklist file is a text file that holds the names of files +; that should not be accelerated. The file format is to add each filename +; to a new line. The filename may be a full path or just a file prefix +; (i.e., /var/www/x blacklists all the files and directories in /var/www +; that start with 'x'). Line starting with a ; are ignored (comments). +;opcache.blacklist_filename= + +; Allows exclusion of large files from being cached. By default all files +; are cached. +;opcache.max_file_size=0 + +; Check the cache checksum each N requests. +; The default value of "0" means that the checks are disabled. +;opcache.consistency_checks=0 + +; How long to wait (in seconds) for a scheduled restart to begin if the cache +; is not being accessed. +;opcache.force_restart_timeout=180 + +; OPcache error_log file name. Empty string assumes "stderr". +;opcache.error_log= + +; All OPcache errors go to the Web server log. +; By default, only fatal errors (level 0) or errors (level 1) are logged. +; You can also enable warnings (level 2), info messages (level 3) or +; debug messages (level 4). +;opcache.log_verbosity_level=1 + +; Preferred Shared Memory back-end. Leave empty and let the system decide. +;opcache.preferred_memory_model= + +; Protect the shared memory from unexpected writing during script execution. +; Useful for internal debugging only. +;opcache.protect_memory=0 + +; Allows calling OPcache API functions only from PHP scripts which path is +; started from specified string. The default "" means no restriction +;opcache.restrict_api= + +; Mapping base of shared memory segments (for Windows only). All the PHP +; processes have to map shared memory into the same address space. This +; directive allows to manually fix the "Unable to reattach to base address" +; errors. +;opcache.mmap_base= + +; Enables and sets the second level cache directory. +; It should improve performance when SHM memory is full, at server restart or +; SHM reset. The default "" disables file based caching. +;opcache.file_cache= + +; Enables or disables opcode caching in shared memory. +;opcache.file_cache_only=0 + +; Enables or disables checksum validation when script loaded from file cache. +;opcache.file_cache_consistency_checks=1 + +; Implies opcache.file_cache_only=1 for a certain process that failed to +; reattach to the shared memory (for Windows only). Explicitly enabled file +; cache is required. +;opcache.file_cache_fallback=1 + +; Enables or disables copying of PHP code (text segment) into HUGE PAGES. +; This should improve performance, but requires appropriate OS configuration. +;opcache.huge_code_pages=1 + +; Validate cached file permissions. +;opcache.validate_permission=0 + +; Prevent name collisions in chroot'ed environment. +;opcache.validate_root=0 + +; If specified, it produces opcode dumps for debugging different stages of +; optimizations. +;opcache.opt_debug_level=0 + +[curl] +; A default value for the CURLOPT_CAINFO option. This is required to be an +; absolute path. +;curl.cainfo = + +[openssl] +; The location of a Certificate Authority (CA) file on the local filesystem +; to use when verifying the identity of SSL/TLS peers. Most users should +; not specify a value for this directive as PHP will attempt to use the +; OS-managed cert stores in its absence. If specified, this value may still +; be overridden on a per-stream basis via the "cafile" SSL stream context +; option. +;openssl.cafile= + +; If openssl.cafile is not specified or if the CA file is not found, the +; directory pointed to by openssl.capath is searched for a suitable +; certificate. This value must be a correctly hashed certificate directory. +; Most users should not specify a value for this directive as PHP will +; attempt to use the OS-managed cert stores in its absence. If specified, +; this value may still be overridden on a per-stream basis via the "capath" +; SSL stream context option. +;openssl.capath= + +; Local Variables: +; tab-width: 4 +; End: diff --git a/nginx/rootfs/etc/confd/templates/www.conf.tmpl b/nginx/rootfs/etc/confd/templates/www.conf.tmpl new file mode 100644 index 00000000..b5069c3d --- /dev/null +++ b/nginx/rootfs/etc/confd/templates/www.conf.tmpl @@ -0,0 +1,438 @@ +; Start a new pool named 'www'. +; the variable $pool can be used in any directive and will be replaced by the +; pool name ('www' here) +[www] + +; Per pool prefix +; It only applies on the following directives: +; - 'access.log' +; - 'slowlog' +; - 'listen' (unixsocket) +; - 'chroot' +; - 'chdir' +; - 'php_values' +; - 'php_admin_values' +; When not set, the global prefix (or /usr) applies instead. +; Note: This directive can also be relative to the global prefix. +; Default Value: none +;prefix = /path/to/pools/$pool + +; Unix user/group of processes +; Note: The user is mandatory. If the group is not set, the default user's group +; will be used. +user = nginx +group = nginx + +; The address on which to accept FastCGI requests. +; Valid syntaxes are: +; 'ip.add.re.ss:port' - to listen on a TCP socket to a specific IPv4 address on +; a specific port; +; '[ip:6:addr:ess]:port' - to listen on a TCP socket to a specific IPv6 address on +; a specific port; +; 'port' - to listen on a TCP socket to all addresses +; (IPv6 and IPv4-mapped) on a specific port; +; '/path/to/unix/socket' - to listen on a unix socket. +; Note: This value is mandatory. +listen = /var/run/php-fpm7/php-fpm7.sock + +; Set listen(2) backlog. +; Default Value: 511 (-1 on FreeBSD and OpenBSD) +;listen.backlog = 511 + +; Set permissions for unix socket, if one is used. In Linux, read/write +; permissions must be set in order to allow connections from a web server. Many +; BSD-derived systems allow connections regardless of permissions. +; Default Values: user and group are set as the running user +; mode is set to 0660 +listen.owner = nginx +listen.group = nginx +listen.mode = 0660 +; When POSIX Access Control Lists are supported you can set them using +; these options, value is a comma separated list of user/group names. +; When set, listen.owner and listen.group are ignored +;listen.acl_users = +;listen.acl_groups = + +; List of addresses (IPv4/IPv6) of FastCGI clients which are allowed to connect. +; Equivalent to the FCGI_WEB_SERVER_ADDRS environment variable in the original +; PHP FCGI (5.2.2+). Makes sense only with a tcp listening socket. Each address +; must be separated by a comma. If this value is left blank, connections will be +; accepted from any ip address. +; Default Value: any +;listen.allowed_clients = 127.0.0.1 + +; Specify the nice(2) priority to apply to the pool processes (only if set) +; The value can vary from -19 (highest priority) to 20 (lower priority) +; Note: - It will only work if the FPM master process is launched as root +; - The pool processes will inherit the master process priority +; unless it specified otherwise +; Default Value: no set +; process.priority = -19 + +; Set the process dumpable flag (PR_SET_DUMPABLE prctl) even if the process user +; or group is differrent than the master process user. It allows to create process +; core dump and ptrace the process for the pool user. +; Default Value: no +; process.dumpable = yes + +; Choose how the process manager will control the number of child processes. +; Possible Values: +; static - a fixed number (pm.max_children) of child processes; +; dynamic - the number of child processes are set dynamically based on the +; following directives. With this process management, there will be +; always at least 1 children. +; pm.max_children - the maximum number of children that can +; be alive at the same time. +; pm.start_servers - the number of children created on startup. +; pm.min_spare_servers - the minimum number of children in 'idle' +; state (waiting to process). If the number +; of 'idle' processes is less than this +; number then some children will be created. +; pm.max_spare_servers - the maximum number of children in 'idle' +; state (waiting to process). If the number +; of 'idle' processes is greater than this +; number then some children will be killed. +; ondemand - no children are created at startup. Children will be forked when +; new requests will connect. The following parameter are used: +; pm.max_children - the maximum number of children that +; can be alive at the same time. +; pm.process_idle_timeout - The number of seconds after which +; an idle process will be killed. +; Note: This value is mandatory. +pm = dynamic + +; The number of child processes to be created when pm is set to 'static' and the +; maximum number of child processes when pm is set to 'dynamic' or 'ondemand'. +; This value sets the limit on the number of simultaneous requests that will be +; served. Equivalent to the ApacheMaxClients directive with mpm_prefork. +; Equivalent to the PHP_FCGI_CHILDREN environment variable in the original PHP +; CGI. The below defaults are based on a server without much resources. Don't +; forget to tweak pm.* to fit your needs. +; Note: Used when pm is set to 'static', 'dynamic' or 'ondemand' +; Note: This value is mandatory. +pm.max_children = 5 + +; The number of child processes created on startup. +; Note: Used only when pm is set to 'dynamic' +; Default Value: min_spare_servers + (max_spare_servers - min_spare_servers) / 2 +pm.start_servers = 2 + +; The desired minimum number of idle server processes. +; Note: Used only when pm is set to 'dynamic' +; Note: Mandatory when pm is set to 'dynamic' +pm.min_spare_servers = 1 + +; The desired maximum number of idle server processes. +; Note: Used only when pm is set to 'dynamic' +; Note: Mandatory when pm is set to 'dynamic' +pm.max_spare_servers = 3 + +; The number of seconds after which an idle process will be killed. +; Note: Used only when pm is set to 'ondemand' +; Default Value: 10s +;pm.process_idle_timeout = 10s; + +; The number of requests each child process should execute before respawning. +; This can be useful to work around memory leaks in 3rd party libraries. For +; endless request processing specify '0'. Equivalent to PHP_FCGI_MAX_REQUESTS. +; Default Value: 0 +;pm.max_requests = 500 + +; The URI to view the FPM status page. If this value is not set, no URI will be +; recognized as a status page. It shows the following informations: +; pool - the name of the pool; +; process manager - static, dynamic or ondemand; +; start time - the date and time FPM has started; +; start since - number of seconds since FPM has started; +; accepted conn - the number of request accepted by the pool; +; listen queue - the number of request in the queue of pending +; connections (see backlog in listen(2)); +; max listen queue - the maximum number of requests in the queue +; of pending connections since FPM has started; +; listen queue len - the size of the socket queue of pending connections; +; idle processes - the number of idle processes; +; active processes - the number of active processes; +; total processes - the number of idle + active processes; +; max active processes - the maximum number of active processes since FPM +; has started; +; max children reached - number of times, the process limit has been reached, +; when pm tries to start more children (works only for +; pm 'dynamic' and 'ondemand'); +; Value are updated in real time. +; Example output: +; pool: www +; process manager: static +; start time: 01/Jul/2011:17:53:49 +0200 +; start since: 62636 +; accepted conn: 190460 +; listen queue: 0 +; max listen queue: 1 +; listen queue len: 42 +; idle processes: 4 +; active processes: 11 +; total processes: 15 +; max active processes: 12 +; max children reached: 0 +; +; By default the status page output is formatted as text/plain. Passing either +; 'html', 'xml' or 'json' in the query string will return the corresponding +; output syntax. Example: +; http://www.foo.bar/status +; http://www.foo.bar/status?json +; http://www.foo.bar/status?html +; http://www.foo.bar/status?xml +; +; By default the status page only outputs short status. Passing 'full' in the +; query string will also return status for each pool process. +; Example: +; http://www.foo.bar/status?full +; http://www.foo.bar/status?json&full +; http://www.foo.bar/status?html&full +; http://www.foo.bar/status?xml&full +; The Full status returns for each process: +; pid - the PID of the process; +; state - the state of the process (Idle, Running, ...); +; start time - the date and time the process has started; +; start since - the number of seconds since the process has started; +; requests - the number of requests the process has served; +; request duration - the duration in µs of the requests; +; request method - the request method (GET, POST, ...); +; request URI - the request URI with the query string; +; content length - the content length of the request (only with POST); +; user - the user (PHP_AUTH_USER) (or '-' if not set); +; script - the main script called (or '-' if not set); +; last request cpu - the %cpu the last request consumed +; it's always 0 if the process is not in Idle state +; because CPU calculation is done when the request +; processing has terminated; +; last request memory - the max amount of memory the last request consumed +; it's always 0 if the process is not in Idle state +; because memory calculation is done when the request +; processing has terminated; +; If the process is in Idle state, then informations are related to the +; last request the process has served. Otherwise informations are related to +; the current request being served. +; Example output: +; ************************ +; pid: 31330 +; state: Running +; start time: 01/Jul/2011:17:53:49 +0200 +; start since: 63087 +; requests: 12808 +; request duration: 1250261 +; request method: GET +; request URI: /test_mem.php?N=10000 +; content length: 0 +; user: - +; script: /home/fat/web/docs/php/test_mem.php +; last request cpu: 0.00 +; last request memory: 0 +; +; Note: There is a real-time FPM status monitoring sample web page available +; It's available in: /usr/share/php7/fpm/status.html +; +; Note: The value must start with a leading slash (/). The value can be +; anything, but it may not be a good idea to use the .php extension or it +; may conflict with a real PHP file. +; Default Value: not set +;pm.status_path = /status + +; The ping URI to call the monitoring page of FPM. If this value is not set, no +; URI will be recognized as a ping page. This could be used to test from outside +; that FPM is alive and responding, or to +; - create a graph of FPM availability (rrd or such); +; - remove a server from a group if it is not responding (load balancing); +; - trigger alerts for the operating team (24/7). +; Note: The value must start with a leading slash (/). The value can be +; anything, but it may not be a good idea to use the .php extension or it +; may conflict with a real PHP file. +; Default Value: not set +;ping.path = /ping + +; This directive may be used to customize the response of a ping request. The +; response is formatted as text/plain with a 200 response code. +; Default Value: pong +;ping.response = pong + +; The access log file +; Default: not set +;access.log = log/php7/$pool.access.log + +; The access log format. +; The following syntax is allowed +; %%: the '%' character +; %C: %CPU used by the request +; it can accept the following format: +; - %{user}C for user CPU only +; - %{system}C for system CPU only +; - %{total}C for user + system CPU (default) +; %d: time taken to serve the request +; it can accept the following format: +; - %{seconds}d (default) +; - %{miliseconds}d +; - %{mili}d +; - %{microseconds}d +; - %{micro}d +; %e: an environment variable (same as $_ENV or $_SERVER) +; it must be associated with embraces to specify the name of the env +; variable. Some exemples: +; - server specifics like: %{REQUEST_METHOD}e or %{SERVER_PROTOCOL}e +; - HTTP headers like: %{HTTP_HOST}e or %{HTTP_USER_AGENT}e +; %f: script filename +; %l: content-length of the request (for POST request only) +; %m: request method +; %M: peak of memory allocated by PHP +; it can accept the following format: +; - %{bytes}M (default) +; - %{kilobytes}M +; - %{kilo}M +; - %{megabytes}M +; - %{mega}M +; %n: pool name +; %o: output header +; it must be associated with embraces to specify the name of the header: +; - %{Content-Type}o +; - %{X-Powered-By}o +; - %{Transfert-Encoding}o +; - .... +; %p: PID of the child that serviced the request +; %P: PID of the parent of the child that serviced the request +; %q: the query string +; %Q: the '?' character if query string exists +; %r: the request URI (without the query string, see %q and %Q) +; %R: remote IP address +; %s: status (response code) +; %t: server time the request was received +; it can accept a strftime(3) format: +; %d/%b/%Y:%H:%M:%S %z (default) +; The strftime(3) format must be encapsuled in a %{}t tag +; e.g. for a ISO8601 formatted timestring, use: %{%Y-%m-%dT%H:%M:%S%z}t +; %T: time the log has been written (the request has finished) +; it can accept a strftime(3) format: +; %d/%b/%Y:%H:%M:%S %z (default) +; The strftime(3) format must be encapsuled in a %{}t tag +; e.g. for a ISO8601 formatted timestring, use: %{%Y-%m-%dT%H:%M:%S%z}t +; %u: remote user +; +; Default: "%R - %u %t \"%m %r\" %s" +;access.format = "%R - %u %t \"%m %r%Q%q\" %s %f %{mili}d %{kilo}M %C%%" + +; The log file for slow requests +; Default Value: not set +; Note: slowlog is mandatory if request_slowlog_timeout is set +;slowlog = log/php7/$pool.slow.log + +; The timeout for serving a single request after which a PHP backtrace will be +; dumped to the 'slowlog' file. A value of '0s' means 'off'. +; Available units: s(econds)(default), m(inutes), h(ours), or d(ays) +; Default Value: 0 +;request_slowlog_timeout = 0 + +; Depth of slow log stack trace. +; Default Value: 20 +;request_slowlog_trace_depth = 20 + +; The timeout for serving a single request after which the worker process will +; be killed. This option should be used when the 'max_execution_time' ini option +; does not stop script execution for some reason. A value of '0' means 'off'. +; Available units: s(econds)(default), m(inutes), h(ours), or d(ays) +; Default Value: 0 +;request_terminate_timeout = 0 + +; The timeout set by 'request_terminate_timeout' ini option is not engaged after +; application calls 'fastcgi_finish_request' or when application has finished and +; shutdown functions are being called (registered via register_shutdown_function). +; This option will enable timeout limit to be applied unconditionally +; even in such cases. +; Default Value: no +;request_terminate_timeout_track_finished = no + +; Set open file descriptor rlimit. +; Default Value: system defined value +;rlimit_files = 1024 + +; Set max core size rlimit. +; Possible Values: 'unlimited' or an integer greater or equal to 0 +; Default Value: system defined value +;rlimit_core = 0 + +; Chroot to this directory at the start. This value must be defined as an +; absolute path. When this value is not set, chroot is not used. +; Note: you can prefix with '$prefix' to chroot to the pool prefix or one +; of its subdirectories. If the pool prefix is not set, the global prefix +; will be used instead. +; Note: chrooting is a great security feature and should be used whenever +; possible. However, all PHP paths will be relative to the chroot +; (error_log, sessions.save_path, ...). +; Default Value: not set +;chroot = + +; Chdir to this directory at the start. +; Note: relative path can be used. +; Default Value: current directory or / when chroot +;chdir = /var/www + +; Redirect worker stdout and stderr into main error log. If not set, stdout and +; stderr will be redirected to /dev/null according to FastCGI specs. +; Note: on highloaded environement, this can cause some delay in the page +; process time (several ms). +; Default Value: no +;catch_workers_output = yes + +; Decorate worker output with prefix and suffix containing information about +; the child that writes to the log and if stdout or stderr is used as well as +; log level and time. This options is used only if catch_workers_output is yes. +; Settings to "no" will output data as written to the stdout or stderr. +; Default value: yes +;decorate_workers_output = no + +; Clear environment in FPM workers +; Prevents arbitrary environment variables from reaching FPM worker processes +; by clearing the environment in workers before env vars specified in this +; pool configuration are added. +; Setting to "no" will make all environment variables available to PHP code +; via getenv(), $_ENV and $_SERVER. +; Default Value: yes +;clear_env = no + +; Limits the extensions of the main script FPM will allow to parse. This can +; prevent configuration mistakes on the web server side. You should only limit +; FPM to .php extensions to prevent malicious users to use other extensions to +; execute php code. +; Note: set an empty value to allow all extensions. +; Default Value: .php +;security.limit_extensions = .php .php3 .php4 .php5 .php7 + +; Pass environment variables like LD_LIBRARY_PATH. All $VARIABLEs are taken from +; the current environment. +; Default Value: clean env +;env[HOSTNAME] = $HOSTNAME +;env[PATH] = /usr/local/bin:/usr/bin:/bin +;env[TMP] = /tmp +;env[TMPDIR] = /tmp +;env[TEMP] = /tmp + +; Additional php.ini defines, specific to this pool of workers. These settings +; overwrite the values previously defined in the php.ini. The directives are the +; same as the PHP SAPI: +; php_value/php_flag - you can set classic ini defines which can +; be overwritten from PHP call 'ini_set'. +; php_admin_value/php_admin_flag - these directives won't be overwritten by +; PHP call 'ini_set' +; For php_*flag, valid values are on, off, 1, 0, true, false, yes or no. + +; Defining 'extension' will load the corresponding shared extension from +; extension_dir. Defining 'disable_functions' or 'disable_classes' will not +; overwrite previously defined php.ini values, but will append the new value +; instead. + +; Note: path INI options can be relative and will be expanded with the prefix +; (pool, global or /usr) + +; Default Value: nothing is defined by default except the values in php.ini and +; specified at startup with the -d argument +;php_admin_value[sendmail_path] = /usr/sbin/sendmail -t -i -f www@my.domain.com +;php_flag[display_errors] = off +;php_admin_value[error_log] = /var/log/php7/$pool.error.log +;php_admin_flag[log_errors] = on +;php_admin_value[memory_limit] = 32M diff --git a/nginx/rootfs/etc/cont-init.d/02-fpm-install.sh b/nginx/rootfs/etc/cont-init.d/02-fpm-install.sh new file mode 100644 index 00000000..78ac88dd --- /dev/null +++ b/nginx/rootfs/etc/cont-init.d/02-fpm-install.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +mkdir /run/php-fpm7 &> /dev/null || true diff --git a/nginx/rootfs/etc/cont-init.d/02-ngnix-install.sh b/nginx/rootfs/etc/cont-init.d/02-ngnix-install.sh new file mode 100755 index 00000000..c7d12cc6 --- /dev/null +++ b/nginx/rootfs/etc/cont-init.d/02-ngnix-install.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +mkdir /run/nginx &> /dev/null || true diff --git a/nginx/rootfs/etc/nginx/modules/daemon.conf b/nginx/rootfs/etc/nginx/modules/daemon.conf new file mode 100644 index 00000000..ef1f9c1c --- /dev/null +++ b/nginx/rootfs/etc/nginx/modules/daemon.conf @@ -0,0 +1 @@ +daemon off; diff --git a/nginx/rootfs/etc/services.d/fpm/finish b/nginx/rootfs/etc/services.d/fpm/finish new file mode 100644 index 00000000..9030da41 --- /dev/null +++ b/nginx/rootfs/etc/services.d/fpm/finish @@ -0,0 +1,4 @@ +#!/usr/bin/execlineb -S1 +# -*- mode: sh -*- +# vi: set ft=sh: +s6-svscanctl -t /var/run/s6/services diff --git a/nginx/rootfs/etc/services.d/fpm/run b/nginx/rootfs/etc/services.d/fpm/run new file mode 100644 index 00000000..3d5b066c --- /dev/null +++ b/nginx/rootfs/etc/services.d/fpm/run @@ -0,0 +1,4 @@ +#!/usr/bin/execlineb -P +# -*- mode: sh -*- +# vi: set ft=sh: +/usr/sbin/php-fpm7 diff --git a/nginx/rootfs/etc/services.d/nginx/finish b/nginx/rootfs/etc/services.d/nginx/finish new file mode 100644 index 00000000..9030da41 --- /dev/null +++ b/nginx/rootfs/etc/services.d/nginx/finish @@ -0,0 +1,4 @@ +#!/usr/bin/execlineb -S1 +# -*- mode: sh -*- +# vi: set ft=sh: +s6-svscanctl -t /var/run/s6/services diff --git a/nginx/rootfs/etc/services.d/nginx/run b/nginx/rootfs/etc/services.d/nginx/run new file mode 100644 index 00000000..7503678e --- /dev/null +++ b/nginx/rootfs/etc/services.d/nginx/run @@ -0,0 +1,4 @@ +#!/usr/bin/execlineb -P +# -*- mode: sh -*- +# vi: set ft=sh: +/usr/sbin/nginx diff --git a/recast/.dockerignore b/recast/.dockerignore new file mode 100644 index 00000000..b43bf86b --- /dev/null +++ b/recast/.dockerignore @@ -0,0 +1 @@ +README.md diff --git a/recast/Dockerfile b/recast/Dockerfile new file mode 100644 index 00000000..27e27481 --- /dev/null +++ b/recast/Dockerfile @@ -0,0 +1,13 @@ +# syntax=docker/dockerfile:experimental +FROM local/crayfish:latest + +RUN --mount=type=cache,target=/root/.composer/cache \ + composer install -d /var/www/crayfish/Recast && \ + ln -s /var/www/crayfish/Recast/src /var/www/html && \ + cleanup.sh + +COPY /rootfs / + +RUN chown -R nginx:nginx /var/www + +WORKDIR /var/www/crayfish/Recast/ diff --git a/recast/README.md b/recast/README.md new file mode 100644 index 00000000..d91a2b94 --- /dev/null +++ b/recast/README.md @@ -0,0 +1,26 @@ +# Recast + +Docker image for [Recast]. + +## Dependencies + +Requires `islandora/crayfish` docker image to build. Please refer to the +[Crayfish Image README](../crayfish/README.md) for additional information including +additional settings, volumes, ports, etc. + +## Settings + +| Environment Variable | Etcd Key | Default | Description | +| :------------------- | :----------------- | :---------------------- | :------------------------------------- | +| RECAST_DRUPAL_URL | /recast/drupal/url | drupal:80 | Drupal URL | +| RECAST_FCREPO_URL | /recast/fcrepo/url | fcrepo/fcrepo/rest | Fcrepo Rest API URL | +| RECAST_GEMINI_URL | /recast/gemini/url | gemini:8000 | Gemini URL | +| RECAST_LOG_LEVEL | /recast/log/level | WARNING | The log level for Recast micro-service | + +## Logs + +| Path | Description | +| :---------------------------- | :---------- | +| /var/log/islandora/recast.log | Recast Log | + +[Recast]: https://github.com/Islandora/Crayfish/tree/master/Recast diff --git a/recast/rootfs/etc/confd/conf.d/config.yaml.toml b/recast/rootfs/etc/confd/conf.d/config.yaml.toml new file mode 100644 index 00000000..7ca1f581 --- /dev/null +++ b/recast/rootfs/etc/confd/conf.d/config.yaml.toml @@ -0,0 +1,7 @@ +[template] +src = "config.yaml.tmpl" +dest = "/var/www/crayfish/Recast/cfg/config.yaml" +uid = 100 +gid = 101 +mode = "0644" +keys = [ "/log/level", "/fcrepo", "/drupal", "/gemini" ] diff --git a/recast/rootfs/etc/confd/confd.toml b/recast/rootfs/etc/confd/confd.toml new file mode 100644 index 00000000..e5403c82 --- /dev/null +++ b/recast/rootfs/etc/confd/confd.toml @@ -0,0 +1,6 @@ +backend = "env" +confdir = "/etc/confd" +log-level = "debug" +interval = 600 +noop = false +prefix = "/recast" diff --git a/recast/rootfs/etc/confd/templates/config.yaml.tmpl b/recast/rootfs/etc/confd/templates/config.yaml.tmpl new file mode 100644 index 00000000..04b958af --- /dev/null +++ b/recast/rootfs/etc/confd/templates/config.yaml.tmpl @@ -0,0 +1,37 @@ +--- + +fedora_base_url: {{ getv "/fcrepo/url" "fcrepo/fcrepo/rest" }} +# if drupal_base_url contains a path, be sure to include trailing slash +# or relative paths will not resolve correctly. +drupal_base_url: {{ getv "/drupal/url" "drupal:80" }} +gemini_base_url: {{ getv "/gemini/url" "gemini:8000" }} + +debug: false + +log: + # Valid log levels are: + # DEBUG, INFO, NOTICE, WARNING, ERROR, CRITICAL, ALERT, EMERGENCY, NONE + # log level none won't open logfile + level: {{ getv "/log/level" "DEBUG" }} + file: /var/log/islandora/recast.log + +syn: + # toggles JWT security for service + enable: false + # Path to the syn config file for authentication. + # example can be found here: + # https://github.com/Islandora/Syn/blob/master/conf/syn-settings.example.xml + config: /var/www/crayfish/syn-settings.xml + +# Add namespace prefixes used by Fedora for recast service +# Must be inside an array to maintain the internal associative array. +namespaces: +- + acl: "http://www.w3.org/ns/auth/acl#" + fedora: "http://fedora.info/definitions/v4/repository#" + ldp: "http://www.w3.org/ns/ldp#" + memento: "http://mementoweb.org/ns#" + pcdm: "http://pcdm.org/models#" + pcdmuse: "http://pcdm.org/use#" + webac: "http://fedora.info/definitions/v4/webac#" + vcard: "http://www.w3.org/2006/vcard/ns#" diff --git a/sandbox/.dockerignore b/sandbox/.dockerignore new file mode 100644 index 00000000..b43bf86b --- /dev/null +++ b/sandbox/.dockerignore @@ -0,0 +1 @@ +README.md diff --git a/sandbox/Dockerfile b/sandbox/Dockerfile new file mode 100644 index 00000000..92651595 --- /dev/null +++ b/sandbox/Dockerfile @@ -0,0 +1,52 @@ +# syntax=docker/dockerfile:experimental +FROM local/drupal:latest + +# Islandora based Drupal install. +RUN --mount=type=cache,target=/root/.composer/cache \ + --mount=id=downloads,type=cache,target=/opt/downloads \ + php -d memory_limit=-1 /usr/bin/composer create-project islandora/drupal-project:8.8.1 \ + --prefer-dist \ + --no-interaction \ + --stability stable \ + --no-dev \ + --no-install \ + /var/www/drupal \ + && \ + php -d memory_limit=-1 /usr/bin/composer require --update-no-dev -- drush/drush:^9.7.1 && \ + wget -N -P /opt/downloads https://github.com/drush-ops/drush-launcher/releases/latest/download/drush.phar && \ + cp /opt/downloads/drush.phar /usr/local/bin/drush && \ + chmod a+x /usr/local/bin/drush && \ + mkdir /var/www/drupal/config && \ + mkdir -p /var/www/drupal/web/libraries && \ + chown -R nginx:nginx /var/www && \ + php -d memory_limit=-1 /usr/bin/composer require --update-no-dev -- \ + zaporylie/composer-drupal-optimizations:^1.0 \ + drupal/console:~1.0 \ + drupal/devel:^2.0 \ + drush/drush:^9.0 \ + drupal/rdfui:^1.0-beta1 \ + drupal/restui:^1.16 \ + drupal/search_api_solr:^3.8 \ + drupal/facets:^1.3 \ + drupal/content_browser:^1.0@alpha \ + drupal/matomo:^1.7 \ + drupal/pdf:1.x-dev \ + drupal/admin_toolbar:^2.0 \ + drupal/rest_oai_pmh:^1.0 \ + drupal/transliterate_filenames:^1.3 \ + islandora/carapace:dev-8.x-3.x \ + islandora/islandora_defaults:dev-8.x-1.x \ + islandora-rdm/islandora_fits:dev-master && \ + MASONRY_VERSION=3.3.2 && \ + wget -N -P /opt/downloads https://github.com/desandro/masonry/archive/v${MASONRY_VERSION}.zip && \ + unzip "/opt/downloads/v${MASONRY_VERSION}.zip" -d /var/www/drupal/web/libraries && \ + mv /var/www/drupal/web/libraries/masonry-${MASONRY_VERSION} /var/www/drupal/web/libraries/masonry && \ + PDFJS_VERSION=2.0.943 && \ + wget -N -P /opt/downloads https://github.com/mozilla/pdf.js/releases/download/v${PDFJS_VERSION}/pdfjs-${PDFJS_VERSION}-dist.zip && \ + mkdir -p /var/www/drupal/web/libraries/pdfjs.js && \ + unzip "/opt/downloads/pdfjs-${PDFJS_VERSION}-dist.zip" -d /var/www/drupal/web/libraries/pdfjs.js && \ + cleanup.sh + +VOLUME [ "/opt/keys/claw", "/var/www/drupal/config", "/var/www/drupal/web/sites" ] + +COPY rootfs / diff --git a/sandbox/README.md b/sandbox/README.md new file mode 100644 index 00000000..ae9e1142 --- /dev/null +++ b/sandbox/README.md @@ -0,0 +1,11 @@ +# Sandbox + +Islandora Sandbox image meant for demoing a functioning system. If you want to +build your own Islandora site site the composer folder for a template on how to +do that. + +## Dependencies + +Requires `islandora/drupal` docker image to build. Please refer to the +[Drupal Image README](../drupal/README.md) for additional information including +additional settings, volumes, ports, etc. diff --git a/sandbox/rootfs/etc/confd/conf.d/blazegraph.properties.toml b/sandbox/rootfs/etc/confd/conf.d/blazegraph.properties.toml new file mode 100644 index 00000000..fcebdff1 --- /dev/null +++ b/sandbox/rootfs/etc/confd/conf.d/blazegraph.properties.toml @@ -0,0 +1,7 @@ +[template] +src = "blazegraph.properties.tmpl" +dest = "/var/run/islandora/blazegraph.properties" +uid = 0 +gid = 0 +mode = "0700" +keys = [ "/" ] diff --git a/sandbox/rootfs/etc/confd/conf.d/inference.nt.toml b/sandbox/rootfs/etc/confd/conf.d/inference.nt.toml new file mode 100644 index 00000000..966edce8 --- /dev/null +++ b/sandbox/rootfs/etc/confd/conf.d/inference.nt.toml @@ -0,0 +1,7 @@ +[template] +src = "inference.nt.tmpl" +dest = "/var/run/islandora/inference.nt" +uid = 0 +gid = 0 +mode = "0700" +keys = [ "/" ] diff --git a/sandbox/rootfs/etc/confd/conf.d/sandbox-setup.sh.toml b/sandbox/rootfs/etc/confd/conf.d/sandbox-setup.sh.toml new file mode 100644 index 00000000..f677eb46 --- /dev/null +++ b/sandbox/rootfs/etc/confd/conf.d/sandbox-setup.sh.toml @@ -0,0 +1,7 @@ +[template] +src = "sandbox-setup.sh.tmpl" +dest = "/var/run/islandora/sandbox-setup.sh" +uid = 0 +gid = 0 +mode = "0700" +keys = [ "/" ] diff --git a/sandbox/rootfs/etc/confd/confd.toml b/sandbox/rootfs/etc/confd/confd.toml new file mode 100644 index 00000000..925d1a48 --- /dev/null +++ b/sandbox/rootfs/etc/confd/confd.toml @@ -0,0 +1,6 @@ +backend = "env" +confdir = "/etc/confd" +log-level = "debug" +interval = 600 +noop = false +prefix = "/drupal" diff --git a/sandbox/rootfs/etc/confd/templates/blazegraph.properties.tmpl b/sandbox/rootfs/etc/confd/templates/blazegraph.properties.tmpl new file mode 100644 index 00000000..c8a6bba3 --- /dev/null +++ b/sandbox/rootfs/etc/confd/templates/blazegraph.properties.tmpl @@ -0,0 +1,12 @@ +com.bigdata.rdf.store.AbstractTripleStore.textIndex=false +com.bigdata.rdf.store.AbstractTripleStore.axiomsClass=com.bigdata.rdf.axioms.OwlAxioms +com.bigdata.rdf.sail.isolatableIndices=false +com.bigdata.rdf.store.AbstractTripleStore.justify=true +com.bigdata.rdf.sail.truthMaintenance=true +com.bigdata.rdf.sail.namespace=islandora +com.bigdata.rdf.store.AbstractTripleStore.quads=false +com.bigdata.namespace.islandora.lex.com.bigdata.btree.BTree.branchingFactor=400 +com.bigdata.journal.Journal.groupCommit=false +com.bigdata.namespace.islandora.spo.com.bigdata.btree.BTree.branchingFactor=1024 +com.bigdata.rdf.store.AbstractTripleStore.geoSpatial=false +com.bigdata.rdf.store.AbstractTripleStore.statementIdentifiers=false diff --git a/sandbox/rootfs/etc/confd/templates/inference.nt.tmpl b/sandbox/rootfs/etc/confd/templates/inference.nt.tmpl new file mode 100644 index 00000000..c2629934 --- /dev/null +++ b/sandbox/rootfs/etc/confd/templates/inference.nt.tmpl @@ -0,0 +1,2 @@ + . + . \ No newline at end of file diff --git a/sandbox/rootfs/etc/confd/templates/sandbox-setup.sh.tmpl b/sandbox/rootfs/etc/confd/templates/sandbox-setup.sh.tmpl new file mode 100644 index 00000000..cee64113 --- /dev/null +++ b/sandbox/rootfs/etc/confd/templates/sandbox-setup.sh.tmpl @@ -0,0 +1,178 @@ +#!/usr/bin/with-contenv bash +set -ex + +function drush { + s6-setuidgid nginx php -d memory_limit=-1 /usr/local/bin/drush ${@} +} + +function main { + local broker_host="{{ getv "/broker/host" "activemq" }}" + local broker_port="{{ getv "/broker/port" "61613" }}" + local broker_url="tcp://${broker_host}:${broker_port}" + local gemini_host="{{ getv "/gemini/host" "gemini" }}" + local gemini_port="{{ getv "/gemini/port" "8000" }}" + local gemini_url="http://${gemini_host}:${gemini_port}" + local solr_host="{{ getv "/solr/host" "solr" }}" + local solr_port="{{ getv "/solr/port" "8983" }}" + local matamo_url="{{ getv "/matomo/url" "http://matomo.localhost/" }}" + local cantaloupe_url="{{ getv "/cantaloupe/url" "http://cantaloupe/cantaloupe/iiif/2" }}" + local triplestore_host="{{ getv "/triplestore/host" "blazegraph" }}" + local triplestore_port="{{ getv "/triplestore/port" "80" }}" + local triplestore_url="http://${triplestore_host}:${triplestore_port}/bigdata" + local fcrepo_host="{{ getv "/fcrepo/host" "fcrepo.localhost" }}" + local fcrepo_port="{{ getv "/fcrepo/host" "80" }}" + local fcrepo_url= + + # Indexing fails if port 80 is given explicitly. + if [[ "${fcrepo_port}" == "80" ]]; then + fcrepo_url="http://${fcrepo_host}/fcrepo/rest/" + else + fcrepo_url="http://${fcrepo_host}:${fcrepo_port}/fcrepo/rest/" + fi + + # Create keys prior to any installation as other services depend on them. + if [[ ! -f "/opt/keys/claw/private.key" ]]; then + openssl genrsa -out "/opt/keys/claw/private.key" 2048 + openssl rsa -pubout -in "/opt/keys/claw/private.key" -out "/opt/keys/claw/public.key" + chmod a=r /opt/keys/claw/* + fi + + # Hackity hack sack. + if ! grep flysystem /var/www/drupal/web/sites/default/settings.php &> /dev/null; then + cat <<-EOT >> /var/www/drupal/web/sites/default/settings.php + +\$settings['flysystem'] = [ + 'fedora' => [ + 'driver' => 'fedora', + 'config' => [ + 'root' => '${fcrepo_url}', + ], + ], +]; +EOT + fi + + # Ensure JWT is setup before any module installations run. + drush en --uri "http://drupal:80/" --no-interaction --yes jwt + drush config-import -y --partial --source=/opt/islandora/configs/jwt + + # Ensure Islandora settings are correct, before install hooks run. + drush en --uri "http://drupal:80/" --no-interaction --yes islandora + drush -y cset --input-format=yaml islandora.settings broker_url "${broker_url}" + drush -y cset --input-format=yaml islandora.settings gemini_url "${gemini_url}" + + # Need access to Solr before we can actually import the right config. + if timeout 300 wait-for-open-port.sh "${solr_host}" "${solr_port}" ; then + echo "Solr Found" + else + echo "Could not connect to Solr" + exit 1 + fi + + # Need access to Solr before we can actually import the right config. + if timeout 300 wait-for-open-port.sh "${fcrepo_host}" "${fcrepo_port}" ; then + echo "Fcrepo Found" + else + echo "Could not connect to Fcrepo" + exit 1 + fi + + # Need access to activemq so we can publish the creation of before we can actually import the right config. + if timeout 300 wait-for-open-port.sh ${broker_host} ${broker_port}; then + echo "Broker Found" + else + echo "Could not connect to Broker" + exit 1 + fi + + # Need access to gemini before importing features. + if timeout 300 wait-for-open-port.sh "${gemini_host}" "${gemini_port}"; then + echo "Gemini Found" + else + echo "Could not connect to Gemini" + exit 1 + fi + + if timeout 300 wait-for-open-port.sh "${triplestore_host}" "${triplestore_port}"; then + echo "Triplestore Found" + else + echo "Could not connect to Triplestore" + exit 1 + fi + + # Setup namespace / inference. + curl -X POST -H "Content-type: text/plain" --data-binary @/var/run/islandora/blazegraph.properties "${triplestore_url}/namespace" + curl -X POST -H "Content-type: text/plain" --data-binary @/var/run/islandora/inference.nt "${triplestore_url}/namespace/islandora/sparql" + + # From: islandora-playbook/inventory/vagrant/group_vars/webserver/drupal.yml + drush en --uri "http://drupal:80/" --no-interaction --yes \ + admin_toolbar \ + basic_auth \ + content_browser \ + controlled_access_terms_defaults \ + devel \ + facets \ + islandora_breadcrumbs \ + islandora_defaults \ + islandora_fits \ + islandora_iiif \ + islandora_oaipmh \ + islandora_search \ + matomo \ + pdf \ + rdf \ + responsive_image \ + rest \ + restui \ + search_api_solr \ + search_api_solr_defaults \ + serialization \ + simpletest \ + syslog \ + transliterate_filenames + + # search_api.index.default_solr_index? + drush -y cset search_api.server.default_solr_server backend_config.connector_config.host "${solr_host}" + drush -y cset search_api.server.default_solr_server backend_config.connector_config.port "${solr_port}" + + # From: islandora-playbook/roles/internal/webserver-app/tasks/drupal.yml + drush -y pm-uninstall search + drush -y "then" -y carapace + drush -y config-set system.theme default carapace + drush -y config-set matomo.settings site_id 1 + drush -y config-set matomo.settings url_http "${matamo_url}" + drush fim --uri "http://drupal:80/" --no-interaction --yes islandora_core_feature,controlled_access_terms_defaults,islandora_defaults,islandora_search + + # Fix what the features overides. + drush -y cset search_api.server.default_solr_server backend_config.connector_config.host "${solr_host}" + drush -y cset search_api.server.default_solr_server backend_config.connector_config.port "${solr_port}" + + # Export the configuration into shared volume. + drush -y solr-gsc default_solr_server /tmp/solr_config.zip 7.1 + mkdir -p /opt/solr/server/solr/ISLANDORA/conf || true + mkdir -p /opt/solr/server/solr/ISLANDORA/data || true + unzip -o /tmp/solr_config.zip -d /opt/solr/server/solr/ISLANDORA/conf + # The uid:gid "100:1000" is "solr:solr" inside of the solr container. + chown -R 100:1000 /opt/solr/server/solr/ISLANDORA + curl -s "http://${solr_host}:${solr_port}/solr/admin/cores?action=CREATE&name=ISLANDORA&instanceDir=ISLANDORA&config=solrconfig.xml&dataDir=data" &> /dev/null + + # From: islandora-playbook/post-install.yml + drush -y urol fedoraadmin admin + drush -y cset --input-format=yaml jsonld.settings remove_jsonld_format true + drush -y cset --input-format=yaml islandora.settings broker_url "${broker_url}" + drush -y cset --input-format=yaml islandora.settings gemini_url "${gemini_url}" + drush -y cset --input-format=yaml islandora.settings gemini_pseudo_bundles.0 "islandora_object:node" + drush -y cset --input-format=yaml islandora.settings gemini_pseudo_bundles.1 "image:media" + drush -y cset --input-format=yaml islandora.settings gemini_pseudo_bundles.2 "file:media" + drush -y cset --input-format=yaml islandora.settings gemini_pseudo_bundles.3 "audio:media" + drush -y cset --input-format=yaml islandora.settings gemini_pseudo_bundles.4 "video:media" + drush -y cset --input-format=yaml media.settings standalone_url true + drush -y cset --input-format=yaml islandora_iiif.settings iiif_server "${cantaloupe_url}" + drush -y cset --input-format=yaml openseadragon.settings manifest_view iiif_manifest + drush -y --uri "http://drupal:80/" --userid=1 mim --group=islandora + s6-setuidgid nginx mkdir -p /var/www/drupal/web/simpletest /var/www/drupal/web/sites/simpletest + + # Cache clear. + drush -y cr +} +main diff --git a/sandbox/rootfs/etc/cont-init.d/04-sandbox-setup.sh b/sandbox/rootfs/etc/cont-init.d/04-sandbox-setup.sh new file mode 100644 index 00000000..fda8eefa --- /dev/null +++ b/sandbox/rootfs/etc/cont-init.d/04-sandbox-setup.sh @@ -0,0 +1,3 @@ +#!/usr/bin/with-contenv bash +set -e +/var/run/islandora/sandbox-setup.sh \ No newline at end of file diff --git a/sandbox/rootfs/opt/islandora/configs/jwt/jwt.config.yml b/sandbox/rootfs/opt/islandora/configs/jwt/jwt.config.yml new file mode 100644 index 00000000..49199f09 --- /dev/null +++ b/sandbox/rootfs/opt/islandora/configs/jwt/jwt.config.yml @@ -0,0 +1,2 @@ +algorithm: RS256 +key_id: islandora_rsa_key diff --git a/sandbox/rootfs/opt/islandora/configs/jwt/key.key.islandora_rsa_key.yml b/sandbox/rootfs/opt/islandora/configs/jwt/key.key.islandora_rsa_key.yml new file mode 100644 index 00000000..9140f3fb --- /dev/null +++ b/sandbox/rootfs/opt/islandora/configs/jwt/key.key.islandora_rsa_key.yml @@ -0,0 +1,17 @@ +uuid: 7f805322-14df-4eac-bfa1-d2f800fccbe3 +langcode: en +status: true +dependencies: + module: + - jwt +id: islandora_rsa_key +label: 'Islandora RSA Key' +description: '' +key_type: jwt_rs +key_type_settings: + algorithm: RS256 +key_provider: file +key_provider_settings: + file_location: /opt/keys/claw/private.key +key_input: none +key_input_settings: { } diff --git a/settings.gradle.kts b/settings.gradle.kts new file mode 100644 index 00000000..1fe4034e --- /dev/null +++ b/settings.gradle.kts @@ -0,0 +1,11 @@ +rootProject.name = "docker" + +// Include any folder that has a Dockerfile as a sub-project. +rootProject.projectDir + .walk() + .maxDepth(1) // Only immediate directories. + .filter { it.isDirectory && it.resolve("Dockerfile").exists() } // Must have a Dockerfile. + .forEach { + // Include as a sub-project. + include(it.relativeTo(rootProject.projectDir).path) + } \ No newline at end of file diff --git a/solr/.dockerignore b/solr/.dockerignore new file mode 100644 index 00000000..b43bf86b --- /dev/null +++ b/solr/.dockerignore @@ -0,0 +1 @@ +README.md diff --git a/solr/Dockerfile b/solr/Dockerfile new file mode 100644 index 00000000..59e4456b --- /dev/null +++ b/solr/Dockerfile @@ -0,0 +1,20 @@ +# syntax=docker/dockerfile:experimental +FROM local/java:latest + +RUN --mount=id=downloads,type=cache,target=/opt/downloads \ + SOLR_VERSION="7.1.0" && \ + install-apache-service.sh \ + --name solr \ + --version "${SOLR_VERSION}" \ + --key "38D2EA16DDF5FC722EBC433FDC92616F177050F6" \ + --mirror "https://archive.apache.org/dist/lucene/solr/${SOLR_VERSION}" \ + --file "solr-${SOLR_VERSION}.tgz" \ + docs example licenses server/solr/configsets + +WORKDIR /opt/solr + +EXPOSE 8983 + +VOLUME [ "/opt/solr/server/solr" ] + +COPY rootfs / diff --git a/solr/README.md b/solr/README.md new file mode 100644 index 00000000..e64cb57a --- /dev/null +++ b/solr/README.md @@ -0,0 +1,40 @@ +# Solr + +Docker image for [Solr] version 7.1.0. + +Please refer to the [Solr Documentation] for more in-depth information. + +As a quick example this will bring up an instance of [Solr], and allow you +to view on . + +```bash +docker run --rm -ti -p 8983:8983 islandora/solr +``` + +## Dependencies + +Requires `islandora/java` docker image to build. Please refer to the +[Java Image README](../java/README.md) for additional information including +additional settings, volumes, ports, etc. + +## Ports + +| Port | Description | +| :--- | :---------- | +| 8983 | HTTP | + +## Volumes + +| Path | Description | +| :-------------------- | :----------------------------------------------- | +| /opt/solr/server/solr | Location of configuration and data for all cores | + +## Logs + +| Path | Description | +| :----------------------------- | :------------- | +| /opt/solr/server/logs/solr.log | [Solr Logging] | + +[Solr Documentation]: https://lucene.apache.org/solr/guide/7_1/ +[Solr Logging]: https://lucene.apache.org/solr/guide/7_1/configuring-logging.html +[Solr]: https://lucene.apache.org/solr/ diff --git a/solr/rootfs/etc/services.d/solr/finish b/solr/rootfs/etc/services.d/solr/finish new file mode 100644 index 00000000..f8984dd3 --- /dev/null +++ b/solr/rootfs/etc/services.d/solr/finish @@ -0,0 +1,4 @@ +#!/usr/bin/execlineb -S1 +# -*- mode: sh -*- +# vi: set ft=sh : +s6-svscanctl -t /var/run/s6/services diff --git a/solr/rootfs/etc/services.d/solr/run b/solr/rootfs/etc/services.d/solr/run new file mode 100644 index 00000000..dc64b621 --- /dev/null +++ b/solr/rootfs/etc/services.d/solr/run @@ -0,0 +1,5 @@ +#!/usr/bin/execlineb -P +# -*- mode: sh -*- +# vi: set ft=sh : +with-contenv +s6-setuidgid solr /opt/solr/bin/solr start -f diff --git a/tomcat/.dockerignore b/tomcat/.dockerignore new file mode 100644 index 00000000..b43bf86b --- /dev/null +++ b/tomcat/.dockerignore @@ -0,0 +1 @@ +README.md diff --git a/tomcat/Dockerfile b/tomcat/Dockerfile new file mode 100644 index 00000000..df9aad3a --- /dev/null +++ b/tomcat/Dockerfile @@ -0,0 +1,24 @@ +# syntax=docker/dockerfile:experimental +FROM local/java:latest + +RUN --mount=id=downloads,type=cache,target=/opt/downloads \ + TOMCAT_VERSION="9.0.34" && \ + install-apache-service.sh \ + --name tomcat \ + --version "${TOMCAT_VERSION}" \ + --key "A9C5DF4D22E99998D9875A5110C01C5A2F6059E7" \ + --mirror "https://archive.apache.org/dist/tomcat/tomcat-9/v${TOMCAT_VERSION}/bin" \ + --file "apache-tomcat-${TOMCAT_VERSION}.tar.gz" \ + webapps/docs webapps/examples + +# Install reverse proxy to redirect from 80 to 8080. +RUN --mount=type=cache,target=/var/cache/apk \ + --mount=type=cache,target=/etc/cache/apk \ + apk-install.sh nginx && \ + cleanup.sh + +WORKDIR /opt/tomcat + +EXPOSE 8080 + +COPY rootfs / diff --git a/tomcat/README.md b/tomcat/README.md new file mode 100644 index 00000000..af0059f1 --- /dev/null +++ b/tomcat/README.md @@ -0,0 +1,75 @@ +# Tomcat + +Docker image for [Tomcat] version 9.0.34. + +Please refer to the [Tomcat Documentation] for more in-depth information. + +As a quick example this will bring up an instance of [Tomcat], and allow you +to view the manager webapp on . + +```bash +docker run --rm -ti \ + -p 80:80 \ + islandora/tomcat +``` + +## Dependencies + +Requires `islandora/java` docker image to build. Please refer to the +[Java Image README](../java/README.md) for additional information including +additional settings, volumes, ports, etc. + +## Ports + +| Port | Description | +| :--- | :---------- | +| 8005 | Shut-down | +| 8009 | [AJP] | +| 8080 | HTTP | +| 8443 | HTTPS | + +## Settings + +> N.B. For all of the settings below images that descend from +> ``islandora/tomcat`` will apply prefix to every setting. So for example +> `CATALINA_OPTS` would become `FCREPO_CATALINA_OPTS` this is to allow for +> different settings on a per-service basis. + +| Environment Variable | Etcd Key | Default | Description | +| :---------------------------------- | :----------------------------------- | :---------- | :------------------------------------------------------------------------ | +| CATALINA_OPTS | /catalina/opts | | | +| JAVA_OPTS | /java/opts | | | +| TOMCAT_ADMIN_NAME | /tomcat/admin/name | admin | The user name of the manager webapp admin user | +| TOMCAT_ADMIN_PASSWORD | /tomcat/admin/password | password | The password for the manager webapp admin user | +| TOMCAT_ADMIN_ROLES | /tomcat/admin/roles | manager-gui | Comma separated list of roles the user has | +| TOMCAT_MANAGER_REMOTE_ADDRESS_VALVE | /tomcat/manager/remote/address/valve | ^.*$ | Allows / blocks access to manager app to addresses which match this regex | + +Additional users/groups/etc can be defined by adding more environment variables, +following the above conventions: + +| Environment Variable | Etcd Key | Description | +| :-------------------------- | :--------------------------- | :----------------------------------------- | +| TOMCAT_USER_{USER}_NAME | /tomcat/user/{USER}/name | The user name | +| TOMCAT_USER_{USER}_PASSWORD | /tomcat/user/{USER}/password | The password for the user | +| TOMCAT_USER_{USER}_ROLES | /tomcat/user/{USER}/roles | Comma separated list of roles the user has | + +> N.B. These do not have defaults. + +For example to add a new user `someone` you would need to define the following: + +| Environment Variable | Etcd Key | Value | +| :--------------------------- | :---------------------------- | :------- | +| TOMCAT_USER_SOMEONE_NAME | /tomcat/user/someone/name | someone | +| TOMCAT_USER_SOMEONE_PASSWORD | /tomcat/user/someone/password | password | +| TOMCAT_USER_SOMEONE_ROLES | /tomcat/user/someone/roles | admin | + +## Logs + +| Path | Description | +| :---------------- | :--------------- | +| /opt/tomcat/logs/ | [Tomcat Logging] | + +[AJP]: https://tomcat.apache.org/tomcat-9.0-doc/config/ajp.html +[Tomcat Documentation]: https://tomcat.apache.org/tomcat-9.0-doc/ +[Tomcat Logging]: https://tomcat.apache.org/tomcat-9.0-doc/logging.html +[Tomcat]: https://tomcat.apache.org/ diff --git a/tomcat/rootfs/etc/confd/conf.d/manager.context.toml b/tomcat/rootfs/etc/confd/conf.d/manager.context.toml new file mode 100644 index 00000000..0480ca66 --- /dev/null +++ b/tomcat/rootfs/etc/confd/conf.d/manager.context.toml @@ -0,0 +1,6 @@ +[template] +src = "manager.context.xml.tmpl" +dest = "/opt/tomcat/webapps/manager/META-INF/context.xml" +uid = 100 +gid = 1000 +keys = ["/tomcat/manager/remote/address/valve"] diff --git a/tomcat/rootfs/etc/confd/conf.d/setenv.sh.toml b/tomcat/rootfs/etc/confd/conf.d/setenv.sh.toml new file mode 100644 index 00000000..7f0fbd2f --- /dev/null +++ b/tomcat/rootfs/etc/confd/conf.d/setenv.sh.toml @@ -0,0 +1,6 @@ +[template] +src = "setenv.sh.tmpl" +dest = "/opt/tomcat/bin/setenv.sh" +uid = 100 +gid = 1000 +keys = ["/java/opts", "/catalina/opts"] diff --git a/tomcat/rootfs/etc/confd/conf.d/tomcat-users.toml b/tomcat/rootfs/etc/confd/conf.d/tomcat-users.toml new file mode 100644 index 00000000..196ecdde --- /dev/null +++ b/tomcat/rootfs/etc/confd/conf.d/tomcat-users.toml @@ -0,0 +1,6 @@ +[template] +src = "tomcat-users.xml.tmpl" +dest = "/opt/tomcat/conf/tomcat-users.xml" +uid = 100 +gid = 1000 +keys = ["/tomcat/admin/user", "/tomcat/admin/password"] diff --git a/tomcat/rootfs/etc/confd/templates/manager.context.xml.tmpl b/tomcat/rootfs/etc/confd/templates/manager.context.xml.tmpl new file mode 100644 index 00000000..ab46261c --- /dev/null +++ b/tomcat/rootfs/etc/confd/templates/manager.context.xml.tmpl @@ -0,0 +1,23 @@ + + + + + + + diff --git a/tomcat/rootfs/etc/confd/templates/setenv.sh.tmpl b/tomcat/rootfs/etc/confd/templates/setenv.sh.tmpl new file mode 100755 index 00000000..789681e5 --- /dev/null +++ b/tomcat/rootfs/etc/confd/templates/setenv.sh.tmpl @@ -0,0 +1,3 @@ +#!/bin/sh +export JAVA_OPTS="{{ getv "/java/opts" "" }}" +export CATALINA_OPTS="{{ getv "/catalina/opts" "" }}" diff --git a/tomcat/rootfs/etc/confd/templates/tomcat-users.xml.tmpl b/tomcat/rootfs/etc/confd/templates/tomcat-users.xml.tmpl new file mode 100644 index 00000000..7e1c42cc --- /dev/null +++ b/tomcat/rootfs/etc/confd/templates/tomcat-users.xml.tmpl @@ -0,0 +1,9 @@ + + + + {{ range $dir := lsdir "/user" }} + {{ end }} + diff --git a/tomcat/rootfs/etc/cont-init.d/02-ngnix-install.sh b/tomcat/rootfs/etc/cont-init.d/02-ngnix-install.sh new file mode 100755 index 00000000..c7d12cc6 --- /dev/null +++ b/tomcat/rootfs/etc/cont-init.d/02-ngnix-install.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +mkdir /run/nginx &> /dev/null || true diff --git a/tomcat/rootfs/etc/nginx/conf.d/default.conf b/tomcat/rootfs/etc/nginx/conf.d/default.conf new file mode 100644 index 00000000..965977b2 --- /dev/null +++ b/tomcat/rootfs/etc/nginx/conf.d/default.conf @@ -0,0 +1,8 @@ +server { + listen 80; + location / { + proxy_set_header X-Forwarded-For $remote_addr; + proxy_set_header Host $http_host; + proxy_pass "http://127.0.0.1:8080"; + } +} diff --git a/tomcat/rootfs/etc/nginx/modules/daemon.conf b/tomcat/rootfs/etc/nginx/modules/daemon.conf new file mode 100644 index 00000000..ef1f9c1c --- /dev/null +++ b/tomcat/rootfs/etc/nginx/modules/daemon.conf @@ -0,0 +1 @@ +daemon off; diff --git a/tomcat/rootfs/etc/services.d/nginx/finish b/tomcat/rootfs/etc/services.d/nginx/finish new file mode 100644 index 00000000..9030da41 --- /dev/null +++ b/tomcat/rootfs/etc/services.d/nginx/finish @@ -0,0 +1,4 @@ +#!/usr/bin/execlineb -S1 +# -*- mode: sh -*- +# vi: set ft=sh: +s6-svscanctl -t /var/run/s6/services diff --git a/tomcat/rootfs/etc/services.d/nginx/run b/tomcat/rootfs/etc/services.d/nginx/run new file mode 100644 index 00000000..7503678e --- /dev/null +++ b/tomcat/rootfs/etc/services.d/nginx/run @@ -0,0 +1,4 @@ +#!/usr/bin/execlineb -P +# -*- mode: sh -*- +# vi: set ft=sh: +/usr/sbin/nginx diff --git a/tomcat/rootfs/etc/services.d/tomcat/finish b/tomcat/rootfs/etc/services.d/tomcat/finish new file mode 100644 index 00000000..f8984dd3 --- /dev/null +++ b/tomcat/rootfs/etc/services.d/tomcat/finish @@ -0,0 +1,4 @@ +#!/usr/bin/execlineb -S1 +# -*- mode: sh -*- +# vi: set ft=sh : +s6-svscanctl -t /var/run/s6/services diff --git a/tomcat/rootfs/etc/services.d/tomcat/run b/tomcat/rootfs/etc/services.d/tomcat/run new file mode 100644 index 00000000..b66a361b --- /dev/null +++ b/tomcat/rootfs/etc/services.d/tomcat/run @@ -0,0 +1,6 @@ +#!/usr/bin/execlineb -P +# -*- mode: sh -*- +# vi: set ft=sh : +with-contenv +s6-setuidgid tomcat +/opt/tomcat/bin/catalina.sh run diff --git a/tomcat/rootfs/usr/local/bin/install-war-into-tomcat.sh b/tomcat/rootfs/usr/local/bin/install-war-into-tomcat.sh new file mode 100755 index 00000000..616c7e16 --- /dev/null +++ b/tomcat/rootfs/usr/local/bin/install-war-into-tomcat.sh @@ -0,0 +1,122 @@ +#!/usr/bin/env bash + +# Exit non-zero if any command fails. +set -e + +readonly PROGNAME=$(basename $0) +readonly ARGS="$@" + +readonly DOWNLOAD_CACHE_DIRECTORY=/opt/downloads + +function usage { + cat <<- EOF + usage: $PROGNAME options [FILE]... + + Installs the given war into tomcat. Makes use of the Buildkit cache, + by first downlading to ${DOWNLOAD_CACHE_DIRECTORY}. + + OPTIONS: + -n --name The name to use for the unpacked war. + -u --url The location to download the war from. + -u --file The location to copy the war from. + -k --key A sha256 key used to verify the intended war was downloaded successfully. + -h --help Show this help. + -x --debug Debug this script. + + The options --file and --url are mutually exclusive. + + Examples: + Install Blazegraph as bigdata: + $PROGNAME \\ + --name "bigdata" \\ + --url "https://github.com/blazegraph/database/releases/download/BLAZEGRAPH_RELEASE_CANDIDATE_2_1_5/blazegraph.war" \\ + --key "b22f1a1aa8e536443db9a57da63720813374ef59e4021cfa9ad0e98f9a420e85" +EOF +} + +function cmdline { + local arg= + for arg + do + local delim="" + case "$arg" in + # Translate --gnu-long-options to -g (short options) + --name) args="${args}-n ";; + --url) args="${args}-u ";; + --file) args="${args}-f ";; + --key) args="${args}-k ";; + --help) args="${args}-h ";; + --debug) args="${args}-x ";; + # Pass through anything else + *) [[ "${arg:0:1}" == "-" ]] || delim="\"" + args="${args}${delim}${arg}${delim} ";; + esac + done + + # Reset the positional parameters to the short options + eval set -- $args + + while getopts "n:u:f:k:hx" OPTION + do + case $OPTION in + n) + readonly NAME=${OPTARG} + readonly DEPLOY_DIRECTORY="/opt/tomcat/webapps/${NAME}" + ;; + u) + readonly URL=${OPTARG} + ;; + f) + readonly FILE=${OPTARG} + ;; + k) + readonly KEY=${OPTARG} + ;; + h) + usage + exit 0 + ;; + x) + readonly DEBUG='-x' + set -x + ;; + esac + done + + if [[ -z $NAME || -z $KEY ]]; then + echo "Missing one or more required options: --name --key" + exit 1 + fi + + if [[ -z $URL && -z $FILE ]]; then + echo "Missing required options you must specify either: --url OR --file" + exit 1 + fi + + return 0 +} + +function validate { + local war="${1}" + sha256sum "${war}" | cut -f1 -d' ' | xargs test "${KEY}" == +} + +function unpack { + local war="${1}" + s6-setuidgid tomcat mkdir "${DEPLOY_DIRECTORY}" + s6-setuidgid tomcat unzip "${war}" -d "${DEPLOY_DIRECTORY}" +} + +function main { + cmdline ${ARGS} + local war=${FILE} + if [[ $URL ]]; then + war="/opt/downloads/$(basename ${URL})" + # Expects that the RUN uses ${DOWNLOAD_CACHE_DIRECTORY} as a cache + # https://github.com/moby/buildkit/blob/master/frontend/dockerfile/docs/experimental.md#run---mounttypecache + wget -N -P ${DOWNLOAD_CACHE_DIRECTORY} ${URL} + fi + validate "${war}" + unpack "${war}" +} +main